Screenshot tests (#130)

* #9 Add snapshot testing library

* #9 Create script to boot test simulators

* #9 Create the UI test plan

* #9 Create shared schemes for test targets

* #9 Disable split view for UI tests

* #9 Fix fastlane dependencies

* #9 Add snapshot testing to the application

* #9 assert screenshots

* #9 fix swipe gestures on iPad

* #9 Fix accessing items in session verification screen

* #9 Workaround for flaky unit test

* #9 Specify scheme for alpha build

* #9 Add reference screenshots

* Update python script path and check assets for png check

* Update script path

* Use static timezone for simulator time

* Fix build after SwiftFormat

* Add changelog

* Upload failed screenshots artifact

* Always upload artifacts

* Update boot simulator script

* Update simulator overridden time

* Install pytz before tests

* Get time from Ruby script

* Disable SwiftUI animation when running UI tests

* Update screenshots after animation setting

* Include reference images in the artifact

* Update matching precision

* Update image matching precision & revert artifact content

* Include Xcode result in the artifact

* Update test output directory

* Disable gradient on splash screen for tests

* Tap next button explicitly

* Wait a bit before checking alert

* Wait 1 second

* Run SwiftFormat on project

* Ignore temporary screenshots

* Fix most of the PR remarks

* Fix conflicts

* Bump Python version to 3

* Update reference screenshots for authentication screens

* Update SwiftFormat

* Fix flakey session verification test.

* Update scheme.

Co-authored-by: Doug <douglase@element.io>
This commit is contained in:
ismailgulek
2022-08-11 15:02:47 +03:00
committed by GitHub
parent cecb132e7b
commit fdbaa16c38
127 changed files with 944 additions and 83 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
UITests/Sources/__Snapshots__/** filter=lfs diff=lfs merge=lfs -text

View File

@@ -17,7 +17,14 @@ jobs:
cancel-in-progress: true
steps:
- name: Setup Xcode version
uses: maxim-lobanov/setup-xcode@v1.4.1
with:
xcode-version: '13.4'
- uses: actions/checkout@v3
with:
lfs: true
- uses: actions/cache@v3
with:
@@ -33,6 +40,15 @@ jobs:
- name: Run tests
run: bundle exec fastlane tests
- name: Archive artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: test-output
path: fastlane/test_output
retention-days: 7
if-no-files-found: ignore
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3

11
.gitignore vendored
View File

@@ -38,3 +38,14 @@ Tools/Scripts/element-android
## macOS Files
.DS_Store
._*
## Temporary Screenshots
# ignore all
/UITests/Sources/__Snapshots__/Application/*
# but keep the references
!/UITests/Sources/__Snapshots__/Application/15-5-de-DE-iPad-9th-generation.*.png
!/UITests/Sources/__Snapshots__/Application/15-5-fr-FR-iPad-9th-generation.*.png
!/UITests/Sources/__Snapshots__/Application/15-5-en-GB-iPad-9th-generation.*.png
!/UITests/Sources/__Snapshots__/Application/15-5-de-DE-iPhone-13-Pro-Max.*.png
!/UITests/Sources/__Snapshots__/Application/15-5-fr-FR-iPhone-13-Pro-Max.*.png
!/UITests/Sources/__Snapshots__/Application/15-5-en-GB-iPhone-13-Pro-Max.*.png

View File

@@ -77,7 +77,7 @@ if hasChangedViews {
}
// Check for pngs on resources
let hasPngs = !editedFiles.filter { $0.lowercased().hasSuffix(".png") }.isEmpty
let hasPngs = !editedFiles.filter { $0.lowercased().contains(".xcassets") && $0.lowercased().hasSuffix(".png") }.isEmpty
if hasPngs {
warn("You seem to have made changes to some images. Please consider using an SVG or PDF.")
warn("You seem to have made changes to some resource images. Please consider using an SVG or PDF.")
}

View File

@@ -100,6 +100,7 @@
46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */; };
4669804D0369FBED4E8625D1 /* ToastViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4470B8CB654B097D807AA713 /* ToastViewPresenter.swift */; };
490E606044B18985055FF690 /* SettingsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E29F98CF0E960689A410E3 /* SettingsUITests.swift */; };
492274DA6691EE985C2FCCAA /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 21C83087604B154AA30E9A8F /* SnapshotTesting */; };
499A26EB06C97E48C27A2DB9 /* BuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F87116470221880017CF522 /* BuildSettings.swift */; };
49E9B99CB6A275C7744351F0 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2D58333B377888012740101 /* LoginViewModel.swift */; };
49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */; };
@@ -265,6 +266,7 @@
D6417E5A799C3C7F14F9EC0A /* SessionVerificationViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3069ADED46D063202FE7698 /* SessionVerificationViewModelProtocol.swift */; };
D826154612415D2A3BB6EBF3 /* ListTableViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E854E7CF531DAC5CBEBDC75 /* ListTableViewAdapter.swift */; };
D8359F67AF3A83516E9083C1 /* MockUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */; };
D85D4FA590305180B4A41795 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB3073CCD77D906B330BC1D6 /* Tests.swift */; };
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */; };
D94F664677C380A3CAB8D7F6 /* ActivityIndicatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */; };
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CC95CD75B688E946438165 /* Coordinator.swift */; };
@@ -295,6 +297,7 @@
FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; };
FC6B7436C3A5B3D0565227D5 /* ActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF05352F28D4E7336228E9F4 /* ActivityIndicatorView.swift */; };
FCB640C576292BEAF7FA3B2E /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F395A2E917115C7AAF7F34 /* SplashViewController.swift */; };
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; };
FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA154570F693D93513E584C1 /* RoomMessageFactory.swift */; };
FFD3E4FF948E06C7585317FC /* TimelineStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892E29C98C4E8182C9037F84 /* TimelineStyler.swift */; };
/* End PBXBuildFile section */
@@ -536,6 +539,7 @@
8C37FB986891D90BEAA93EAE /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = "<group>"; };
8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = "<group>"; };
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = "<group>"; };
9010EE0CC913D095887EF36E /* OIDCService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCService.swift; sourceTree = "<group>"; };
90733775209F4D4D366A268F /* RootRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = "<group>"; };
92B61C243325DC76D3086494 /* EventBriefFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBriefFactoryProtocol.swift; sourceTree = "<group>"; };
@@ -613,6 +617,7 @@
B83CB897B183BF3C33715F55 /* bn-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "bn-IN"; path = "bn-IN.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
B8A56EA2A5AE726F445CB2E3 /* eo */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = eo; path = eo.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
B902EA6CD3296B0E10EE432B /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
BB3073CCD77D906B330BC1D6 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
BC9B05D6B293A039EB963CA7 /* az */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = az; path = az.lproj/Localizable.strings; sourceTree = "<group>"; };
BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageComposerTextField.swift; sourceTree = "<group>"; };
BEE6BF9BA63FF42F8AF6EEEA /* sr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sr; path = sr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -684,6 +689,7 @@
EDB6E40BAD4504D899FAAC9A /* TemplateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateViewModel.swift; sourceTree = "<group>"; };
EE8BCD14EFED23459A43FDFF /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewFactoryProtocol.swift; sourceTree = "<group>"; };
EF1593DD87F974F8509BB619 /* ElementAnimations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementAnimations.swift; sourceTree = "<group>"; };
EF188681D6B6068CFAEAFC3F /* MXLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXLogger.m; sourceTree = "<group>"; };
EFF7BF82A950B91BC5469E91 /* ViewFrameReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewFrameReader.swift; sourceTree = "<group>"; };
EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -720,6 +726,7 @@
A4E885358D7DD5A072A06824 /* SwiftState in Frameworks */,
29EE1791E0AFA1ABB7F23D2F /* GZIP in Frameworks */,
33CAC1226DFB8B5D8447D286 /* Sentry in Frameworks */,
492274DA6691EE985C2FCCAA /* SnapshotTesting in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -756,6 +763,7 @@
052CC920F473C10B509F9FC1 /* SwiftUI */ = {
isa = PBXGroup;
children = (
E2DA161C142B7AB8CC40F752 /* Animation */,
595B8797ED6A7489ABDCE384 /* ErrorHandling */,
CE2FBFD64A89F5DBE4EB30DB /* Layout */,
10578D9852BA78D309A1CBDF /* ViewModel */,
@@ -850,13 +858,6 @@
path = Resources;
sourceTree = "<group>";
};
3180C73BA7B8F5F7447C99B0 /* React */ = {
isa = PBXGroup;
children = (
);
path = React;
sourceTree = "<group>";
};
328DD5DA1281F758B72006C7 /* Views */ = {
isa = PBXGroup;
children = (
@@ -1143,6 +1144,7 @@
children = (
49D2C8E66E83EA578A7F318A /* Info.plist */,
D4DA544B2520BFA65D6DB4BB /* target.yml */,
8E088F2A1B9EC529D3221931 /* UITests.xctestplan */,
);
path = SupportingFiles;
sourceTree = "<group>";
@@ -1454,6 +1456,7 @@
1027BB9A852F445B7623897F /* ElementSettings.swift */,
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */,
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
BB3073CCD77D906B330BC1D6 /* Tests.swift */,
44BBB96FAA2F0D53C507396B /* Extensions */,
8F9A844EB44B6AD7CA18FD96 /* HTMLParsing */,
06501F0E978B2D5C92771DC7 /* Logging */,
@@ -1497,13 +1500,20 @@
path = SessionVerification;
sourceTree = "<group>";
};
E2DA161C142B7AB8CC40F752 /* Animation */ = {
isa = PBXGroup;
children = (
EF1593DD87F974F8509BB619 /* ElementAnimations.swift */,
);
path = Animation;
sourceTree = "<group>";
};
E59565F441830B19DBAE567C /* Screens */ = {
isa = PBXGroup;
children = (
E74CD7681375AD2EAA34D66B /* Authentication */,
4009BE2E791C16AC6EE39A7E /* BugReport */,
B53CA9BECD3F97805E1432D0 /* HomeScreen */,
3180C73BA7B8F5F7447C99B0 /* React */,
679E9837ECA8D6776079D16E /* RoomScreen */,
D958761758AA1110476DE6A3 /* SessionVerification */,
70B74A432C241E56A7ACE610 /* Settings */,
@@ -1623,6 +1633,7 @@
isa = PBXNativeTarget;
buildConfigurationList = F1B67CF63C1231AEB14D70E6 /* Build configuration list for PBXNativeTarget "UITests" */;
buildPhases = (
17364E8B37FC780E07DDEAF7 /* Override Simulator Status Bars */,
BAD5CD7BE53A7C832569B67A /* Sources */,
86982BD498105258F3778110 /* Resources */,
CD30252A70288BD4BF476ED7 /* Frameworks */,
@@ -1644,6 +1655,7 @@
3853B78FB8531B83936C5DA6 /* SwiftState */,
1BCD21310B997A6837B854D6 /* GZIP */,
67E7A6F388D3BF85767609D9 /* Sentry */,
21C83087604B154AA30E9A8F /* SnapshotTesting */,
);
productName = UITests;
productReference = F506C6ADB1E1DA6638078E11 /* UITests.xctest */;
@@ -1805,6 +1817,7 @@
D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */,
80B898A3AD2AC63F3ABFC218 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */,
A08925A9D5E3770DEB9D8509 /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */,
6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */,
25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */,
);
@@ -1864,6 +1877,24 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
17364E8B37FC780E07DDEAF7 /* Override Simulator Status Bars */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Override Simulator Status Bars";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "python3 $PROJECT_DIR/Tools/Scripts/bootTestSimulator.py --name 'iPhone 13 Pro Max' --version 'iOS.15.5'\npython3 $PROJECT_DIR/Tools/Scripts/bootTestSimulator.py --name 'iPad (9th generation)' --version 'iOS.15.5'\n";
};
98CA896D84BFD53B2554E891 /* ⚠️ SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1991,6 +2022,7 @@
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */,
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */,
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
06E93B2E3B32740B40F47CC5 /* ElementNavigationController.swift in Sources */,
9738F894DB1BD383BE05767A /* ElementSettings.swift in Sources */,
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
@@ -2126,6 +2158,7 @@
1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */,
75EA4ABBFAA810AFF289D6F4 /* TemplateViewModel.swift in Sources */,
5F1FDE49DFD0C680386E48F9 /* TemplateViewModelProtocol.swift in Sources */,
D85D4FA590305180B4A41795 /* Tests.swift in Sources */,
D013E70C8E28E43497820444 /* TextRoomMessage.swift in Sources */,
7963F98CDFDEAC75E072BD81 /* TextRoomTimelineItem.swift in Sources */,
5E0F2E612718BB4397A6D40A /* TextRoomTimelineView.swift in Sources */,
@@ -2742,6 +2775,14 @@
minimumVersion = 7.2.0;
};
};
F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.9.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -2765,6 +2806,11 @@
package = 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */;
productName = GZIP;
};
21C83087604B154AA30E9A8F /* SnapshotTesting */ = {
isa = XCSwiftPackageProductDependency;
package = F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */;
productName = SnapshotTesting;
};
36B7FC232711031AA2B0D188 /* DTCoreText */ = {
isa = XCSwiftPackageProductDependency;
package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */;

View File

@@ -66,7 +66,7 @@
{
"identity" : "matrix-rust-components-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
"location" : "https://github.com/matrix-org/matrix-rust-components-swift.git",
"state" : {
"revision" : "1358c9c2a85cfb5fc1bfadce13565e02618725d4",
"version" : "1.0.13-alpha"
@@ -81,6 +81,15 @@
"version" : "7.18.1"
}
},
{
"identity" : "swift-snapshot-testing",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing.git",
"state" : {
"revision" : "f8a9c997c3c1dab4e216a8ec9014e23144cbab37",
"version" : "1.9.0"
}
},
{
"identity" : "swiftstate",
"kind" : "remoteSourceControl",

View File

@@ -63,13 +63,6 @@
</Testables>
<CommandLineArguments>
</CommandLineArguments>
<EnvironmentVariables>
<EnvironmentVariable
key = "IS_RUNNING_UNIT_TESTS"
value = "1"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E28CD62691FDBC63147D5E3"
BuildableName = "UITests.xctest"
BlueprintName = "UITests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
onlyGenerateCoverageForSpecifiedTargets = "NO"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
default = "YES"
reference = "container:UITests/SupportingFiles/UITests.xctestplan">
</TestPlanReference>
</TestPlans>
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E28CD62691FDBC63147D5E3"
BuildableName = "UITests.xctest"
BlueprintName = "UITests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E28CD62691FDBC63147D5E3"
BuildableName = "UITests.xctest"
BlueprintName = "UITests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E28CD62691FDBC63147D5E3"
BuildableName = "UITests.xctest"
BlueprintName = "UITests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
</CommandLineArguments>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
runPostActionsOnFailure = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "32C23C8D224D46EFE62AFAD0"
BuildableName = "UnitTests.xctest"
BlueprintName = "UnitTests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "NO"
shouldUseLaunchSchemeArgsEnv = "YES"
systemAttachmentLifetime = "keepNever">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "32C23C8D224D46EFE62AFAD0"
BuildableName = "UnitTests.xctest"
BlueprintName = "UnitTests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "32C23C8D224D46EFE62AFAD0"
BuildableName = "UnitTests.xctest"
BlueprintName = "UnitTests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "32C23C8D224D46EFE62AFAD0"
BuildableName = "UnitTests.xctest"
BlueprintName = "UnitTests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CommandLineArguments>
</CommandLineArguments>
<EnvironmentVariables>
<EnvironmentVariable
key = "IS_RUNNING_UNIT_TESTS"
value = "1"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "32C23C8D224D46EFE62AFAD0"
BuildableName = "UnitTests.xctest"
BlueprintName = "UnitTests"
ReferencedContainer = "container:ElementX.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
</CommandLineArguments>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -18,7 +18,7 @@ import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
private lazy var appCoordinator: Coordinator = isRunningUITests ? UITestsAppCoordinator() : AppCoordinator()
private lazy var appCoordinator: Coordinator = Tests.isRunningUITests ? UITestsAppCoordinator() : AppCoordinator()
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
// use `en` as fallback language
@@ -28,7 +28,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
if isRunningUnitTests {
if Tests.isRunningUnitTests {
return true
}
@@ -36,20 +36,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}
private var isRunningUnitTests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
#else
false
#endif
}
private var isRunningUITests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UI_TESTS"] == "1"
#else
false
#endif
}
}

