chore: update the snapshot documents and UITests

This commit is contained in:
CMK 2022-03-19 00:30:00 +08:00
parent e82b97619e
commit 12349105e7
18 changed files with 732 additions and 276 deletions

View File

@ -9,12 +9,19 @@
}
],
"defaultOptions" : {
"defaultTestExecutionTimeAllowance" : 1800,
"testTimeoutsEnabled" : true
},
"testTargets" : [
{
"selectedTests" : [
"MastodonUISnapshotTests\/testSmoke()"
"MastodonUISnapshotTests\/testSmoke()",
"MastodonUISnapshotTests\/testSnapshotCompose()",
"MastodonUISnapshotTests\/testSnapshotHome()",
"MastodonUISnapshotTests\/testSnapshotProfile()",
"MastodonUISnapshotTests\/testSnapshotSearch()",
"MastodonUISnapshotTests\/testSnapshotServerRules()",
"MastodonUISnapshotTests\/testSnapshotThread()"
],
"target" : {
"containerPath" : "container:Mastodon.xcodeproj",

View File

@ -8,12 +8,13 @@ The app use the Xcode UITest generate snapshots attachments. Then use the `xcpar
# install xcparse from Homebrew
brew install chargepoint/xcparse/xcparse
```
## Take Snapshots
We use `xcodebuild` CLI tool to trigger UITest. To change device for snapshot.
## How it works
We use `xcodebuild` CLI tool to trigger UITest.
Replace the `name` in `-destinatio` option to change device. For example:
Set the `name` in `-destinatio` option to add device for snapshot. For example:
`-destination 'platform=iOS Simulator,name=iPad Pro (12.9-inch) (5th generation)' \`
You can list the avaiable simulator:
```zsh
# list the destinations
xcodebuild \
@ -22,16 +23,27 @@ xcodebuild \
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
-workspace Mastodon.xcworkspace \
-scheme 'Mastodon - Snapshot'
# output
Available destinations for the "Mastodon - Snapshot" scheme:
{ platform:iOS Simulator, id:7F6D7727-AD49-4B79-B6F5-AEC538925576, OS:15.2, name:iPad (9th generation) }
{ platform:iOS Simulator, id:BEB9533C-F786-40E6-8C38-248F6A11FC37, OS:15.2, name:iPad Air (4th generation) }
```
#### Auto-Login before make snapshots
#### Note:
Multiple lines for destination will dispatches the parallel snapshot jobs.
## Login before make snapshots
This script trigger the `MastodonUITests/MastodonUISnapshotTests/testSignInAccount` test case to sign-in the account. The test case may wait for 2FA code or email code. Please input it if needed. Also, you can skip this and sign-in the test account manually.
Replace the `<Email>` and `<Password>` for test account.
```zsh
# build and run test case for auto sign-in
TEST_RUNNER_email='<Email>' \
TEST_RUNNER_password='<Password>' \
TEST_RUNNER_login_domain='<Domain>' \
TEST_RUNNER_login_email='<Email>' \
TEST_RUNNER_login_password='<Password>' \
xcodebuild \
test \
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
@ -48,16 +60,31 @@ TEST_RUNNER_email='<Email>' \
Note:
UITest may running silent. Open the Simulator.app to make the device display.
#### Take and extract snapshots
## Take and extract snapshots
### 1. Setup status bar
```zsh
# boot devices
xcrun simctl boot 'iPhone 8 Plus'
xcrun simctl boot 'iPhone 13 Pro Max'
xcrun simctl boot 'iPad Pro (12.9-inch) (5th generation)'
# setup magic status bar
xcrun simctl status_bar 'iPhone 13 Pro Max' override --time "9:41" --batteryState charged --batteryLevel 100
xcrun simctl status_bar 'iPhone 8 Plus' override --time "9:41" --batteryState charged --batteryLevel 100
xcrun simctl status_bar 'iPad Pro (12.9-inch) (5th generation)' override --time "9:41" --batteryState charged --batteryLevel 100
```
### 2. Take snapshots
The `TEST_RUNNER_` prefix will sets env value into test runner.
```zsh
# take snapshots
TEST_RUNNER_domain='<domain.com>' \
TEST_RUNNER_username_snapshot='username@domain.com' \
TEST_RUNNER_login_domain='<domain.com>' \
TEST_RUNNER_login_email='<email>' \
TEST_RUNNER_login_password='<email>' \
TEST_RUNNER_thread_id='<thread_id>' \
TEST_RUNNER_profile_id='<profile_id>' \
xcodebuild \
test \
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
@ -67,8 +94,9 @@ TEST_RUNNER_domain='<domain.com>' \
-destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' \
-destination 'platform=iOS Simulator,name=iPhone 8 Plus' \
-destination 'platform=iOS Simulator,name=iPad Pro (12.9-inch) (5th generation)' \
-testPlan 'AppStoreSnapshotTestPlan' \
-only-testing:MastodonUITests/MastodonUISnapshotTests/testSnapshot
-test-iterations 3 \
-retry-tests-on-failure \
-testPlan 'AppStoreSnapshotTestPlan'
# output:
Test session results, code coverage, and logs:
@ -77,6 +105,18 @@ Test session results, code coverage, and logs:
** TEST SUCCEEDED **
```
#### Note:
Add `-only-testing:MastodonUITests/MastodonUISnapshotTests/testSnapshot…` to run specific test case.
| Task | key | value |
| ------------------- | -------------- | ----------------------------------------------------- |
| testSignInAccount | login_domain | The server domain for user login |
| testSignInAccount | login_email | The user email for login |
| testSignInAccount | login_password | The user password for login |
| testSnapshotThread | thread_id | The ID for post which used for thread scene snapshot |
| testSnapshotProfile | profile_id | The ID for user which used for profile scene snapshot |
### 3. Extract snapshots
Use `xcparse screenshots <path_for_xcresult> <path_for_destination>` extracts snapshots.
```zsh
@ -86,4 +126,11 @@ xcparse screenshots '<path_for_xcresult>' ~/Downloads/MastodonBuild/Screenshots/
# output
100% [============]
🎊 Export complete! 🎊
# group
mkdir 'iPhone 8 Plus' 'iPhone 13 Pro Max' 'iPad Pro (12.9-inch) (5th generation)'
find . -name "*iPad*" -type file -print0 | xargs -0 -I {} mv {} './iPad Pro (12.9-inch) (5th generation)'
find . -name "*iPhone 8*" -type file -print0 | xargs -0 -I {} mv {} './iPhone 8 Plus'
find . -name "*iPhone 13*" -type file -print0 | xargs -0 -I {} mv {} './iPhone 13 Pro Max'
```

View File

@ -700,6 +700,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0655B257371274BEB7EB1C19 /* Pods-Mastodon.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.release snapshot.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.release snapshot.xcconfig"; sourceTree = "<group>"; };
0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.release snapshot.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.release snapshot.xcconfig"; sourceTree = "<group>"; };
0F1E2D0A2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleTitleLabelNavigationBarTitleView.swift; sourceTree = "<group>"; };
0F2021FA2613262F000C64BF /* HashtagTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineViewController.swift; sourceTree = "<group>"; };
0F202200261326E6000C64BF /* HashtagTimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineViewModel.swift; sourceTree = "<group>"; };
@ -719,6 +721,7 @@
159AC43EFE0A1F95FCB358A4 /* Pods-MastodonIntent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.release.xcconfig"; sourceTree = "<group>"; };
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = "<group>"; };
1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = "<group>"; };
2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.release snapshot.xcconfig"; sourceTree = "<group>"; };
2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = "<group>"; };
2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = "<group>"; };
2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
@ -783,6 +786,7 @@
374AA339A20E0FAC75BCDA6D /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - debug.xcconfig"; sourceTree = "<group>"; };
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release snapshot.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release snapshot.xcconfig"; sourceTree = "<group>"; };
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - release.xcconfig"; sourceTree = "<group>"; };
@ -814,6 +818,8 @@
819CEC9DCAD8E8E7BD85A7BB /* Pods-Mastodon.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk.xcconfig"; sourceTree = "<group>"; };
861BE60ED27430771CFD578D /* Pods-MastodonIntent.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.debug.xcconfig"; sourceTree = "<group>"; };
8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = "<group>"; };
8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release snapshot.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release snapshot.xcconfig"; sourceTree = "<group>"; };
8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release snapshot.xcconfig"; sourceTree = "<group>"; };
8ED8C4B1F1BA2DCFF2926BB1 /* Pods-Mastodon-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
9553C689FFA9EBC880CAB78D /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
95AD0663479892A2109EEFD0 /* Pods-ShareActionExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.release.xcconfig"; sourceTree = "<group>"; };
@ -1340,6 +1346,7 @@
ECA373ABA86BE3C2D7ED878E /* Pods-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release.xcconfig"; sourceTree = "<group>"; };
EE13214BC0246BE5210CCC10 /* Pods-AppShared.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk.xcconfig"; sourceTree = "<group>"; };
F31E7502A7E3945B98C6CBAF /* Pods-NotificationService.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk.xcconfig"; sourceTree = "<group>"; };
F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.release snapshot.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.release snapshot.xcconfig"; sourceTree = "<group>"; };
F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F4C94BD75C96D0EFF5F6D961 /* Pods_MastodonIntent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonIntent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - release.xcconfig"; sourceTree = "<group>"; };
@ -1541,6 +1548,13 @@
C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */,
F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */,
159AC43EFE0A1F95FCB358A4 /* Pods-MastodonIntent.release.xcconfig */,
3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */,
0655B257371274BEB7EB1C19 /* Pods-Mastodon.release snapshot.xcconfig */,
0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */,
2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */,
8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */,
8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */,
F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -3430,22 +3444,22 @@
);
mainGroup = DB427DC925BAA00100D1B89D;
packageReferences = (
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */,
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */,
2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */,
DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */,
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */,
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */,
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */,
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */,
DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */,
DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */,
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */,
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */,
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */,
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */,
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */,
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */,
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */,
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */,
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */,
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */,
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */,
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */,
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */,
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */,
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */,
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */,
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */,
);
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
projectDirPath = "";
@ -4925,6 +4939,237 @@
};
name = Release;
};
DBEB19E127E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INTENTS_CODEGEN_LANGUAGE = Swift;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = SNAPSHOT;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = "Release Snapshot";
};
DBEB19E227E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0655B257371274BEB7EB1C19 /* Pods-Mastodon.release snapshot.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 108;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.7;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = "Release Snapshot";
};
DBEB19E327E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.MastodonTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mastodon.app/Mastodon";
};
name = "Release Snapshot";
};
DBEB19E427E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.MastodonUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Mastodon;
};
name = "Release Snapshot";
};
DBEB19E527E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 108;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 108;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AppShared/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.AppShared;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = "Release Snapshot";
};
DBEB19E627E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 108;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.7;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = "Release Snapshot";
};
DBEB19E727E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 108;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.7;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = "Release Snapshot";
};
DBEB19E827E4658E00B0E80E /* Release Snapshot */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 108;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.7;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.MastodonIntent;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = "Release Snapshot";
};
DBF8AE1C263293E400C9C23C /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9553C689FFA9EBC880CAB78D /* Pods-NotificationService.debug.xcconfig */;
@ -4981,6 +5226,7 @@
buildConfigurations = (
DB427DFA25BAA00100D1B89D /* Debug */,
DB427DFB25BAA00100D1B89D /* Release */,
DBEB19E127E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -4990,6 +5236,7 @@
buildConfigurations = (
DB427DFD25BAA00100D1B89D /* Debug */,
DB427DFE25BAA00100D1B89D /* Release */,
DBEB19E227E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -4999,6 +5246,7 @@
buildConfigurations = (
DB427E0025BAA00100D1B89D /* Debug */,
DB427E0125BAA00100D1B89D /* Release */,
DBEB19E327E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5008,6 +5256,7 @@
buildConfigurations = (
DB427E0325BAA00100D1B89D /* Debug */,
DB427E0425BAA00100D1B89D /* Release */,
DBEB19E427E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5017,6 +5266,7 @@
buildConfigurations = (
DB6804892637CD4C00430867 /* Debug */,
DB68048A2637CD4C00430867 /* Release */,
DBEB19E527E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5026,6 +5276,7 @@
buildConfigurations = (
DB8FABD026AEC7B2008E5AF4 /* Debug */,
DB8FABD326AEC7B2008E5AF4 /* Release */,
DBEB19E827E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5035,6 +5286,7 @@
buildConfigurations = (
DBC6461D26A170AB00B0E31B /* Debug */,
DBC6462026A170AB00B0E31B /* Release */,
DBEB19E727E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5044,6 +5296,7 @@
buildConfigurations = (
DBF8AE1C263293E400C9C23C /* Debug */,
DBF8AE1D263293E400C9C23C /* Release */,
DBEB19E627E4658E00B0E80E /* Release Snapshot */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@ -5051,7 +5304,7 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = {
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/vtourraine/ThirdPartyMailer.git";
requirement = {
@ -5067,7 +5320,7 @@
minimumVersion = 3.1.0;
};
};
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */ = {
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/TimOliver/TOCropViewController.git";
requirement = {
@ -5083,7 +5336,7 @@
minimumVersion = 0.1.1;
};
};
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */ = {
DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git";
requirement = {
@ -5091,7 +5344,7 @@
version = 2.2.1;
};
};
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git";
requirement = {
@ -5099,7 +5352,7 @@
minimumVersion = 8.0.0;
};
};
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */ = {
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Alamofire/AlamofireImage.git";
requirement = {
@ -5107,7 +5360,7 @@
minimumVersion = 4.1.0;
};
};
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */ = {
DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-collections.git";
requirement = {
@ -5115,7 +5368,7 @@
minimumVersion = 0.0.5;
};
};
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = {
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git";
requirement = {
@ -5131,7 +5384,7 @@
minimumVersion = 1.4.1;
};
};
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = {
DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/slackhq/PanModal.git";
requirement = {
@ -5139,7 +5392,7 @@
minimumVersion = 1.2.7;
};
};
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = {
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ra1028/DifferenceKit.git";
requirement = {
@ -5147,7 +5400,7 @@
version = 1.2.0;
};
};
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */ = {
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/MainasuK/DiffableDataSources.git";
requirement = {
@ -5155,7 +5408,7 @@
kind = branch;
};
};
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */ = {
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/cezheng/Fuzi.git";
requirement = {
@ -5171,7 +5424,7 @@
minimumVersion = 2.11.0;
};
};
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */ = {
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/MainasuK/FPSIndicator.git";
requirement = {
@ -5184,7 +5437,7 @@
/* Begin XCSwiftPackageProductDependency section */
2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */ = {
isa = XCSwiftPackageProductDependency;
package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */;
package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */;
productName = ThirdPartyMailer;
};
2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */ = {
@ -5194,7 +5447,7 @@
};
2D939AC725EE14620076FA61 /* CropViewController */ = {
isa = XCSwiftPackageProductDependency;
package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */;
package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */;
productName = CropViewController;
};
5D526FE125BE9AC400460CB9 /* MastodonSDK */ = {
@ -5213,17 +5466,17 @@
};
DB01E23226A98F0900C3965B /* MastodonMeta */ = {
isa = XCSwiftPackageProductDependency;
package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */;
package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */;
productName = MastodonMeta;
};
DB01E23426A98F0900C3965B /* MetaTextKit */ = {
isa = XCSwiftPackageProductDependency;
package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */;
package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */;
productName = MetaTextKit;
};
DB0C946426A6FD4D0088FB11 /* AlamofireImage */ = {
isa = XCSwiftPackageProductDependency;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */;
productName = AlamofireImage;
};
DB179266278D5A4A00B71DEB /* MastodonSDK */ = {
@ -5232,22 +5485,22 @@
};
DB3D0FF225BAA61700EAA174 /* AlamofireImage */ = {
isa = XCSwiftPackageProductDependency;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */;
productName = AlamofireImage;
};
DB552D4E26BBD10C00E481F6 /* OrderedCollections */ = {
isa = XCSwiftPackageProductDependency;
package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */;
package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */;
productName = OrderedCollections;
};
DB68050F2637D0F800430867 /* KeychainAccess */ = {
isa = XCSwiftPackageProductDependency;
package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */;
package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */;
productName = KeychainAccess;
};
DB6D9F41263527CE008423CD /* AlamofireImage */ = {
isa = XCSwiftPackageProductDependency;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */;
productName = AlamofireImage;
};
DB9A487D2603456B008B817C /* UITextView+Placeholder */ = {
@ -5257,22 +5510,22 @@
};
DBA5A52E26F07ED800CACBAA /* PanModal */ = {
isa = XCSwiftPackageProductDependency;
package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */;
package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */;
productName = PanModal;
};
DBAC6482267D0B21007FE9FD /* DifferenceKit */ = {
isa = XCSwiftPackageProductDependency;
package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */;
package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */;
productName = DifferenceKit;
};
DBAC649D267DFE43007FE9FD /* DiffableDataSources */ = {
isa = XCSwiftPackageProductDependency;
package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */;
package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */;
productName = DiffableDataSources;
};
DBAC64A0267E6D02007FE9FD /* Fuzi */ = {
isa = XCSwiftPackageProductDependency;
package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */;
package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */;
productName = Fuzi;
};
DBB525072611EAC0002F1F29 /* Tabman */ = {
@ -5300,7 +5553,7 @@
};
DBF7A0FB26830C33004176A2 /* FPSIndicator */ = {
isa = XCSwiftPackageProductDependency;
package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */;
package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */;
productName = FPSIndicator;
};
/* End XCSwiftPackageProductDependency section */

View File

@ -51,7 +51,7 @@
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Release"
buildConfiguration = "Release Snapshot"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
@ -63,7 +63,7 @@
</TestPlans>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
buildConfiguration = "Release Snapshot"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
disableMainThreadChecker = "YES"

View File

@ -9,7 +9,7 @@
<key>isShown</key>
<true/>
<key>orderHint</key>
<integer>16</integer>
<integer>15</integer>
</dict>
<key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict>
@ -104,7 +104,7 @@
<key>MastodonIntent.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>32</integer>
<integer>37</integer>
</dict>
<key>MastodonIntents.xcscheme_^#shared#^_</key>
<dict>
@ -119,12 +119,12 @@
<key>NotificationService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>33</integer>
<integer>36</integer>
</dict>
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>31</integer>
<integer>38</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "IMG_1010.jpg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

@ -381,7 +381,7 @@ extension ComposeViewController {
// bind publish bar button state
viewModel.$isPublishBarButtonItemEnabled
.receive(on: DispatchQueue.main)
.assign(to: \.isEnabled, on: publishBarButtonItem)
.assign(to: \.isEnabled, on: publishButton)
.store(in: &disposeBag)
// bind media button toolbar state
@ -915,14 +915,25 @@ extension ComposeViewController: UITextViewDelegate {
// MARK: - ComposeToolbarViewDelegate
extension ComposeViewController: ComposeToolbarViewDelegate {
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) {
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, mediaButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) {
switch type {
case .photoLibrary:
present(photoLibraryPicker, animated: true, completion: nil)
case .camera:
present(imagePickerController, animated: true, completion: nil)
case .browse:
#if SNAPSHOT
guard let image = UIImage(named: "Athens") else { return }
let attachmentService = MastodonAttachmentService(
context: context,
image: image,
initialAuthenticationBox: viewModel.authenticationBox
)
viewModel.attachmentServices = viewModel.attachmentServices + [attachmentService]
#else
present(documentPickerController, animated: true, completion: nil)
#endif
}
}

View File

@ -13,7 +13,7 @@ import MastodonAsset
import MastodonLocalization
protocol ComposeToolbarViewDelegate: AnyObject {
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, mediaButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any)
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any)
@ -304,21 +304,21 @@ extension ComposeToolbarView {
let photoLibraryAction = UIAction(title: L10n.Scene.Compose.MediaSelection.photoLibrary, image: UIImage(systemName: "rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .photoLibrary", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, cameraButtonDidPressed: self.mediaButton, mediaSelectionType: .photoLibrary)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .photoLibrary)
}
children.append(photoLibraryAction)
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let cameraAction = UIAction(title: L10n.Scene.Compose.MediaSelection.camera, image: UIImage(systemName: "camera"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .camera", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, cameraButtonDidPressed: self.mediaButton, mediaSelectionType: .camera)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .camera)
})
children.append(cameraAction)
}
let browseAction = UIAction(title: L10n.Scene.Compose.MediaSelection.browse, image: UIImage(systemName: "ellipsis"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in
guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: mediaSelectionType: .browse", ((#file as NSString).lastPathComponent), #line, #function)
self.delegate?.composeToolbarView(self, cameraButtonDidPressed: self.mediaButton, mediaSelectionType: .browse)
self.delegate?.composeToolbarView(self, mediaButtonDidPressed: self.mediaButton, mediaSelectionType: .browse)
}
children.append(browseAction)

View File

@ -6,7 +6,7 @@
//
#if DEBUG
#if DEBUG || SNAPSHOT
import os.log
import UIKit
import CoreData

View File

@ -127,6 +127,11 @@ extension HomeTimelineViewController {
settingBarButtonItem.action = #selector(HomeTimelineViewController.settingBarButtonItemPressed(_:))
#endif
#if SNAPSHOT
titleView.logoButton.menu = self.debugMenu
titleView.button.menu = self.debugMenu
#endif
viewModel.$displayComposeBarButtonItem
.receive(on: DispatchQueue.main)
.sink { [weak self] displayComposeBarButtonItem in

View File

@ -65,6 +65,9 @@ extension HomeTimelineNavigationBarTitleView {
configure(state: .logo)
logoButton.addTarget(self, action: #selector(HomeTimelineNavigationBarTitleView.logoButtonDidPressed(_:)), for: .touchUpInside)
button.addTarget(self, action: #selector(HomeTimelineNavigationBarTitleView.buttonDidPressed(_:)), for: .touchUpInside)
logoButton.accessibilityIdentifier = "TitleButton"
button.accessibilityIdentifier = "TitleButton"
}
}

View File

@ -38,7 +38,7 @@ final class MastodonConfirmEmailViewModel {
self.updateCredentialQuery = updateCredentialQuery
}
#if DEBUG
#if DEBUG || SNAPSHOT
init() {
self.context = AppContext.shared
self.email = "example.com"

View File

@ -12,6 +12,8 @@ final class CachedProfileViewModel: ProfileViewModel {
init(context: AppContext, mastodonUser: MastodonUser) {
super.init(context: context, optionalMastodonUser: mastodonUser)
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Profile] user[\(mastodonUser.id)] profile: \(mastodonUser.acctWithDomain)")
}
}

View File

@ -59,6 +59,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
sceneCoordinator.setup()
sceneCoordinator.setupOnboardingIfNeeds(animated: false)
window.makeKeyAndVisible()
#if SNAPSHOT
// speedup animation
// window.layer.speed = 999
// disable animation
UIView.setAnimationsEnabled(false)
#endif
if let shortcutItem = connectionOptions.shortcutItem {
// Save it off for later when we become active.
@ -67,7 +75,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
UserDefaults.shared.observe(\.customUserInterfaceStyle, options: [.initial, .new]) { [weak self] defaults, _ in
guard let self = self else { return }
#if SNAPSHOT
// toggle Dark Mode
// https://stackoverflow.com/questions/32988241/how-to-access-launchenvironment-and-launcharguments-set-in-xcuiapplication-runn
if ProcessInfo.processInfo.arguments.contains("UIUserInterfaceStyleForceDark") {
self.window?.overrideUserInterfaceStyle = .dark
}
#else
self.window?.overrideUserInterfaceStyle = defaults.customUserInterfaceStyle
#endif
}
.store(in: &observations)

View File

@ -45,6 +45,19 @@ extension MastodonUISnapshotTests {
extension MastodonUISnapshotTests {
func takeSnapshot(name: String) {
let snapshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(
uniformTypeIdentifier: "public.png",
name: "\(name).\(UIDevice.current.name).png",
payload: snapshot.pngRepresentation,
userInfo: nil
)
attachment.lifetime = .keepAlways
add(attachment)
}
// make tab display by tap it
private func tapTab(app: XCUIApplication, tab: String) {
let searchTab = app.tabBars.buttons[tab]
if searchTab.exists { searchTab.tap() }
@ -52,159 +65,223 @@ extension MastodonUISnapshotTests {
let searchCell = app.collectionViews.cells[tab]
if searchCell.exists { searchCell.tap() }
}
private func showTitleButtonMenu(app: XCUIApplication) async throws {
let titleButton = app.navigationBars.buttons["TitleButton"].firstMatch
XCTAssert(titleButton.waitForExistence(timeout: 5))
titleButton.press(forDuration: 1.0)
try await Task.sleep(nanoseconds: .second * 1)
}
func testSnapshot() async throws {
let app = XCUIApplication()
app.launch()
private func snapshot(
name: String,
count: Int = 3,
task: (_ app: XCUIApplication) async throws -> Void
) async rethrows {
var app = XCUIApplication()
try await testSnapshotHome()
try await testSnapshotSearch()
try await testSnapshotNotification()
try await testSnapshotProfile()
try await testSnapshotCompose()
}
func testSnapshotHome() async throws {
let app = XCUIApplication()
app.launch()
tapTab(app: app, tab: "Home")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Home - 1")
tapTab(app: app, tab: "Home")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Home - 2")
tapTab(app: app, tab: "Home")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Home - 3")
}
func testSnapshotSearch() async throws {
let app = XCUIApplication()
app.launch()
tapTab(app: app, tab: "Search")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Search - 1")
tapTab(app: app, tab: "Search")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Search - 2")
tapTab(app: app, tab: "Search")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Search - 3")
}
func testSnapshotNotification() async throws {
let app = XCUIApplication()
app.launch()
tapTab(app: app, tab: "Notification")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Notification - 1")
tapTab(app: app, tab: "Notification")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Notification - 2")
tapTab(app: app, tab: "Notification")
try await Task.sleep(nanoseconds: .second * 3)
takeSnapshot(name: "Notification - 3")
}
func testSnapshotProfile() async throws {
let username = ProcessInfo.processInfo.environment["username_snapshot"] ?? "Gargron"
let app = XCUIApplication()
app.launch()
// Go to Search tab
tapTab(app: app, tab: "Search")
// Tap and search user
let searchField = app.navigationBars.searchFields.firstMatch
XCTAssert(searchField.waitForExistence(timeout: 5))
searchField.tap()
searchField.typeText(username)
// Tap the cell and display user profile
let cell = app.tables.cells.firstMatch
XCTAssert(cell.waitForExistence(timeout: 5))
cell.tap()
try await Task.sleep(nanoseconds: .second * 5)
takeSnapshot(name: "Profile")
}
func testSnapshotCompose() async throws {
let app = XCUIApplication()
app.launch()
// open Compose scene
let composeBarButtonItem = app.navigationBars.buttons["Compose"].firstMatch
let composeCollectionViewCell = app.collectionViews.cells["Compose"]
if composeBarButtonItem.waitForExistence(timeout: 5) {
composeBarButtonItem.tap()
} else if composeCollectionViewCell.waitForExistence(timeout: 5) {
composeCollectionViewCell.tap()
} else {
XCTFail()
// pass -1 to debug test case
guard count >= 0 else {
app.launch()
try await task(app)
takeSnapshot(name: name)
return
}
// type text
let textView = app.textViews.firstMatch
XCTAssert(textView.waitForExistence(timeout: 5))
textView.tap()
textView.typeText("Look at that view! #Athens ")
// tap Add Attachment toolbar button
let addAttachmentButton = app.buttons["Add Attachment"].firstMatch
XCTAssert(addAttachmentButton.waitForExistence(timeout: 5))
addAttachmentButton.tap()
// Light Mode
for index in 0..<count {
app.launch()
try await task(app)
let name = "\(name).light.\(index+1)"
takeSnapshot(name: name)
}
// tap Photo Library menu action
let photoLibraryButton = app.buttons["Photo Library"].firstMatch
XCTAssert(photoLibraryButton.waitForExistence(timeout: 5))
photoLibraryButton.tap()
// select the first photo
let photo = app.images.containing(NSPredicate(format: "label BEGINSWITH 'Photo'")).element(boundBy: 0).firstMatch
XCTAssert(photo.waitForExistence(timeout: 5))
photo.tap()
// tap Add barButtonItem
let addBarButtonItem = app.navigationBars.buttons["Add"].firstMatch
XCTAssert(addBarButtonItem.waitForExistence(timeout: 5))
addBarButtonItem.tap()
try await Task.sleep(nanoseconds: .second * 10)
takeSnapshot(name: "Compose - 1")
try await Task.sleep(nanoseconds: .second * 10)
takeSnapshot(name: "Compose - 2")
try await Task.sleep(nanoseconds: .second * 10)
takeSnapshot(name: "Compose - 3")
// Dark Mode
app = XCUIApplication()
app.launchArguments.append("UIUserInterfaceStyleForceDark")
for index in 0..<count {
app.launch()
try await task(app)
let name = "\(name).dark.\(index+1)"
takeSnapshot(name: name)
}
}
}
// MARK: - Home
extension MastodonUISnapshotTests {
func testSnapshotHome() async throws {
try await snapshot(name: "Home") { app in
tapTab(app: app, tab: "Home")
try await Task.sleep(nanoseconds: .second * 3)
}
}
}
// MARK: - Thread
extension MastodonUISnapshotTests {
func testSnapshotThread() async throws {
try await snapshot(name: "Thread") { app in
let threadID = ProcessInfo.processInfo.environment["thread_id"]!
try await coordinateToThread(app: app, id: threadID)
try await Task.sleep(nanoseconds: .second * 5)
}
}
// use debug entry goto thread scene by thread ID
// assert the thread ID is valid for current sign in user server
private func coordinateToThread(app: XCUIApplication, id: String) async throws {
try await Task.sleep(nanoseconds: .second * 1)
try await showTitleButtonMenu(app: app)
let showMenu = app.collectionViews.buttons["Show…"].firstMatch
XCTAssert(showMenu.waitForExistence(timeout: 3))
showMenu.tap()
try await Task.sleep(nanoseconds: .second * 1)
let threadAction = app.collectionViews.buttons["Thread"].firstMatch
XCTAssert(threadAction.waitForExistence(timeout: 3))
threadAction.tap()
try await Task.sleep(nanoseconds: .second * 1)
let textField = app.alerts.textFields.firstMatch
XCTAssert(textField.waitForExistence(timeout: 3))
textField.typeText(id)
try await Task.sleep(nanoseconds: .second * 1)
let showAction = app.alerts.buttons["Show"].firstMatch
XCTAssert(showAction.waitForExistence(timeout: 3))
showAction.tap()
try await Task.sleep(nanoseconds: .second * 1)
}
}
// MARK: - Profile
extension MastodonUISnapshotTests {
func testSnapshotProfile() async throws {
try await snapshot(name: "Profile") { app in
let profileID = ProcessInfo.processInfo.environment["profile_id"]!
try await coordinateToProfile(app: app, id: profileID)
try await Task.sleep(nanoseconds: .second * 5)
}
}
// use debug entry goto thread scene by profile ID
// assert the profile ID is valid for current sign in user server
private func coordinateToProfile(app: XCUIApplication, id: String) async throws {
try await Task.sleep(nanoseconds: .second * 1)
try await showTitleButtonMenu(app: app)
let showMenu = app.collectionViews.buttons["Show…"].firstMatch
XCTAssert(showMenu.waitForExistence(timeout: 3))
showMenu.tap()
try await Task.sleep(nanoseconds: .second * 1)
let profileAction = app.collectionViews.buttons["Profile"].firstMatch
XCTAssert(profileAction.waitForExistence(timeout: 3))
profileAction.tap()
try await Task.sleep(nanoseconds: .second * 1)
let textField = app.alerts.textFields.firstMatch
XCTAssert(textField.waitForExistence(timeout: 3))
textField.typeText(id)
try await Task.sleep(nanoseconds: .second * 1)
let showAction = app.alerts.buttons["Show"].firstMatch
XCTAssert(showAction.waitForExistence(timeout: 3))
showAction.tap()
try await Task.sleep(nanoseconds: .second * 1)
}
}
// MARK: - Server Rules
extension MastodonUISnapshotTests {
func testSnapshotServerRules() async throws {
try await snapshot(name: "ServerRules") { app in
let domain = "mastodon.social"
try await coordinateToOnboarding(app: app, page: .serverRules(domain: domain))
try await Task.sleep(nanoseconds: .second * 3)
}
}
}
// MARK: - Search
extension MastodonUISnapshotTests {
func testSnapshotSearch() async throws {
try await snapshot(name: "ServerRules") { app in
tapTab(app: app, tab: "Search")
try await Task.sleep(nanoseconds: .second * 3)
}
}
}
// MARK: - Compose
extension MastodonUISnapshotTests {
func testSnapshotCompose() async throws {
try await snapshot(name: "Compose") { app in
// open Compose scene
let composeBarButtonItem = app.navigationBars.buttons["Compose"].firstMatch
let composeCollectionViewCell = app.collectionViews.cells["Compose"]
if composeBarButtonItem.waitForExistence(timeout: 5) {
composeBarButtonItem.tap()
} else if composeCollectionViewCell.waitForExistence(timeout: 5) {
composeCollectionViewCell.tap()
} else {
XCTFail()
}
// type text
let textView = app.textViews.firstMatch
XCTAssert(textView.waitForExistence(timeout: 5))
textView.tap()
textView.typeText("Look at that view! #Athens ")
// tap Add Attachment toolbar button
let addAttachmentButton = app.buttons["Add Attachment"].firstMatch
XCTAssert(addAttachmentButton.waitForExistence(timeout: 5))
addAttachmentButton.tap()
// tap Browse menu action to add stub image
let browseButton = app.buttons["Browse"].firstMatch
XCTAssert(browseButton.waitForExistence(timeout: 5))
browseButton.tap()
try await Task.sleep(nanoseconds: .second * 10)
}
}
}
// MARK: Sign in
extension MastodonUISnapshotTests {
// Please check the Documentation/Snapshot.md and run this test case in the command line
func testSignInAccount() async throws {
guard let domain = ProcessInfo.processInfo.environment["domain"] else {
fatalError("env 'domain' missing")
guard let domain = ProcessInfo.processInfo.environment["login_domain"] else {
fatalError("env 'login_domain' missing")
}
guard let email = ProcessInfo.processInfo.environment["email"] else {
fatalError("env 'email' missing")
guard let email = ProcessInfo.processInfo.environment["login_email"] else {
fatalError("env 'login_email' missing")
}
guard let password = ProcessInfo.processInfo.environment["password"] else {
fatalError("env 'password' missing")
guard let password = ProcessInfo.processInfo.environment["login_password"] else {
fatalError("env 'login_password' missing")
}
try await signInApplication(
domain: domain,
@ -221,62 +298,7 @@ extension MastodonUISnapshotTests {
let app = XCUIApplication()
app.launch()
// check in Onboarding or not
let loginButton = app.buttons["Log In"].firstMatch
let loginButtonExists = loginButton.waitForExistence(timeout: 5)
// goto Onboarding scene if already sign-in
if !loginButtonExists {
let profileTabBarButton = app.tabBars.buttons["Profile"]
XCTAssert(profileTabBarButton.waitForExistence(timeout: 3))
profileTabBarButton.press(forDuration: 2)
let addAccountCell = app.cells.containing(.staticText, identifier: "Add Account").firstMatch
XCTAssert(addAccountCell.waitForExistence(timeout: 3))
addAccountCell.tap()
}
// Tap login button
XCTAssert(loginButtonExists)
loginButton.tap()
// type domain
let domainTextField = app.textFields.firstMatch
XCTAssert(domainTextField.waitForExistence(timeout: 5))
domainTextField.tap()
// Skip system keyboard swipe input guide
skipKeyboardSwipeInputGuide(app: app)
domainTextField.typeText(domain)
XCUIApplication().keyboards.buttons["Done"].firstMatch.tap()
// wait searching
try await Task.sleep(nanoseconds: .second * 3)
// tap server
let cell = app.cells.containing(.staticText, identifier: domain).firstMatch
XCTAssert(cell.waitForExistence(timeout: 5))
cell.tap()
// add system alert monitor
// A. The monitor not works
// addUIInterruptionMonitor(withDescription: "Authentication Alert") { alert in
// alert.buttons["Continue"].firstMatch.tap()
// return true
// }
// tap next button
let nextButton = app.buttons.matching(NSPredicate(format: "enabled == true")).matching(identifier: "Next").firstMatch
XCTAssert(nextButton.waitForExistence(timeout: 3))
nextButton.tap()
// wait authentication alert display
try await Task.sleep(nanoseconds: .second * 3)
// B. Workaround
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let continueButton = springboard.buttons["Continue"].firstMatch
XCTAssert(continueButton.waitForExistence(timeout: 3))
continueButton.tap()
try await coordinateToOnboarding(app: app, page: .login(domain: domain))
// wait OAuth webpage display
try await Task.sleep(nanoseconds: .second * 10)
@ -331,24 +353,102 @@ extension MastodonUISnapshotTests {
print("OAuth finish")
}
private func skipKeyboardSwipeInputGuide(app: XCUIApplication) {
enum OnboardingPage {
case welcome
case login(domain: String)
case serverRules(domain: String)
}
private func coordinateToOnboarding(app: XCUIApplication, page: OnboardingPage) async throws {
// check in Onboarding or not
let loginButton = app.buttons["Log In"].firstMatch
try await Task.sleep(nanoseconds: .second * 3)
let loginButtonExists = loginButton.exists
// goto Onboarding scene if already sign-in
if !loginButtonExists {
try await showTitleButtonMenu(app: app)
let showMenu = app.collectionViews.buttons["Show…"].firstMatch
XCTAssert(showMenu.waitForExistence(timeout: 3))
showMenu.tap()
try await Task.sleep(nanoseconds: .second * 1)
let welcomeAction = app.collectionViews.buttons["Welcome"].firstMatch
XCTAssert(welcomeAction.waitForExistence(timeout: 3))
welcomeAction.tap()
try await Task.sleep(nanoseconds: .second * 1)
}
func type(domain: String) async throws {
// type domain
let domainTextField = app.textFields.firstMatch
XCTAssert(domainTextField.waitForExistence(timeout: 5))
domainTextField.tap()
// Skip system keyboard swipe input guide
try await skipKeyboardSwipeInputGuide(app: app)
domainTextField.typeText(domain)
XCUIApplication().keyboards.buttons["Done"].firstMatch.tap()
}
switch page {
case .welcome:
break
case .login(let domain):
// Tap login button
XCTAssert(loginButtonExists)
loginButton.tap()
// type domain
try await type(domain: domain)
// add system alert monitor
// A. The monitor not works
// addUIInterruptionMonitor(withDescription: "Authentication Alert") { alert in
// alert.buttons["Continue"].firstMatch.tap()
// return true
// }
// tap next
try await selectServerAndContinue(app: app, domain: domain)
// wait authentication alert display
try await Task.sleep(nanoseconds: .second * 3)
// B. Workaround
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let continueButton = springboard.buttons["Continue"].firstMatch
XCTAssert(continueButton.waitForExistence(timeout: 3))
continueButton.tap()
case .serverRules(let domain):
// Tap sign up button
let signUpButton = app.buttons["Get Started"].firstMatch
XCTAssert(signUpButton.waitForExistence(timeout: 3))
signUpButton.tap()
// type domain
try await type(domain: domain)
// tap next
try await selectServerAndContinue(app: app, domain: domain)
}
}
private func selectServerAndContinue(app: XCUIApplication, domain: String) async throws {
// wait searching
try await Task.sleep(nanoseconds: .second * 3)
// tap server
let cell = app.cells.containing(.staticText, identifier: domain).firstMatch
XCTAssert(cell.waitForExistence(timeout: 5))
cell.tap()
// tap next button
let nextButton = app.buttons.matching(NSPredicate(format: "enabled == true")).matching(identifier: "Next").firstMatch
XCTAssert(nextButton.waitForExistence(timeout: 3))
nextButton.tap()
}
private func skipKeyboardSwipeInputGuide(app: XCUIApplication) async throws {
let swipeInputLabel = app.staticTexts["Speed up your typing by sliding your finger across the letters to compose a word."].firstMatch
guard swipeInputLabel.waitForExistence(timeout: 3) else { return }
try await Task.sleep(nanoseconds: .second * 3)
guard swipeInputLabel.exists else { return }
let continueButton = app.buttons["Continue"]
continueButton.tap()
}
}
extension MastodonUISnapshotTests {
func takeSnapshot(name: String) {
let snapshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(
uniformTypeIdentifier: "public.png",
name: "Screenshot-\(name)-\(UIDevice.current.name).png",
payload: snapshot.pngRepresentation,
userInfo: nil
)
attachment.lifetime = .keepAlways
add(attachment)
}
}

View File

@ -16,7 +16,7 @@ target 'Mastodon' do
pod 'Sourcery', '~> 1.6.1'
# DEBUG
pod 'FLEX', '~> 4.4.0', :configurations => ['Debug']
pod 'FLEX', '~> 4.4.0', :configurations => ['Debug', "Release Snapshot"]
target 'MastodonTests' do
inherit! :search_paths

View File

@ -40,6 +40,6 @@ SPEC CHECKSUMS:
SwiftGen: 67860cc7c3cfc2ed25b9b74cfd55495fc89f9108
"UITextField+Shake": 298ac5a0f239d731bdab999b19b628c956ca0ac3
PODFILE CHECKSUM: 1426a4b78d8d711a5ae7600b9deea8986ddfdf7d
PODFILE CHECKSUM: c471d1f9c923dc63bf8684415c79b85adb2ac36b
COCOAPODS: 1.11.2