View File

@@ -0,0 +1,34 @@
//
// ElementAnimations.swift
// ElementX
//
// Created by Ismail on 8.07.2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
import SwiftUI
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public extension Animation {
/// Animation to be used to disable animations.
static let noAnimation: Animation = .linear(duration: 0)
/// `noAnimation` if running UI tests, otherwise `default` animation.
static var elementDefault: Animation {
Tests.isRunningUITests ? .noAnimation : .default
}
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
/// Returns the result of recomputing the view's body with the provided
/// animation.
/// - Parameters:
/// - animation: Animation
/// - body: operations to be animated
public func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
if Tests.isRunningUITests {
return try withAnimation(.noAnimation, body)
}
return try withAnimation(animation, body)
}

View File

@@ -0,0 +1,29 @@
//
// Tests.swift
// ElementX
//
// Created by Ismail on 29.07.2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
public enum Tests {
/// Flag indicating whether the app is running the unit tests.
static var isRunningUnitTests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
#else
false
#endif
}
/// Flag indicating whether the app is running the UI tests.
static var isRunningUITests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UI_TESTS"] == "1"
#else
false
#endif
}
}

View File

@@ -51,7 +51,7 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
func displayError(_ type: ServerSelectionErrorType) {
switch type {
case .footerMessage(let message):
withAnimation {
withElementAnimation {
state.footerErrorMessage = message
}
}
@@ -62,6 +62,6 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
/// Clear any errors shown in the text field footer.
private func clearFooterError() {
guard state.footerErrorMessage != nil else { return }
withAnimation { state.footerErrorMessage = nil }
withElementAnimation { state.footerErrorMessage = nil }
}
}

View File

@@ -64,7 +64,7 @@ struct HomeScreen: View {
Spacer()
}
.transition(.slide)
.animation(.default, value: context.viewState.showSessionVerificationBanner)
.animation(.elementDefault, value: context.viewState.showSessionVerificationBanner)
.ignoresSafeArea(.all, edges: .bottom)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
@@ -72,11 +72,11 @@ struct HomeScreen: View {
Button { context.send(viewAction: .tapUserAvatar) } label: {
HStack {
userAvatarImage
.animation(.default, value: context.viewState.userAvatar)
.animation(.elementDefault, value: context.viewState.userAvatar)
.transition(.opacity)
userDisplayNameView
.animation(.default, value: context.viewState.userDisplayName)
.animation(.elementDefault, value: context.viewState.userDisplayName)
.transition(.opacity)
}
}
@@ -147,7 +147,7 @@ struct RoomCell: View {
}
}
}
.animation(.default, value: room)
.animation(.elementDefault, value: room)
.frame(minHeight: 60.0)
.task {
context.send(viewAction: .loadRoomData(roomIdentifier: room.id))

View File

@@ -36,7 +36,7 @@ struct MessageComposer: View {
.padding(.bottom, 6.0)
.disabled(disabled)
.opacity(disabled ? 0.5 : 1.0)
.animation(.default, value: disabled)
.animation(.elementDefault, value: disabled)
.keyboardShortcut(.return, modifiers: [.command])
}
}

View File

@@ -57,7 +57,7 @@ struct MessageComposerTextField: View {
.background(placeholderView, alignment: .topLeading)
.clipShape(rect)
.overlay(rect.stroke(borderColor, lineWidth: borderWidth))
.animation(.default, value: isEditing)
.animation(.elementDefault, value: isEditing)
}
@ViewBuilder

View File

@@ -42,7 +42,7 @@ struct ImageRoomTimelineView: View {
}
}
.id(timelineItem.id)
.animation(.default, value: timelineItem.image)
.animation(.elementDefault, value: timelineItem.image)
.frame(maxHeight: 1000.0)
} else {
TimelineStyler(timelineItem: timelineItem) {

View File

@@ -37,7 +37,7 @@ struct TimelineItemList: View {
Spacer()
ProgressView()
.opacity(context.viewState.isBackPaginating ? 1.0 : 0.0)
.animation(.default, value: context.viewState.isBackPaginating)
.animation(.elementDefault, value: context.viewState.isBackPaginating)
Spacer()
}
.listRowBackground(Color.clear)

View File

@@ -40,6 +40,6 @@ struct TimelineSenderAvatarView: View {
.stroke(Color.element.background, lineWidth: 2)
)
.animation(.default, value: timelineItem.senderAvatar)
.animation(.elementDefault, value: timelineItem.senderAvatar)
}
}

View File

@@ -47,7 +47,7 @@ struct TimelineView: View {
scollToBottomButtonVisible = !visible
})
.opacity(scollToBottomButtonVisible ? 1.0 : 0.0)
.animation(.default, value: scollToBottomButtonVisible)
.animation(.elementDefault, value: scollToBottomButtonVisible)
}
}

View File

@@ -50,6 +50,11 @@ class SessionVerificationViewModel: SessionVerificationViewModelType, SessionVer
switch callback {
case .receivedVerificationData(let emojis):
guard self.stateMachine.state == .requestingVerification else {
MXLog.warning("[SessionVerificationViewModel] callbacks: Ignoring receivedVerificationData due to invalid state.")
return
}
self.stateMachine.processEvent(.didReceiveChallenge(emojis: emojis))
case .finished:
self.stateMachine.processEvent(.didAcceptChallenge)

View File

@@ -53,6 +53,9 @@ struct SplashScreenViewState: BindableState {
/// The background gradient for all 4 pages and the hidden page at the start of the carousel.
var backgroundGradient: Gradient {
if Tests.isRunningUITests {
return Gradient(colors: [.white])
}
// Include the extra stop for the hidden page at the start of the carousel.
// (The last color is the right-hand stop, but we need the left-hand stop,
// so take the last but one color from the array).

View File

@@ -123,11 +123,11 @@ struct SplashScreen: View {
if context.pageIndex == pageCount - 1 {
showHiddenPage()
withAnimation(.easeInOut(duration: 0.7)) {
withElementAnimation(.easeInOut(duration: 0.7)) {
showNextPage()
}
} else {
withAnimation(.easeInOut(duration: 0.7)) {
withElementAnimation(.easeInOut(duration: 0.7)) {
showNextPage()
}
}
@@ -185,7 +185,7 @@ struct SplashScreen: View {
stopTimer()
// Animate the change over a few frames to smooth out any stuttering.
withAnimation(.linear(duration: 0.05)) {
withElementAnimation(.linear(duration: 0.05)) {
dragOffset = isLeftToRight ? drag.translation.width : -drag.translation.width
}
}
@@ -195,11 +195,11 @@ struct SplashScreen: View {
private func handleDragGestureEnded(_ drag: DragGesture.Value, viewSize: CGSize) {
guard shouldSwipeForTranslation(drag.predictedEndTranslation.width) else {
// Reset the offset just in case.
withAnimation { dragOffset = 0 }
withElementAnimation { dragOffset = 0 }
return
}
withAnimation(.easeInOut(duration: 0.2)) {
withElementAnimation(.easeInOut(duration: 0.2)) {
if drag.predictedEndTranslation.width < -viewSize.width / 2 {
showNextPage()
} else if drag.predictedEndTranslation.width > viewSize.width / 2 {

View File

@@ -89,7 +89,7 @@ class ScreenshotDetector {
}
}
private extension PHAsset {
extension PHAsset {
static func fetchLastScreenshot() -> PHAsset? {
let options = PHFetchOptions()

View File

@@ -31,5 +31,6 @@ struct UITestsRootView: View {
.listStyle(.plain)
}
.navigationTitle("Screens")
.navigationViewStyle(.stack)
}
}

View File

@@ -23,8 +23,6 @@ schemes:
gatherCoverageData: true
coverageTargets:
- ElementX
environmentVariables:
IS_RUNNING_UNIT_TESTS: "1"
targets:
- UnitTests
- UITests

View File

@@ -8,6 +8,7 @@ GEM
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
artifactory (3.0.15)
@@ -246,10 +247,10 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.6.0)
PLATFORMS
arm64-darwin-21
x86_64-linux
ruby
DEPENDENCIES
fastlane
@@ -259,4 +260,4 @@ DEPENDENCIES
slather
BUNDLED WITH
2.3.7
2.1.4

View File

@@ -15,3 +15,11 @@ Usage:
```
./localizer.py
```
## Boot Test Simulator
Boots a desired simulator and makes status bar overrides on that.
Usage:
```
./bootTestSimulator.py 'iPhone 13 Pro Max'
```

View File

@@ -43,7 +43,7 @@ struct TemplateScreen: View {
.padding(.horizontal)
.padding(.vertical)
.readableFrame()
.background(.regularMaterial)
.background(Color.element.system)
}
}

View File

@@ -26,6 +26,8 @@ class TemplateScreenUITests: XCTestCase {
XCTAssert(title.exists)
XCTAssertEqual(title.label, "Make this chat public?")
app.assertScreenshot(.simpleRegular)
}
func testUpgradeScreen() {
@@ -36,5 +38,7 @@ class TemplateScreenUITests: XCTestCase {
XCTAssert(title.exists)
XCTAssertEqual(title.label, "Privacy warning")
app.assertScreenshot(.simpleUpgrade)
}
}

View File

@@ -0,0 +1,52 @@
#!/usr/bin/python3
from encodings import utf_8
import os
import subprocess
import json
import argparse
from datetime import datetime
RUNTIME_PREFIX = 'com.apple.CoreSimulator.SimRuntime.'
def device_name(device):
return device['name']
def runtime_name(runtime):
return runtime.replace(RUNTIME_PREFIX, '').replace('-', '.')
parser = argparse.ArgumentParser()
parser.add_argument('--name', type=str, help='Simulator name (like \'iPhone 13 Pro Max\')', required=True)
parser.add_argument('--version', type=str, default='iOS.15.5', help='OS version (defaults to \'iOS.15.5\')', required=False)
args = vars(parser.parse_args())
simulator_name = args['name']
os_version = args['version'].replace('.', '-')
runtimes_map = subprocess.check_output("/usr/bin/xcrun simctl list --json devices available", shell=True)
runtime = RUNTIME_PREFIX + os_version
json_object = json.loads(runtimes_map)
if runtime in json_object['devices']:
devices = json_object['devices'][runtime]
device_found=False
for device in devices:
if device_name(device) == simulator_name:
UDID=device['udid']
print("Found device UDID: " + UDID)
dirname = os.path.dirname(os.path.abspath(__file__))
overridden_time = datetime(2007, 1, 9, 9, 41, 0).astimezone().isoformat()
print("Will override simulator with time: " + overridden_time)
os.system("/usr/bin/xcrun simctl boot '" + UDID + "' > /dev/null 2>&1")
os.system("/usr/bin/xcrun simctl status_bar '" + UDID + "' override --time '" + overridden_time + "' --dataNetwork 'wifi' --wifiMode 'active' --wifiBars 3 --cellularMode 'active' --cellularBars 4 --batteryState 'charged' --batteryLevel 100 > /dev/null 2>&1")
print("Simulator booted and status bar overriden")
device_found=True
break
if device_found == False:
print("Device could not be found. \n\nAvailable devices: " + ', '.join(map(device_name, devices)))
exit(1)
else:
print("Runtime could not be found. \n\nAvailable runtimes: " + ', '.join(map(runtime_name, json_object['devices'].keys())))
exit(1)

View File

@@ -14,12 +14,14 @@
// limitations under the License.
//
import SnapshotTesting
import XCTest
struct Application {
static func launch() -> XCUIApplication {
let app = XCUIApplication()
app.launchEnvironment = ["IS_RUNNING_UI_TESTS": "1"]
Bundle.elementFallbackLanguage = "en"
app.launch()
return app
}
@@ -36,4 +38,39 @@ extension XCUIApplication {
button.tap()
}
/// Assert screenshot for a screen with the given identifier. Does not fail if a screenshot is newly created.
/// - Parameter identifier: Identifier of the UI test screen
func assertScreenshot(_ identifier: UITestScreenIdentifier) {
let failure = verifySnapshot(matching: screenshot().image,
as: .image(precision: 0.98, scale: nil),
named: identifier.rawValue,
testName: testName)
if let failure = failure,
!failure.contains("No reference was found on disk."),
!failure.contains("to test against the newly-recorded snapshot") {
XCTFail(failure)
}
}
private var testName: String {
osVersion + "-" + languageCode + "-" + regionCode + "-" + deviceName
}
private var deviceName: String {
UIDevice.current.name
}
private var languageCode: String {
Locale.current.languageCode ?? ""
}
private var regionCode: String {
Locale.current.regionCode ?? ""
}
private var osVersion: String {
UIDevice.current.systemVersion.replacingOccurrences(of: ".", with: "-")
}
}

View File

@@ -33,6 +33,8 @@ class AuthenticationCoordinatorUITests: XCTestCase {
app.typeText("alice\n")
app.secureTextFields["passwordTextField"].tap()
app.typeText("12345678")
app.assertScreenshot(.authenticationFlow)
// Login Screen: Tap next
app.buttons["nextButton"].tap()
@@ -41,7 +43,7 @@ class AuthenticationCoordinatorUITests: XCTestCase {
XCTAssertFalse(app.alerts.element.exists, "No alert should be shown when logging in with valid credentials.")
}
func testLoginWithIncorrectPassword() {
func testLoginWithIncorrectPassword() async throws {
// Given the authentication flow.
let app = Application.launch()
app.goToScreenWithIdentifier(.authenticationFlow)
@@ -51,11 +53,15 @@ class AuthenticationCoordinatorUITests: XCTestCase {
// Login Screen: Enter invalid credentials
app.textFields["usernameTextField"].tap()
app.typeText("alice\n")
app.typeText("87654321\n")
app.typeText("alice")
app.secureTextFields["passwordTextField"].tap()
app.typeText("87654321")
// Login Screen: Tap next
app.buttons["nextButton"].tap()
// Then login should fail.
XCTAssertTrue(app.alerts.element.exists, "An error alert should be shown when attempting login with invalid credentials.")
XCTAssertTrue(app.alerts.element.waitForExistence(timeout: 1), "An error alert should be shown when attempting login with invalid credentials.")
}
func testSelectingOIDCServer() {

View File

@@ -26,6 +26,8 @@ class BugReportUITests: XCTestCase {
XCTAssertFalse(app.images["screenshotImage"].exists)
XCTAssertFalse(app.buttons["removeScreenshotButton"].exists)
app.assertScreenshot(.bugReport)
}
func testToggleSendingLogs() {
@@ -62,6 +64,8 @@ class BugReportUITests: XCTestCase {
XCTAssert(app.images["screenshotImage"].exists)
XCTAssert(app.buttons["removeScreenshotButton"].exists)
app.assertScreenshot(.bugReportWithScreenshot)
}
func verifyInitialStateComponents(in app: XCUIApplication) {

View File

@@ -36,6 +36,8 @@ class LoginScreenUITests: XCTestCase {
validateOIDCButtonIsHidden(for: state)
validateNextButtonIsDisabled(for: state)
validateUnsupportedServerTextIsHidden(for: state)
app.assertScreenshot(.login)
// When typing in a username and password.
app.textFields.element.tap()

View File

@@ -26,6 +26,8 @@ class RoomScreenUITests: XCTestCase {
XCTAssert(app.staticTexts["roomNameLabel"].exists)
XCTAssert(app.staticTexts["roomAvatarPlaceholderImage"].exists)
XCTAssertFalse(app.images["encryptionBadgeIcon"].exists)
app.assertScreenshot(.roomPlainNoAvatar)
}
func testEncryptedWithAvatar() {
@@ -35,5 +37,7 @@ class RoomScreenUITests: XCTestCase {
XCTAssert(app.staticTexts["roomNameLabel"].exists)
XCTAssert(app.images["roomAvatarImage"].exists)
XCTAssert(app.images["encryptionBadgeIcon"].exists)
app.assertScreenshot(.roomEncryptedWithAvatar)
}
}

View File

@@ -41,6 +41,8 @@ class ServerSelectionUITests: XCTestCase {
let dismissButton = app.buttons["dismissButton"]
XCTAssertTrue(dismissButton.exists, "The dismiss button should be shown during modal presentation.")
app.assertScreenshot(.serverSelection)
}
func testEmptyAddress() async {
@@ -95,5 +97,7 @@ class ServerSelectionUITests: XCTestCase {
let confirmButton = app.buttons["confirmButton"]
XCTAssertEqual(confirmButton.label, ElementL10n.actionNext, "The confirm button should say Next when not in modal presentation.")
app.assertScreenshot(.serverSelectionNonModal)
}
}

View File

@@ -22,11 +22,13 @@ class SessionVerificationUITests: XCTestCase {
let app = Application.launch()
app.goToScreenWithIdentifier(.sessionVerification)
XCTAssert(app.navigationBars["Verify this session"].exists)
XCTAssert(app.navigationBars[ElementL10n.verificationVerifyDevice].exists)
XCTAssert(app.buttons["startButton"].exists)
XCTAssert(app.buttons["dismissButton"].exists)
XCTAssert(app.staticTexts["titleLabel"].exists)
app.assertScreenshot(.sessionVerification)
app.buttons["startButton"].tap()
@@ -52,7 +54,7 @@ class SessionVerificationUITests: XCTestCase {
let app = Application.launch()
app.goToScreenWithIdentifier(.sessionVerification)
XCTAssert(app.navigationBars["Verify this session"].exists)
XCTAssert(app.navigationBars[ElementL10n.verificationVerifyDevice].exists)
XCTAssert(app.buttons["startButton"].exists)
XCTAssert(app.buttons["dismissButton"].exists)
@@ -80,7 +82,7 @@ class SessionVerificationUITests: XCTestCase {
let app = Application.launch()
app.goToScreenWithIdentifier(.sessionVerification)
XCTAssert(app.navigationBars["Verify this session"].exists)
XCTAssert(app.navigationBars[ElementL10n.verificationVerifyDevice].exists)
XCTAssert(app.buttons["startButton"].exists)
XCTAssert(app.buttons["dismissButton"].exists)
@@ -88,12 +90,12 @@ class SessionVerificationUITests: XCTestCase {
app.buttons["startButton"].tap()
XCTAssert(app.activityIndicators["requestingVerificationProgressView"].exists)
XCTAssert(app.activityIndicators["requestingVerificationProgressView"].waitForExistence(timeout: 1))
XCTAssert(app.buttons["cancelButton"].exists)
app.buttons["cancelButton"].tap()
XCTAssert(app.images["sessionVerificationFailedIcon"].exists)
XCTAssert(app.images["sessionVerificationFailedIcon"].waitForExistence(timeout: 1))
XCTAssert(app.buttons["restartButton"].exists)
XCTAssert(app.buttons["dismissButton"].exists)

View File

@@ -35,5 +35,7 @@ class SettingsUITests: XCTestCase {
let logoutButton = app.buttons["logoutButton"]
XCTAssert(logoutButton.exists)
XCTAssertEqual(logoutButton.label, ElementL10n.logout)
app.assertScreenshot(.settings)
}
}

View File

@@ -25,6 +25,8 @@ class SplashScreenUITests: XCTestCase {
let getStartedButton = app.buttons["getStartedButton"]
XCTAssertTrue(getStartedButton.exists, "The primary action button should be shown.")
XCTAssertEqual(getStartedButton.label, ElementL10n.loginSplashSubmit)
app.assertScreenshot(.splash)
}
func testSwipingBetweenPages() {
@@ -32,8 +34,8 @@ class SplashScreenUITests: XCTestCase {
app.goToScreenWithIdentifier(.splash)
// Given the splash screen in its initial state.
let page1TitleText = app.staticTexts["Own your conversations."]
let page2TitleText = app.staticTexts["You're in control."]
let page1TitleText = app.staticTexts[ElementL10n.ftueAuthCarouselSecureTitle]
let page2TitleText = app.staticTexts[ElementL10n.ftueAuthCarouselControlTitle]
let hiddenPageTitleText = app.staticTexts["hiddenPage"].firstMatch
XCTAssertTrue(page1TitleText.isHittable, "The title from the first page of the carousel should be onscreen.")
@@ -41,21 +43,21 @@ class SplashScreenUITests: XCTestCase {
XCTAssertFalse(hiddenPageTitleText.isHittable, "The hidden page of the carousel should be offscreen.")
// When swiping to the next screen.
page1TitleText.swipeLeft()
page1TitleText.swipeLeft(velocity: .fast)
// Then the second screen should be shown.
XCTAssertFalse(page1TitleText.isHittable, "The title from the first page of the carousel should be offscreen.")
XCTAssertTrue(page2TitleText.isHittable, "The title from the second page of the carousel should be onscreen.")
// When swiping back to the previous screen.
page2TitleText.swipeRight()
page2TitleText.swipeRight(velocity: .fast)
// Then the first screen should be shown again.
XCTAssertTrue(page1TitleText.isHittable, "The title from the first page of the carousel should be onscreen.")
XCTAssertFalse(page2TitleText.isHittable, "The title from the second page of the carousel should be offscreen.")
// When swiping back to the previous screen.
page1TitleText.swipeRight()
page1TitleText.swipeRight(velocity: .fast)
// Then the screen shouldn't change and the hidden screen should be ignored.
XCTAssertTrue(page1TitleText.isHittable, "The title from the first page of the carousel should be still be onscreen.")

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:60037d78b322527f64c0a47cdfc61b96513f22c0091f7afb0a4105580b1eea41
size 91503

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9c195ee646e48580e0d728800560843bdf5dd8b79d42f4e8b698789653eceb11
size 133295

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:01d71c887f8826d4773870545b783c72ac3a53907702a9939e206a4757cd964b
size 141874

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:22845af4a94d276e29356bab40507686ec2c14eca3513ccc91793c6336fdb997
size 96025

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c59f19903191f38dfd7a9bfef2b8e2c2aa002495657253f3df4eea1b3aeea440
size 98733

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c625a166d76a1021086cd97a9548a761385ebd0dbaee6e18c5f5a9d09aec5ae3
size 99082

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:634e8238082c2c41a57827a998bc899492d7a7a1470103cf24c23aa288bd29de
size 95254

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1977a8035b854bc819d55eb0ba68cc1ad9152feb81f473addbc90cf6296c3c4d
size 92097

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ee3d153825cd161ae93cdd95967f3d3f6c1726c5e73ba7c922265b04a775c45
size 96763

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a135e969addb8545f736ab0f8c4e7aad76db7321f3ab0b5f424afffeabfed799
size 86517

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33465db5f5f55edce021a2dfadce43b2779bfea31cdade02522101118047dd6d
size 87425

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:893079215cd22c90b390e712295715c31e92edb99556c111d45af1d391b5b2a6
size 82161

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c44984bc009d7b21752487684cea325dd60b7d696c864bc892f6010cd2a260b2
size 176423

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1d6eeb4ef424e6e15bca3123ee1087a1c47da4e06732f0b66504234440302791
size 108537

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2e42686a5550b507f02e4fa8860ec88de40d673fa3700cfc36027d2e271a89a5
size 189958

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3432845788298295390e3a706638c932fa0a1c7a7a4d99a95626a50c515731d8
size 200350

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b593a969b05c11bac33f7fa63833b92a37ca0a32218a2b876f87231b2f5f4b83
size 114179

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:baade06124e5051e89c86a4a4ae74f516d2bd1e97dc4d3f4c3a1cb54aeeb0006
size 121212

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:94bf164d92d3b9a30b1f55488c15ad2fbd0ff6187177dd9ca6793af1ecf96f09
size 121590

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6deeb2e7af547800490dcb1e9ec6b201ed89331078af132289d9d746e10ccf88
size 117759

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8cd264fc469594f43120841529b71e286bb2c5d1d6af98ec8aabd405955812a0
size 112645

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:832cbe7eaaff779cb9fade6c70e46e35f5129e16d097116290a2fc7d08ccda3e
size 125052

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d1ab43eb65bff3b8928097ea7ab7c42636031b15826b3066d3bffa72d0e916eb
size 105058

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0559cb067d5d208ff3b3bfe227cb05c982f02049afbfcae16a1fd18502659110
size 105346

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9111429919c609590775d155fd3851b3cf4f3a1e95d8e29103cd5f30630d8362
size 98287

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5c13e2a3bc474aace45c29c7e0948529aa1937de79a08be45c7e0041fb419bd6
size 258258

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e251c01cc598169a9a3097b1d7ca8e4aca60bc118861abfa97f987e9edc03cc8
size 89500

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d04e1e639afb1fbecfc81ab1aae9e28bea8a0218beb48fbba38cb027ecf00c2c
size 123508

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:50638cf723cbb02e8dd07d0835a86400f38323b3d498086ef9c4627d308ce851
size 132380

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5ff18b059dcafd687568a5e514be23683b7b26ae0bdcf946cad0f6da00bdda48
size 91794

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c59f19903191f38dfd7a9bfef2b8e2c2aa002495657253f3df4eea1b3aeea440
size 98733

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c625a166d76a1021086cd97a9548a761385ebd0dbaee6e18c5f5a9d09aec5ae3
size 99082

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0d15a4cf9a2cbcd2f067bd6f4882c6aa984de0540691f0cdf18cfb9254b42340
size 94820

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1977a8035b854bc819d55eb0ba68cc1ad9152feb81f473addbc90cf6296c3c4d
size 92097

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4ab0b4e922dcec267143fd1ecb79f688f3dd1fb4142ca4b9802f9658811bd04f
size 88919

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f71157a2b3031ff4ba712e4437b1764d191b37949b31057f73d7d72d07f45b19
size 85095

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33465db5f5f55edce021a2dfadce43b2779bfea31cdade02522101118047dd6d
size 87425

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:893079215cd22c90b390e712295715c31e92edb99556c111d45af1d391b5b2a6
size 82161

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4002de7d9b069256b944d5e465d2e621ddecf774485e78d98aa53576f4b12fb4
size 171343

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c38c756d04ba1ca5e619a3a654e2e31d34a2c3ef26d13a91fa3df3a1532420f3
size 105554

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1d11254b71618a27c5480f6e6baef320a7c33fd6f930573233d2c828ac8c815e
size 170519

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f50dab74af47bf3e6b2ad0879ac795534e33ce0c5fd350286747ddca380f6bb3
size 181677

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3af816fad7b9cd25b79dc5daab3593882c9863d1659a817dd1a03464d6b74e70
size 108198

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:baade06124e5051e89c86a4a4ae74f516d2bd1e97dc4d3f4c3a1cb54aeeb0006
size 121212

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:94bf164d92d3b9a30b1f55488c15ad2fbd0ff6187177dd9ca6793af1ecf96f09
size 121590

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0b1807c06fa9ec79c1b679c3240b4b82877fcfaddc85b36800d336782d8187fd
size 116993

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8cd264fc469594f43120841529b71e286bb2c5d1d6af98ec8aabd405955812a0
size 112645

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9666d0d3e3575d86396b48740f6ee1771278385036c03b6602b734f5839b683e
size 111487

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2d698f31e4e8f1023cb30a6514ebb150c527b42dd1fec4011a56c2eaccb36bc1
size 103704

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0559cb067d5d208ff3b3bfe227cb05c982f02049afbfcae16a1fd18502659110
size 105346

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9111429919c609590775d155fd3851b3cf4f3a1e95d8e29103cd5f30630d8362
size 98287

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:86adb84be619da4c1565c925c54d590deb164934e82ea6b13479e3ecf5d2e189
size 250198

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:93d44ea1d0046ab223ccb72c748b349fa84367f3b57608632378ff308a14653e
size 91694

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bc22a188001292f3875c25e440513af319a905e7b8c3c1338c611131a503a3f5
size 131243

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4e132481b0b5440778b879901c5b3845fd94b1a3d9e9aec6677a9b40fc9585b7
size 140116

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5716a0d96325187cd36cb3e8932ab8174689fb3d7af217672338b98015c8362c
size 95897

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c59f19903191f38dfd7a9bfef2b8e2c2aa002495657253f3df4eea1b3aeea440
size 98733

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c625a166d76a1021086cd97a9548a761385ebd0dbaee6e18c5f5a9d09aec5ae3
size 99082

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1ee3a80d365927ea32e2c7f58a26d43676cb5318d81b33b5fbce4f2990af055f
size 94345

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1977a8035b854bc819d55eb0ba68cc1ad9152feb81f473addbc90cf6296c3c4d
size 92097

Some files were not shown because too many files have changed in this diff Show More