diff --git a/AccessibilityTests/Sources/Application.swift b/AccessibilityTests/Sources/Application.swift new file mode 100644 index 000000000..d78470936 --- /dev/null +++ b/AccessibilityTests/Sources/Application.swift @@ -0,0 +1,41 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import XCTest + +enum Application { + static func launch(viewID: String) -> XCUIApplication { + checkEnvironments() + + let app = XCUIApplication() + + let launchEnvironment = [ + "ACCESSIBILITY_VIEW": viewID + ] + + app.launchEnvironment = launchEnvironment + app.launch() + return app + } + + private static func checkEnvironments() { + let requirediPhoneSimulator = "iPhone17,3" // iPhone 16 + let requiredOSVersion = 18 + + let osVersion = ProcessInfo().operatingSystemVersion + guard osVersion.majorVersion == requiredOSVersion else { + fatalError("Switch to iOS \(requiredOSVersion) for these tests.") + } + + guard let deviceModel = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] else { + fatalError("Unknown simulator.") + } + guard deviceModel == requirediPhoneSimulator else { + fatalError("Running on \(deviceModel) but we only support \(requirediPhoneSimulator)") + } + } +} diff --git a/AccessibilityTests/Sources/Test.swift b/AccessibilityTests/Sources/Test.swift new file mode 100644 index 000000000..8c5e3ae70 --- /dev/null +++ b/AccessibilityTests/Sources/Test.swift @@ -0,0 +1,43 @@ +// +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import XCTest + +@MainActor +class Test: XCTestCase { + var app: XCUIApplication! + + func test() async throws { + let client = try UITestsSignalling.Client(mode: .tests) + app = Application.launch(viewID: "SecureBackupLogoutConfirmationScreen_Previews") + await client.waitForApp() + defer { try? client.stop() } + + try client.send(.accessibilityAudit(.nextPreview)) + forLoop: for await signal in client.signals.values { + switch signal { + case .accessibilityAudit(let auditSignal): + switch auditSignal { + case .nextPreviewReady(let name): + try? app.performAccessibilityAudit { issue in + XCTFail("\(name): \(issue)") + return true + } + try? client.send(.accessibilityAudit(.nextPreview)) + case .noMorePreviews: + break forLoop + default: + fatalError("Unhandled signal") + } + default: + fatalError("Unhandled signal") + } + } + + app.terminate() + } +} diff --git a/AccessibilityTests/SupportingFiles/AccessibilityTests.xctestplan b/AccessibilityTests/SupportingFiles/AccessibilityTests.xctestplan new file mode 100644 index 000000000..a2a909774 --- /dev/null +++ b/AccessibilityTests/SupportingFiles/AccessibilityTests.xctestplan @@ -0,0 +1,52 @@ +{ + "configurations" : [ + { + "id" : "EFC6A442-D3B7-4273-B349-7A923C06AF5E", + "name" : "Default", + "options" : { + + } + } + ], + "defaultOptions" : { + "addressSanitizer" : { + "enabled" : true + }, + "codeCoverage" : { + "targets" : [ + { + "containerPath" : "container:ElementX.xcodeproj", + "identifier" : "C0FAEB81CFD9776CD78CE489", + "name" : "ElementX" + } + ] + }, + "defaultTestExecutionTimeAllowance" : 120, + "environmentVariableEntries" : [ + + ], + "language" : "en-US", + "locationScenario" : { + "identifier" : "San Francisco, CA, USA", + "referenceType" : "built-in" + }, + "region" : "US", + "targetForVariableExpansion" : { + "containerPath" : "container:ElementX.xcodeproj", + "identifier" : "C0C687DE1D270F9895FEE186", + "name" : "AccessibilityTests" + }, + "testTimeoutsEnabled" : true, + "undefinedBehaviorSanitizerEnabled" : true + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:ElementX.xcodeproj", + "identifier" : "C0C687DE1D270F9895FEE186", + "name" : "AccessibilityTests" + } + } + ], + "version" : 1 +} diff --git a/AccessibilityTests/SupportingFiles/Info.plist b/AccessibilityTests/SupportingFiles/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/AccessibilityTests/SupportingFiles/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/AccessibilityTests/SupportingFiles/target.yml b/AccessibilityTests/SupportingFiles/target.yml new file mode 100644 index 000000000..b80f00867 --- /dev/null +++ b/AccessibilityTests/SupportingFiles/target.yml @@ -0,0 +1,51 @@ +name: AccessibilityTests + +schemes: + AccessibilityTests: + analyze: + config: Debug + archive: + config: Release + build: + targets: + AccessibilityTests: all + profile: + config: Release + run: + config: Debug + disableMainThreadChecker: false + test: + config: Debug + testPlans: + - path: AccessibilityTests.xctestplan + defaultPlan: true + +targets: + AccessibilityTests: + type: bundle.ui-testing + platform: iOS + + dependencies: + - target: ElementX + - package: KZFileWatchers + + info: + path: ../SupportingFiles/Info.plist + + settings: + base: + PRODUCT_NAME: AccessibilityTests + PRODUCT_BUNDLE_IDENTIFIER: ${BASE_BUNDLE_IDENTIFIER}.accessibility.tests + configs: + # This is required to remove the $(inherited) flags + # which would prevent SnapshotTesting to be imported in UI Tests + debug: + OTHER_SWIFT_FLAGS: ["-DDEBUG"] + release: + OTHER_SWIFT_FLAGS: ["-DRELEASE"] + + sources: + - path: ../Sources + - path: ../SupportingFiles + - path: ../../ElementX/Sources/UITests/UITestsSignalling.swift + diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index a09ce1bfc..a656c8d60 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -178,6 +178,7 @@ 1D623953F970D11F6F38499C /* AppLockService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B95BB98649B8E773D6790 /* AppLockService.swift */; }; 1D69E31913DF66426985909B /* EmojiPickerScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */; }; 1DC227816777A2F3A19657E5 /* RoomDirectorySearchScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF71646898A2F720C5BFDF5 /* RoomDirectorySearchScreenViewModel.swift */; }; + 1ECE584D2CFA0FEF0ADE458C /* TestablePreviewsDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA723686F23EF45E2B398FBC /* TestablePreviewsDictionary.swift */; }; 1F3232BD368DF430AB433907 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = 07FEEEDB11543A7DED420F04 /* Compound */; }; 1FE593ECEC40A43789105D80 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */; }; 1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; }; @@ -198,6 +199,7 @@ 237FC70AA257B935F53316BA /* SessionVerificationControllerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D7E514F9DE4E3D72FDCAD /* SessionVerificationControllerProxy.swift */; }; 238D561CA231339C6D4D06F3 /* ClientBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A1C33355FFB0F0953C35036 /* ClientBuilder.swift */; }; 241CDEFE23819867D9B39066 /* RoomChangePermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */; }; + 2435DCCBD4513B9FD053CAC9 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = DD3C65634A34467CB407A061 /* target.yml */; }; 244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DFA1B7B088D033E0794B82 /* RoomChangeRolesScreenCoordinator.swift */; }; 2447FADEF13225BB6227B977 /* VerificationBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D97BAF04AA150C0EF03021 /* VerificationBadge.swift */; }; 24A1BBADAC43DC3F3A7347DA /* AnalyticsPromptScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */; }; @@ -223,6 +225,7 @@ 2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; }; 288408E6151D7BD3EBAA073A /* RoomScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */; }; 28AB1614E749D1147A2AC6C2 /* CreateRoomScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2214C32EA81FA9168D923D4C /* CreateRoomScreenTests.swift */; }; + 28E8C44DD6E39BEB2A1599C8 /* AccessibilityTestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CABD320DE5566D133890B24 /* AccessibilityTestsAppCoordinator.swift */; }; 292827744227DF61C930BDDB /* CreateRoomScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB0D6CB491777E7FC6B5BA12 /* CreateRoomScreen.swift */; }; 29491EE7AE37E239E839C5A3 /* LocationSharingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BEBF0E59F25E842EDB6FD11 /* LocationSharingScreenModels.swift */; }; 2955F4C160CFD7794D819C64 /* EffectsScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F7398C5FC12586FB10E9D /* EffectsScene.swift */; }; @@ -516,7 +519,6 @@ 63DCEBC1DD555E0D645B9E98 /* MapTilerURLBuilderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1033290D99D5BBA1AF3560A /* MapTilerURLBuilderProtocol.swift */; }; 63E46D18B91D08E15FC04125 /* ExpiringTaskRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B25F959A434BB9923A3223F /* ExpiringTaskRunner.swift */; }; 63FD7DBE7BBA149B4B8B99D7 /* TimelineControllerFactoryMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F5CC38803B8382D2C63222 /* TimelineControllerFactoryMock.swift */; }; - 642DF13C49ED4121C148230E /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E227F34BE43B08E098796E /* TestablePreview.swift */; }; 6448F8D1D3CA4CD27BB4CADD /* RoomMemberProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F36C5D9B37E50915ECBD3EE /* RoomMemberProxy.swift */; }; 64AB99285DC4437C0DDE9585 /* MenuSheetLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ABAB186CF00B15C5521D04 /* MenuSheetLabelStyle.swift */; }; 64D05250CEDE8B604119F6E6 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 981663D961C94270FA035FD0 /* Alert.swift */; }; @@ -559,6 +561,7 @@ 6AD722DD92E465E56D2885AB /* BugReportScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */; }; 6AEB650311F694A5702255C9 /* UserProfileScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B4932E4EFBC8FAC10972CD /* UserProfileScreenCoordinator.swift */; }; 6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */; }; + 6B3AB95A6993646A5081BFF9 /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43F773904F87FF5ADFE4DD1 /* TestablePreview.swift */; }; 6B61F5B27412ED4BC2F9769C /* test_audio.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 66B96842BF5F8ACA1AC84C55 /* test_audio.mp3 */; }; 6B80C24A52411EAF10E06E96 /* SecurityAndPrivacyScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBADF8010C813D905C172CE /* SecurityAndPrivacyScreenModels.swift */; }; 6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */; }; @@ -847,6 +850,7 @@ A1672EF491FE6F3BBF7878BE /* test_apple_image.heic in Resources */ = {isa = PBXBuildFile; fileRef = BB576F4118C35E6B5124FA22 /* test_apple_image.heic */; }; A17FAD2EBC53E17B5FD384DB /* InviteUsersScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22730A30C50AC2E3D5BA8642 /* InviteUsersScreenViewModelProtocol.swift */; }; A1BA8D6BABAFA9BAAEAA3FFD /* NotificationSettingsProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDD775CFD72DD2D3C8A8390 /* NotificationSettingsProxyProtocol.swift */; }; + A1C8951A632AC5F350FE0A6C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 932E4E8BB476283CBF219427 /* Test.swift */; }; A1DF0E1E526A981ED6D5DF44 /* UserIndicatorControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */; }; A216C83ADCF32BA5EF8A6FBC /* InviteUsersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */; }; A2172B5A26976F9174228B8A /* AppHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E4AB573FAEBB7B853DD04C /* AppHooks.swift */; }; @@ -888,6 +892,7 @@ A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; }; A87DC550659C5176AC1829DE /* ElementTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7673F2B0B038FAB2A8D16AD /* ElementTextFieldStyle.swift */; }; A8FA7671948E3DF27F320026 /* BugReportFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */; }; + A91D125414C3D9ABBABCF2F1 /* KZFileWatchers in Frameworks */ = {isa = PBXBuildFile; productRef = 6690850AA47ECED7E1CAB345 /* KZFileWatchers */; }; A93661C962B12942C08864B6 /* WysiwygComposer in Frameworks */ = {isa = PBXBuildFile; productRef = CA07D57389DACE18AEB6A5E2 /* WysiwygComposer */; }; A950C95855C474F75B30CA7B /* PollFormScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */; }; A969147E0EEE0E27EE226570 /* MediaUploadPreviewScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F29139BC2A804CE5E0757E /* MediaUploadPreviewScreenViewModel.swift */; }; @@ -1065,6 +1070,7 @@ CDCA8A559E098503DDE29477 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; }; CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */ = {isa = PBXBuildFile; fileRef = D2F7194F440375338F8E2487 /* Untranslated.strings */; }; CE3B7FC34FB2C279AAA5EA01 /* AVMetadataMachineReadableCodeObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3339B1DDB1341E833D2555BC /* AVMetadataMachineReadableCodeObject.swift */; }; + CE4B342F9DD747CF4BEDB5AB /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43F773904F87FF5ADFE4DD1 /* TestablePreview.swift */; }; CE6F237360875D3D573FD0B2 /* RoomNotificationSettingsProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */; }; CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */; }; CEAEA57B7665C8E790599A78 /* BlockedUsersScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 240610DF32F3213BEC5611D7 /* BlockedUsersScreenViewModelTests.swift */; }; @@ -1139,7 +1145,6 @@ DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; }; E0B6A569AC3E81D233B43D60 /* SettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E625B0EB2F86B37C14EF7E6 /* SettingsScreenViewModel.swift */; }; E0C167D41A48EDB30B447DE3 /* VoiceMessageRecordingComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A5C3F7C9C1DA10CAEC6A98 /* VoiceMessageRecordingComposer.swift */; }; - E0FB26262689F04D66A949D7 /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E227F34BE43B08E098796E /* TestablePreview.swift */; }; E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52983FAFB4E0998C00EE8A /* CancellableTask.swift */; }; E184FFAD32342D3D6E2F89AA /* PinnedEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D53754227CEBD06358956D7 /* PinnedEventsTimelineScreenCoordinator.swift */; }; E1A0752244567A25E376A2F4 /* AdvancedSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7A1B80FE6E3BA72F9C748AD /* AdvancedSettingsScreenViewModel.swift */; }; @@ -1153,6 +1158,7 @@ E2DB696117BAEABAD5718023 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49B9785E3AD7D1C15A29F2F /* MediaSourceProxy.swift */; }; E2DDA49BD62F03F180A42E30 /* MapLibreStaticMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */; }; E313BDD2B8813144139B2E00 /* UserDiscoveryServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0287793F11C480E242B03DF5 /* UserDiscoveryServiceTest.swift */; }; + E323A54F317604BDD6968D79 /* UITestsSignalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */; }; E3291AD16D7A5CB14781819C /* UserNotificationCenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */; }; E32A18802EB37EEE3EF7B965 /* GlobalSearchScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B788615712FED326F73D3F83 /* GlobalSearchScreenViewModelProtocol.swift */; }; E362924A42934C9F0F97A956 /* OIDCConfigurationProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69869844D2B6F5BD9AABF85 /* OIDCConfigurationProxy.swift */; }; @@ -1275,6 +1281,7 @@ F8F47CE757EE656905F01F2C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90DFF217B3D9D0941283278C /* RoomRolesAndPermissionsScreenViewModelProtocol.swift */; }; F9788AE0B9EA19F1190ED14F /* StartChatScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B927A399A5418DA40A5CA15 /* StartChatScreenTests.swift */; }; F9842667B68DC6FA1F9ECCBB /* NSItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72EFC8C634469F9262659C7 /* NSItemProvider.swift */; }; + F996259EAE68664BC345C197 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9DBE1C69F3A60D93B2203F /* Application.swift */; }; F99FB21EFC6D99D247FE7CBE /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DE8DC9B3FBA402117DC4C49F /* Kingfisher */; }; F9EA79092C18A8CFE4922DD2 /* PollFormScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F64A8582F65567AC38C2976A /* PollFormScreenViewModel.swift */; }; FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */; }; @@ -1311,6 +1318,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 1CE0B5D9ECEB44A4A32285B4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = AC22997D58D612146053154D /* Project object */; + proxyType = 1; + remoteGlobalIDString = C0FAEB81CFD9776CD78CE489; + remoteInfo = ElementX; + }; 4448BD77D7203616C4FAD26A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AC22997D58D612146053154D /* Project object */; @@ -1567,6 +1581,7 @@ 227AC5D71A4CE43512062243 /* URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URL.swift; sourceTree = ""; }; 22DB19219E6CC4D002E15D48 /* GlobalSearchScreenCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenCell.swift; sourceTree = ""; }; 2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProvider.swift; sourceTree = ""; }; + 2363DB6162BBCC511B67B527 /* AccessibilityTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = AccessibilityTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 23674BF78CE814366EBD8762 /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/InfoPlist.strings; sourceTree = ""; }; 2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenCoordinator.swift; sourceTree = ""; }; 23E6EB7960BC9D0F7396B3BD /* RoomChangeRolesScreenRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenRow.swift; sourceTree = ""; }; @@ -1628,6 +1643,7 @@ 2D0946F77B696176E062D037 /* RoomMembersListScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenModels.swift; sourceTree = ""; }; 2D505843AB66822EB91F0DF0 /* TimelineItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemProxy.swift; sourceTree = ""; }; 2D7A2C4A3A74F0D2FFE9356A /* MediaPlayerProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerProviderTests.swift; sourceTree = ""; }; + 2D9DBE1C69F3A60D93B2203F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; 2DA3DBE1A42EAFF93889FA04 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/SAS.strings; sourceTree = ""; }; 2DA4F09CB613C54FDC73AE6A /* ThreadDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDecorator.swift; sourceTree = ""; }; 2DB0E533508094156D8024C3 /* TimelineStyler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyler.swift; sourceTree = ""; }; @@ -1662,6 +1678,7 @@ 34E0FA38BD473FFA6F1AB7A5 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = be; path = be.lproj/Localizable.stringsdict; sourceTree = ""; }; 34ED3AB7E0287552A5648AB3 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = ""; }; 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = ""; }; + 35A057BA9BE0F079784CD061 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = ""; }; 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; @@ -1849,6 +1866,7 @@ 5B8F0ED874DF8C9A51B0AB6F /* SettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenCoordinator.swift; sourceTree = ""; }; 5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewViewModelTests.swift; sourceTree = ""; }; 5C7C7CFA6B2A62A685FF6CE3 /* DeveloperOptionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenCoordinator.swift; sourceTree = ""; }; + 5CABD320DE5566D133890B24 /* AccessibilityTestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityTestsAppCoordinator.swift; sourceTree = ""; }; 5CDE60FEE95039CCCEEEE3B0 /* TimelineMediaPreviewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewController.swift; sourceTree = ""; }; 5CEEAE1BFAACD6C96B6DB731 /* PHGPostHogProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogProtocol.swift; sourceTree = ""; }; 5D26A086A8278D39B5756D6F /* project.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = project.yml; sourceTree = ""; }; @@ -2106,6 +2124,7 @@ 922E498EB74CF6F5CC236F81 /* AdvancedSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenModels.swift; sourceTree = ""; }; 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAuthenticationPresenter.swift; sourceTree = ""; }; 92DB574F954CC2B40F7BE892 /* QRCodeScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeScannerView.swift; sourceTree = ""; }; + 932E4E8BB476283CBF219427 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 9332DFE9642F0A46ECA0497B /* BlurHashEncode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; 933B074F006F8E930DB98B4E /* TimelineMediaFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaFrame.swift; sourceTree = ""; }; 9342F5D6729627B6393AF853 /* ServerConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenModels.swift; sourceTree = ""; }; @@ -2222,6 +2241,7 @@ AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationAnnotation.swift; sourceTree = ""; }; AB07F03461023BC39C730922 /* PhishingDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingDetector.swift; sourceTree = ""; }; AB26D5444A4A7E095222DE8B /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.stringsdict"; sourceTree = ""; }; + AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */ = {isa = PBXFileReference; path = AccessibilityTests.xctestplan; sourceTree = ""; }; ABA4CF2F5B4F68D02E412004 /* ServerConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenViewModelProtocol.swift; sourceTree = ""; }; AC0275CEE9CA078B34028BDF /* AppLockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockScreenViewModelTests.swift; sourceTree = ""; }; AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockImageCache.swift; sourceTree = ""; }; @@ -2266,7 +2286,6 @@ B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineItem.swift; sourceTree = ""; }; B172057567E049007A5C4D92 /* Strings+SAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+SAS.swift"; sourceTree = ""; }; B18A454132A5A5247802821E /* TimelineMediaPreviewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDataSource.swift; sourceTree = ""; }; - B1E227F34BE43B08E098796E /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = ""; }; B1FDB0B87D925AE830E32621 /* ReportRoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportRoomScreenViewModel.swift; sourceTree = ""; }; B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; B2AD8A56CD37E23071A2F4BF /* PHGPostHogMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogMock.swift; sourceTree = ""; }; @@ -2482,6 +2501,7 @@ DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = ""; }; DCDAB580109C09A6AA97AF7E /* PollFormScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenTests.swift; sourceTree = ""; }; DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = ""; }; + DD3C65634A34467CB407A061 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; DD955A0380C287C418F1A74D /* PhotoLibraryManagerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLibraryManagerMock.swift; sourceTree = ""; }; DD97F9661ABF08CE002054A2 /* AppLockServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceTests.swift; sourceTree = ""; }; DE5127D6EA05B2E45D0A7D59 /* JoinRoomScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenViewModelTests.swift; sourceTree = ""; }; @@ -2514,6 +2534,7 @@ E4103AB4340F2974D690A12A /* CallScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreen.swift; sourceTree = ""; }; E413F4CBD7BF0588F394A9DD /* RoomDetailsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModel.swift; sourceTree = ""; }; E43005941B3A2C9671E23C85 /* UserIndicatorModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorModalView.swift; sourceTree = ""; }; + E43F773904F87FF5ADFE4DD1 /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = ""; }; E44E35AA87F49503E7B3BF6E /* AudioConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioConverter.swift; sourceTree = ""; }; E45EBAFF1A83538D54ABDF92 /* ServerSelectionScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModelTests.swift; sourceTree = ""; }; E461B3C8BBBFCA400B268D14 /* AppRouteURLParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteURLParserTests.swift; sourceTree = ""; }; @@ -2617,6 +2638,7 @@ F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreen.swift; sourceTree = ""; }; F9E543072DE58E751F028998 /* TimelineProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxy.swift; sourceTree = ""; }; FA3EB5B1848CF4F64E63C6B7 /* PermalinkTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermalinkTests.swift; sourceTree = ""; }; + FA723686F23EF45E2B398FBC /* TestablePreviewsDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreviewsDictionary.swift; sourceTree = ""; }; FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModelProtocol.swift; sourceTree = ""; }; FABAC5C4373B0EC24D399663 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/SAS.strings"; sourceTree = ""; }; FB0D6CB491777E7FC6B5BA12 /* CreateRoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreen.swift; sourceTree = ""; }; @@ -2721,6 +2743,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EE2DAC14F8157479693D2705 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A91D125414C3D9ABBABCF2F1 /* KZFileWatchers in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EE878EAA342710DB973E0A87 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -3445,6 +3475,15 @@ path = View; sourceTree = ""; }; + 35784B4A763838C0324B324A /* TestablePreview */ = { + isa = PBXGroup; + children = ( + E43F773904F87FF5ADFE4DD1 /* TestablePreview.swift */, + FA723686F23EF45E2B398FBC /* TestablePreviewsDictionary.swift */, + ); + path = TestablePreview; + sourceTree = ""; + }; 358B1920EA0C8129198FBA4F /* View */ = { isa = PBXGroup; children = ( @@ -3621,6 +3660,7 @@ A4852B57D55D71EEBFCD931D /* UnitTests */, 1803CD2B96BF06009334BB61 /* PreviewTests */, C0FAC17D4DD7D3A502822550 /* UITests */, + D7117C32909844BCF5AF30BA /* AccessibilityTests */, 8A9C09B6A392465E03B8D1B1 /* IntegrationTests */, A8002CB4F20B6282850A614C /* DevelopmentAssets */, 2197234282B4BC0CE79AAC74 /* Secrets */, @@ -4141,6 +4181,16 @@ path = SecureBackupLogoutConfirmationScreen; sourceTree = ""; }; + 63FCFB02914E796299B25213 /* SupportingFiles */ = { + isa = PBXGroup; + children = ( + AB389C38BD41EB3E47092CFB /* AccessibilityTests.xctestplan */, + 35A057BA9BE0F079784CD061 /* Info.plist */, + DD3C65634A34467CB407A061 /* target.yml */, + ); + path = SupportingFiles; + sourceTree = ""; + }; 6709362D60732DED2069AE0F /* MediaPlayer */ = { isa = PBXGroup; children = ( @@ -4184,6 +4234,7 @@ 681566846AF307E9BA4C72C6 /* Products */ = { isa = PBXGroup; children = ( + 2363DB6162BBCC511B67B527 /* AccessibilityTests.xctest */, 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */, 9C7F7DE62D33C6A26CBFCD72 /* IntegrationTests.xctest */, 0D8F620C8B314840D8602E3F /* NSE.appex */, @@ -4540,6 +4591,14 @@ path = View; sourceTree = ""; }; + 79654D131C1B234A7D034532 /* AccessibilityTests */ = { + isa = PBXGroup; + children = ( + 5CABD320DE5566D133890B24 /* AccessibilityTestsAppCoordinator.swift */, + ); + path = AccessibilityTests; + sourceTree = ""; + }; 79E560F5113ED25D172E550C /* Media */ = { isa = PBXGroup; children = ( @@ -5442,7 +5501,6 @@ 53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */, FE5CD2993048222B64C45006 /* SDKListener.swift */, 4481799F455B3DA243BDA2AC /* ShareToMapsAppActivity.swift */, - B1E227F34BE43B08E098796E /* TestablePreview.swift */, 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */, 35FA991289149D31F4286747 /* UserPreference.swift */, 7431C962E314ADAE38B6D708 /* Analytics */, @@ -5456,6 +5514,7 @@ 9C4193C4524B35FD6B94B5A9 /* Pills */, 25852CD5316875417111E5CA /* Progress */, 052CC920F473C10B509F9FC1 /* SwiftUI */, + 35784B4A763838C0324B324A /* TestablePreview */, B687E3E8C23415A06A3D5C65 /* UserIndicator */, A33CE1B72A29E3931CBEC2A5 /* VoiceMessage */, ); @@ -5701,6 +5760,15 @@ path = RoomPollsHistoryScreen; sourceTree = ""; }; + D7117C32909844BCF5AF30BA /* AccessibilityTests */ = { + isa = PBXGroup; + children = ( + EB9C851423AA9BC8CEC381DC /* Sources */, + 63FCFB02914E796299B25213 /* SupportingFiles */, + ); + path = AccessibilityTests; + sourceTree = ""; + }; D8388454B5909D862CAC78F7 /* RoomChangeRolesScreen */ = { isa = PBXGroup; children = ( @@ -5908,6 +5976,7 @@ E59565F441830B19DBAE567C /* Screens */, C0937E3B06A8F0E2DB7C8241 /* Other */, 2ECFF6B05DAA37EB10DBF7E8 /* UITests */, + 79654D131C1B234A7D034532 /* AccessibilityTests */, 22F9F1514B91803BB4B88894 /* AppHooks */, 337015ADFBA3AB96660DB3A6 /* Generated */, 31CE4DA53232AA534057F912 /* Mocks */, @@ -5980,6 +6049,15 @@ path = AccountSettings; sourceTree = ""; }; + EB9C851423AA9BC8CEC381DC /* Sources */ = { + isa = PBXGroup; + children = ( + 2D9DBE1C69F3A60D93B2203F /* Application.swift */, + 932E4E8BB476283CBF219427 /* Test.swift */, + ); + path = Sources; + sourceTree = ""; + }; EC4545C7E37E8294D3FE6800 /* StartChatScreen */ = { isa = PBXGroup; children = ( @@ -6291,6 +6369,27 @@ productReference = D95E8C0EFEC0C6F96EDAA71A /* PreviewTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + C0C687DE1D270F9895FEE186 /* AccessibilityTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8FFA8C81E8F740B7AC0183EC /* Build configuration list for PBXNativeTarget "AccessibilityTests" */; + buildPhases = ( + 94540A814D43C5F35B910D5E /* Sources */, + E8235B7CF8A765A03DC263A1 /* Resources */, + EE2DAC14F8157479693D2705 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 856923B8570E40A97E26EEDE /* PBXTargetDependency */, + ); + name = AccessibilityTests; + packageProductDependencies = ( + 6690850AA47ECED7E1CAB345 /* KZFileWatchers */, + ); + productName = AccessibilityTests; + productReference = 2363DB6162BBCC511B67B527 /* AccessibilityTests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; C0FAEB81CFD9776CD78CE489 /* ElementX */ = { isa = PBXNativeTarget; buildConfigurationList = B15427F8699AD5A5FC75C17E /* Build configuration list for PBXNativeTarget "ElementX" */; @@ -6298,6 +6397,7 @@ A7130911BCB2DF3D249A1836 /* 🛠 SwiftGen */, 7F26850DA7BC749F6FC41586 /* 🧙 Sourcery - Generate mocks */, 024F73AD10ACB163505ABE1E /* 🧙 Sourcery - Generate preview tests */, + B48A38232A774CE14E6CAFC9 /* 🧙 Sourcery - Generate Accessibility Tests */, 9797D588420FCBBC228A63C9 /* Sources */, 215E1D91B98672C856F559D0 /* Resources */, EE878EAA342710DB973E0A87 /* Frameworks */, @@ -6423,6 +6523,10 @@ 7A17BE29BAC81ADBAC6349D9 = { DevelopmentTeam = 7J4U792NQT; }; + C0C687DE1D270F9895FEE186 = { + DevelopmentTeam = 7J4U792NQT; + TestTargetID = C0FAEB81CFD9776CD78CE489; + }; C0FAEB81CFD9776CD78CE489 = { DevelopmentTeam = "$(DEVELOPMENT_TEAM)"; }; @@ -6513,6 +6617,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( + C0C687DE1D270F9895FEE186 /* AccessibilityTests */, C0FAEB81CFD9776CD78CE489 /* ElementX */, D3DB351B7FBE0F49649171FC /* IntegrationTests */, FEB53A5BC378C913769656D8 /* NSE */, @@ -6624,6 +6729,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E8235B7CF8A765A03DC263A1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2435DCCBD4513B9FD053CAC9 /* target.yml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -6741,6 +6854,25 @@ shellPath = /bin/sh; shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftformat >/dev/null; then\n swiftformat --lint --lenient \"$PROJECT_DIR\"\nelse\n echo \"warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat\"\nfi\n"; }; + B48A38232A774CE14E6CAFC9 /* 🧙 Sourcery - Generate Accessibility Tests */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "🧙 Sourcery - Generate Accessibility Tests"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which sourcery >/dev/null; then\n sourcery --config Tools/Sourcery/TestablePreviewsDictionary.yml\nelse\n echo \"warning: Sourcery not installed, run swift run tools setup-project\"\nfi\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -6805,7 +6937,7 @@ 6EC7A40A537CFB3D526A111C /* Strings.swift in Sources */, 88A3FBBC3D67996863DB9CAF /* TargetConfiguration.swift in Sources */, 719E7AAD1F8E68F68F30FECD /* Task.swift in Sources */, - E0FB26262689F04D66A949D7 /* TestablePreview.swift in Sources */, + CE4B342F9DD747CF4BEDB5AB /* TestablePreview.swift in Sources */, AC3C3D6D4AD31F13EE987390 /* TraceLogPack.swift in Sources */, B81840E45D8746A4692DA774 /* Tracing.swift in Sources */, DDB47D29C6865669288BF87C /* UIFont+AttributedStringBuilder.m in Sources */, @@ -6990,6 +7122,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94540A814D43C5F35B910D5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F996259EAE68664BC345C197 /* Application.swift in Sources */, + A1C8951A632AC5F350FE0A6C /* Test.swift in Sources */, + E323A54F317604BDD6968D79 /* UITestsSignalling.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9797D588420FCBBC228A63C9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -6997,6 +7139,7 @@ 41F553349AF44567184822D8 /* APNSPayload.swift in Sources */, CE3B7FC34FB2C279AAA5EA01 /* AVMetadataMachineReadableCodeObject.swift in Sources */, 70394ECD2DCC70741538620D /* AccessibilityIdentifiers.swift in Sources */, + 28E8C44DD6E39BEB2A1599C8 /* AccessibilityTestsAppCoordinator.swift in Sources */, 09E1A358EA4205480AEF4698 /* AdvancedSettingsScreen.swift in Sources */, 34ADC506C929D10B138EBA51 /* AdvancedSettingsScreenCoordinator.swift in Sources */, 2BEDEA4851E1DF901779362C /* AdvancedSettingsScreenModels.swift in Sources */, @@ -7766,7 +7909,8 @@ CCBEC2100CAF2EEBE9DB4156 /* TemplateScreenModels.swift in Sources */, 275EDE8849A2AC1D9309ED7C /* TemplateScreenViewModel.swift in Sources */, 2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */, - 642DF13C49ED4121C148230E /* TestablePreview.swift in Sources */, + 6B3AB95A6993646A5081BFF9 /* TestablePreview.swift in Sources */, + 1ECE584D2CFA0FEF0ADE458C /* TestablePreviewsDictionary.swift in Sources */, 887AC93C523AEFB640EA5EC8 /* TextBasedRoomTimelineItem.swift in Sources */, 4FE688FE9375B2FBF424146A /* TextBasedRoomTimelineViewProtocol.swift in Sources */, BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */, @@ -7991,6 +8135,11 @@ target = 19F0C845D67E9BEA4BE7133E /* ShareExtension */; targetProxy = 52A426E590105174D83B9532 /* PBXContainerItemProxy */; }; + 856923B8570E40A97E26EEDE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C0FAEB81CFD9776CD78CE489 /* ElementX */; + targetProxy = 1CE0B5D9ECEB44A4A32285B4 /* PBXContainerItemProxy */; + }; 8E24DC048A099AAFEE13B4F5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = C0FAEB81CFD9776CD78CE489 /* ElementX */; @@ -8166,6 +8315,48 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 2F9917BC52CB6F9FFACE9D64 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = AccessibilityTests/SupportingFiles/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = ( + "-DRELEASE", + ); + PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; + PRODUCT_NAME = AccessibilityTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = ElementX; + }; + name = Release; + }; + 33096BC465A038B6B6D76B7A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = AccessibilityTests/SupportingFiles/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = ( + "-DDEBUG", + ); + PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.accessibility.tests"; + PRODUCT_NAME = AccessibilityTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = ElementX; + }; + name = Debug; + }; 4CB921EC997F763064B8E436 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -8644,6 +8835,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + 8FFA8C81E8F740B7AC0183EC /* Build configuration list for PBXNativeTarget "AccessibilityTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33096BC465A038B6B6D76B7A /* Debug */, + 2F9917BC52CB6F9FFACE9D64 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; A60414DDC2A95B206C91D4A4 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -9058,6 +9258,11 @@ package = 6FC4820D8D4559CEECA064D7 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */; productName = MatrixRustSDK; }; + 6690850AA47ECED7E1CAB345 /* KZFileWatchers */ = { + isa = XCSwiftPackageProductDependency; + package = 395DE6AE429B7ACC7C7FE31D /* XCRemoteSwiftPackageReference "KZFileWatchers" */; + productName = KZFileWatchers; + }; 67E7A6F388D3BF85767609D9 /* Sentry */ = { isa = XCSwiftPackageProductDependency; package = A08925A9D5E3770DEB9D8509 /* XCRemoteSwiftPackageReference "sentry-cocoa" */; diff --git a/ElementX.xcodeproj/xcshareddata/xcschemes/AccessibilityTests.xcscheme b/ElementX.xcodeproj/xcshareddata/xcschemes/AccessibilityTests.xcscheme new file mode 100644 index 000000000..3f2e7e6f2 --- /dev/null +++ b/ElementX.xcodeproj/xcshareddata/xcschemes/AccessibilityTests.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift b/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift new file mode 100644 index 000000000..3f0dd0c4e --- /dev/null +++ b/ElementX/Sources/AccessibilityTests/AccessibilityTestsAppCoordinator.swift @@ -0,0 +1,155 @@ +// +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import Combine +import SwiftUI + +class AccessibilityTestsAppCoordinator: AppCoordinatorProtocol { + var windowManager: any SecureWindowManagerProtocol + + func handleDeepLink(_ url: URL, isExternalURL: Bool) -> Bool { + fatalError("Not implemented") + } + + func handlePotentialPhishingAttempt(url: URL, openURLAction: @escaping (URL) -> Void) -> Bool { + fatalError("Not implemented") + } + + func handleUserActivity(_ userActivity: NSUserActivity) { + fatalError("Not implemented") + } + + private let previewsWrapper: PreviewsWrapper + + private var cancellables = Set() + + init(appDelegate: AppDelegate) { + windowManager = WindowManager(appDelegate: appDelegate) + // disabling View animations + UIView.setAnimationsEnabled(false) + + MXLog.configure(currentTarget: "accessibility-tests") + + ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) + + AppSettings.configureWithSuiteName("io.element.elementx.accessibilitytests") + AppSettings.resetAllSettings() + ServiceLocator.shared.register(appSettings: AppSettings()) + ServiceLocator.shared.register(bugReportService: BugReportServiceMock(.init())) + + let analyticsClient = AnalyticsClientMock() + analyticsClient.isRunning = false + ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient, + appSettings: ServiceLocator.shared.settings)) + + guard let name = ProcessInfo.accessibilityViewID, + let previewType = TestablePreviewsDictionary.dictionary[name] else { + fatalError("Unable to launch with unknown screen.") + } + previewsWrapper = .init(name: name, previews: previewType._allPreviews) + + setupSignalling() + } + + func toPresentable() -> AnyView { + AnyView(PreviewsWrapperView(wrapper: previewsWrapper)) + } + + private func setupSignalling() { + do { + let client = try UITestsSignalling.Client(mode: .app) + client.signals.sink { [weak self] signal in + guard let self else { return } + switch signal { + case .accessibilityAudit(let auditSignal): + switch auditSignal { + case .nextPreview: + Task { [weak self] in + guard let self else { return } + await previewsWrapper.updateCurrentIndex() + do { + guard !previewsWrapper.isDone else { + try client.send(.accessibilityAudit(.noMorePreviews)) + return + } + + try client.send(.accessibilityAudit(.nextPreviewReady(name: previewsWrapper.previewName))) + } catch { + fatalError("Failed sending signal: \(signal)") + } + } + default: + break + } + default: + break + } + } + .store(in: &cancellables) + } catch { + fatalError("Unable to start client signalling") + } + } +} + +struct PreviewsWrapperView: View { + let wrapper: PreviewsWrapper + + var body: some View { + if wrapper.currentIndex < 0 || wrapper.isDone { + EmptyView() + } else { + wrapper.currentPreview.content + .id(wrapper.previewName) + } + } +} + +@Observable final class PreviewsWrapper { + private let name: String + private let previews: [_Preview] + private(set) var currentIndex = -1 + var currentPreview: _Preview { previews[currentIndex] } + + private(set) var isDone = false + + var previewName: String { + "\(name)-\(currentPreview.displayName ?? String(currentIndex))" + } + + init(name: String, previews: [_Preview]) { + self.name = name + self.previews = previews + } + + @MainActor + func updateCurrentIndex() async { + let newIndex = currentIndex + 1 + guard newIndex < previews.count else { + isDone = true + return + } + let newPreview = previews[newIndex] + var fulfillmentSource: SnapshotFulfillmentPreferenceKey.Source? + let preferenceReadingView = newPreview.content.onPreferenceChange(SnapshotFulfillmentPreferenceKey.self) { fulfillmentSource = $0?.source } + + // Render an image of the view in order to trigger the preference updates to occur. + let imageRenderer = ImageRenderer(content: preferenceReadingView) + _ = imageRenderer.uiImage + + switch fulfillmentSource { + case .publisher(let publisher): + _ = await publisher.values.first { $0 == true } + case .stream(let stream): + _ = await stream.first { $0 == true } + case .none: + break + } + + currentIndex = newIndex + } +} diff --git a/ElementX/Sources/Application/Application.swift b/ElementX/Sources/Application/Application.swift index 4ebf94f36..48fba3d74 100644 --- a/ElementX/Sources/Application/Application.swift +++ b/ElementX/Sources/Application/Application.swift @@ -19,6 +19,8 @@ struct Application: App { appCoordinator = UITestsAppCoordinator(appDelegate: appDelegate) } else if ProcessInfo.isRunningUnitTests { appCoordinator = UnitTestsAppCoordinator(appDelegate: appDelegate) + } else if ProcessInfo.isRunningAccessibilityTests { + appCoordinator = AccessibilityTestsAppCoordinator(appDelegate: appDelegate) } else { appCoordinator = AppCoordinator(appDelegate: appDelegate) } diff --git a/ElementX/Sources/Other/Extensions/ProcessInfo.swift b/ElementX/Sources/Other/Extensions/ProcessInfo.swift index 6990c3548..c90164df9 100644 --- a/ElementX/Sources/Other/Extensions/ProcessInfo.swift +++ b/ElementX/Sources/Other/Extensions/ProcessInfo.swift @@ -33,10 +33,18 @@ extension ProcessInfo { false #endif } + + static var isRunningAccessibilityTests: Bool { + #if DEBUG + processInfo.environment["ACCESSIBILITY_VIEW"] != nil + #else + false + #endif + } /// Flag indicating whether the app is running the UI tests or unit tests. static var isRunningTests: Bool { - isRunningUITests || isRunningUnitTests || isRunningIntegrationTests + isRunningUITests || isRunningUnitTests || isRunningIntegrationTests || isRunningAccessibilityTests } /// The identifier of the screen to be loaded when running UI tests. @@ -48,6 +56,15 @@ extension ProcessInfo { #endif } + /// The identifier of the preview that will be accessibility tested + static var accessibilityViewID: String? { + #if DEBUG + processInfo.environment["ACCESSIBILITY_VIEW"] + #else + nil + #endif + } + static var shouldDisableTimelineAccessibility: Bool { guard isRunningUITests else { return false diff --git a/ElementX/Sources/Other/TestablePreview.swift b/ElementX/Sources/Other/TestablePreview/TestablePreview.swift similarity index 100% rename from ElementX/Sources/Other/TestablePreview.swift rename to ElementX/Sources/Other/TestablePreview/TestablePreview.swift diff --git a/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift b/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift new file mode 100644 index 000000000..4e58b869e --- /dev/null +++ b/ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift @@ -0,0 +1,205 @@ +// Generated using Sourcery 2.2.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +// swiftlint:disable all +// swiftformat:disable all + +import SwiftUI + + +enum TestablePreviewsDictionary { + static let dictionary: [String: any PreviewProvider.Type] = [ + "AdvancedSettingsScreen_Previews" : AdvancedSettingsScreen_Previews.self, + "AnalyticsPromptScreen_Previews" : AnalyticsPromptScreen_Previews.self, + "AnalyticsSettingsScreen_Previews" : AnalyticsSettingsScreen_Previews.self, + "AppLockScreen_Previews" : AppLockScreen_Previews.self, + "AppLockSetupBiometricsScreen_Previews" : AppLockSetupBiometricsScreen_Previews.self, + "AppLockSetupPINScreen_Previews" : AppLockSetupPINScreen_Previews.self, + "AppLockSetupSettingsScreen_Previews" : AppLockSetupSettingsScreen_Previews.self, + "AudioMediaEventsTimelineView_Previews" : AudioMediaEventsTimelineView_Previews.self, + "AudioRoomTimelineView_Previews" : AudioRoomTimelineView_Previews.self, + "AuthenticationStartScreen_Previews" : AuthenticationStartScreen_Previews.self, + "AvatarHeaderView_Previews" : AvatarHeaderView_Previews.self, + "BadgeLabel_Previews" : BadgeLabel_Previews.self, + "BigIcon_Previews" : BigIcon_Previews.self, + "BlockedUsersScreen_Previews" : BlockedUsersScreen_Previews.self, + "BugReportScreen_Previews" : BugReportScreen_Previews.self, + "CallInviteRoomTimelineView_Previews" : CallInviteRoomTimelineView_Previews.self, + "CallNotificationRoomTimelineView_Previews" : CallNotificationRoomTimelineView_Previews.self, + "CollapsibleRoomTimelineView_Previews" : CollapsibleRoomTimelineView_Previews.self, + "CompletionSuggestion_Previews" : CompletionSuggestion_Previews.self, + "ComposerToolbar_Previews" : ComposerToolbar_Previews.self, + "CreateRoom_Previews" : CreateRoom_Previews.self, + "DeactivateAccountScreen_Previews" : DeactivateAccountScreen_Previews.self, + "DeclineAndBlockScreen_Previews" : DeclineAndBlockScreen_Previews.self, + "EditRoomAddressScreen_Previews" : EditRoomAddressScreen_Previews.self, + "ElementTextFieldStyle_Previews" : ElementTextFieldStyle_Previews.self, + "EmojiPickerScreenHeaderView_Previews" : EmojiPickerScreenHeaderView_Previews.self, + "EmojiPickerScreen_Previews" : EmojiPickerScreen_Previews.self, + "EmoteRoomTimelineView_Previews" : EmoteRoomTimelineView_Previews.self, + "EncryptedRoomTimelineView_Previews" : EncryptedRoomTimelineView_Previews.self, + "EncryptionResetPasswordScreen_Previews" : EncryptionResetPasswordScreen_Previews.self, + "EncryptionResetScreen_Previews" : EncryptionResetScreen_Previews.self, + "EstimatedWaveformView_Previews" : EstimatedWaveformView_Previews.self, + "FileMediaEventsTimelineView_Previews" : FileMediaEventsTimelineView_Previews.self, + "FileRoomTimelineView_Previews" : FileRoomTimelineView_Previews.self, + "FormButtonStyles_Previews" : FormButtonStyles_Previews.self, + "FormattedBodyText_Previews" : FormattedBodyText_Previews.self, + "FormattingToolbar_Previews" : FormattingToolbar_Previews.self, + "FullscreenDialog_Previews" : FullscreenDialog_Previews.self, + "GlobalSearchScreenListRow_Previews" : GlobalSearchScreenListRow_Previews.self, + "GlobalSearchScreen_Previews" : GlobalSearchScreen_Previews.self, + "HighlightedTimelineItemModifier_Previews" : HighlightedTimelineItemModifier_Previews.self, + "HomeScreenEmptyStateView_Previews" : HomeScreenEmptyStateView_Previews.self, + "HomeScreenInviteCell_Previews" : HomeScreenInviteCell_Previews.self, + "HomeScreenKnockedCell_Previews" : HomeScreenKnockedCell_Previews.self, + "HomeScreenRecoveryKeyConfirmationBanner_Previews" : HomeScreenRecoveryKeyConfirmationBanner_Previews.self, + "HomeScreenRoomCell_Previews" : HomeScreenRoomCell_Previews.self, + "HomeScreen_Previews" : HomeScreen_Previews.self, + "IdentityConfirmationScreen_Previews" : IdentityConfirmationScreen_Previews.self, + "IdentityConfirmedScreen_Previews" : IdentityConfirmedScreen_Previews.self, + "ImageMediaEventsTimelineView_Previews" : ImageMediaEventsTimelineView_Previews.self, + "ImageRoomTimelineView_Previews" : ImageRoomTimelineView_Previews.self, + "InviteUsersScreenSelectedItem_Previews" : InviteUsersScreenSelectedItem_Previews.self, + "InviteUsersScreen_Previews" : InviteUsersScreen_Previews.self, + "JoinRoomByAddressView_Previews" : JoinRoomByAddressView_Previews.self, + "JoinRoomScreen_Previews" : JoinRoomScreen_Previews.self, + "KnockRequestCell_Previews" : KnockRequestCell_Previews.self, + "KnockRequestsBannerView_Previews" : KnockRequestsBannerView_Previews.self, + "KnockRequestsListEmptyStateView_Previews" : KnockRequestsListEmptyStateView_Previews.self, + "KnockRequestsListScreen_Previews" : KnockRequestsListScreen_Previews.self, + "LegalInformationScreen_Previews" : LegalInformationScreen_Previews.self, + "LoadableImage_Previews" : LoadableImage_Previews.self, + "LocationMarkerView_Previews" : LocationMarkerView_Previews.self, + "LocationRoomTimelineView_Previews" : LocationRoomTimelineView_Previews.self, + "LoginScreen_Previews" : LoginScreen_Previews.self, + "LongPressWithFeedback_Previews" : LongPressWithFeedback_Previews.self, + "ManageRoomMemberSheetView_Previews" : ManageRoomMemberSheetView_Previews.self, + "MapLibreStaticMapView_Previews" : MapLibreStaticMapView_Previews.self, + "MatrixUserPermalink_Previews" : MatrixUserPermalink_Previews.self, + "MediaEventsTimelineScreen_Previews" : MediaEventsTimelineScreen_Previews.self, + "MediaUploadPreviewScreen_Previews" : MediaUploadPreviewScreen_Previews.self, + "MentionSuggestionItemView_Previews" : MentionSuggestionItemView_Previews.self, + "MessageComposerTextField_Previews" : MessageComposerTextField_Previews.self, + "MessageComposer_Previews" : MessageComposer_Previews.self, + "MessageForwardingScreen_Previews" : MessageForwardingScreen_Previews.self, + "MessageText_Previews" : MessageText_Previews.self, + "NoticeRoomTimelineView_Previews" : NoticeRoomTimelineView_Previews.self, + "NotificationPermissionsScreen_Previews" : NotificationPermissionsScreen_Previews.self, + "NotificationSettingsEditScreenRoomCell_Previews" : NotificationSettingsEditScreenRoomCell_Previews.self, + "NotificationSettingsEditScreen_Previews" : NotificationSettingsEditScreen_Previews.self, + "NotificationSettingsScreen_Previews" : NotificationSettingsScreen_Previews.self, + "PINTextField_Previews" : PINTextField_Previews.self, + "PaginationIndicatorRoomTimelineView_Previews" : PaginationIndicatorRoomTimelineView_Previews.self, + "PillViewOnBubble_Previews" : PillViewOnBubble_Previews.self, + "PillView_Previews" : PillView_Previews.self, + "PinnedEventsTimelineScreen_Previews" : PinnedEventsTimelineScreen_Previews.self, + "PinnedItemsBannerView_Previews" : PinnedItemsBannerView_Previews.self, + "PinnedItemsIndicatorView_Previews" : PinnedItemsIndicatorView_Previews.self, + "PlaceholderAvatarImage_Previews" : PlaceholderAvatarImage_Previews.self, + "PlaceholderScreen_Previews" : PlaceholderScreen_Previews.self, + "PollFormScreen_Previews" : PollFormScreen_Previews.self, + "PollOptionView_Previews" : PollOptionView_Previews.self, + "PollRoomTimelineView_Previews" : PollRoomTimelineView_Previews.self, + "PollView_Previews" : PollView_Previews.self, + "QRCodeLoginScreen_Previews" : QRCodeLoginScreen_Previews.self, + "ReactionsSummaryView_Previews" : ReactionsSummaryView_Previews.self, + "ReadMarkerRoomTimelineView_Previews" : ReadMarkerRoomTimelineView_Previews.self, + "ReadReceiptCell_Previews" : ReadReceiptCell_Previews.self, + "ReadReceiptsSummaryView_Previews" : ReadReceiptsSummaryView_Previews.self, + "RedactedRoomTimelineView_Previews" : RedactedRoomTimelineView_Previews.self, + "ReportContentScreen_Previews" : ReportContentScreen_Previews.self, + "ReportRoomScreen_Previews" : ReportRoomScreen_Previews.self, + "ResolveVerifiedUserSendFailureScreen_Previews" : ResolveVerifiedUserSendFailureScreen_Previews.self, + "RoomAttachmentPicker_Previews" : RoomAttachmentPicker_Previews.self, + "RoomAvatarImage_Previews" : RoomAvatarImage_Previews.self, + "RoomChangePermissionsScreen_Previews" : RoomChangePermissionsScreen_Previews.self, + "RoomChangeRolesScreenRow_Previews" : RoomChangeRolesScreenRow_Previews.self, + "RoomChangeRolesScreenSelectedItem_Previews" : RoomChangeRolesScreenSelectedItem_Previews.self, + "RoomChangeRolesScreen_Previews" : RoomChangeRolesScreen_Previews.self, + "RoomDetailsEditScreen_Previews" : RoomDetailsEditScreen_Previews.self, + "RoomDetailsScreen_Previews" : RoomDetailsScreen_Previews.self, + "RoomDirectorySearchCell_Previews" : RoomDirectorySearchCell_Previews.self, + "RoomDirectorySearchScreen_Previews" : RoomDirectorySearchScreen_Previews.self, + "RoomHeaderView_Previews" : RoomHeaderView_Previews.self, + "RoomInviterLabel_Previews" : RoomInviterLabel_Previews.self, + "RoomListFilterView_Previews" : RoomListFilterView_Previews.self, + "RoomListFiltersEmptyStateView_Previews" : RoomListFiltersEmptyStateView_Previews.self, + "RoomListFiltersView_Previews" : RoomListFiltersView_Previews.self, + "RoomMemberDetailsScreen_Previews" : RoomMemberDetailsScreen_Previews.self, + "RoomMembersListMemberCell_Previews" : RoomMembersListMemberCell_Previews.self, + "RoomMembersListScreen_Previews" : RoomMembersListScreen_Previews.self, + "RoomNotificationSettingsCustomSectionView_Previews" : RoomNotificationSettingsCustomSectionView_Previews.self, + "RoomNotificationSettingsScreen_Previews" : RoomNotificationSettingsScreen_Previews.self, + "RoomNotificationSettingsUserDefinedScreen_Previews" : RoomNotificationSettingsUserDefinedScreen_Previews.self, + "RoomPollsHistoryScreen_Previews" : RoomPollsHistoryScreen_Previews.self, + "RoomRolesAndPermissionsScreen_Previews" : RoomRolesAndPermissionsScreen_Previews.self, + "RoomScreenFooterView_Previews" : RoomScreenFooterView_Previews.self, + "RoomScreen_Previews" : RoomScreen_Previews.self, + "RoomSelectionScreen_Previews" : RoomSelectionScreen_Previews.self, + "SFNumberedListView_Previews" : SFNumberedListView_Previews.self, + "SecureBackupKeyBackupScreen_Previews" : SecureBackupKeyBackupScreen_Previews.self, + "SecureBackupLogoutConfirmationScreen_Previews" : SecureBackupLogoutConfirmationScreen_Previews.self, + "SecureBackupRecoveryKeyScreen_Previews" : SecureBackupRecoveryKeyScreen_Previews.self, + "SecureBackupScreen_Previews" : SecureBackupScreen_Previews.self, + "SecurityAndPrivacyScreen_Previews" : SecurityAndPrivacyScreen_Previews.self, + "SendInviteConfirmationView_Previews" : SendInviteConfirmationView_Previews.self, + "SeparatorMediaEventsTimelineView_Previews" : SeparatorMediaEventsTimelineView_Previews.self, + "SeparatorRoomTimelineView_Previews" : SeparatorRoomTimelineView_Previews.self, + "ServerConfirmationScreen_Previews" : ServerConfirmationScreen_Previews.self, + "ServerSelection_Previews" : ServerSelection_Previews.self, + "SessionVerificationRequestDetailsView_Previews" : SessionVerificationRequestDetailsView_Previews.self, + "SessionVerification_Previews" : SessionVerification_Previews.self, + "SettingsScreen_Previews" : SettingsScreen_Previews.self, + "ShimmerOverlay_Previews" : ShimmerOverlay_Previews.self, + "SoftLogoutScreen_Previews" : SoftLogoutScreen_Previews.self, + "SplashScreen_Previews" : SplashScreen_Previews.self, + "StackedAvatarsView_Previews" : StackedAvatarsView_Previews.self, + "StartChatScreen_Previews" : StartChatScreen_Previews.self, + "StateRoomTimelineView_Previews" : StateRoomTimelineView_Previews.self, + "StaticLocationScreenViewer_Previews" : StaticLocationScreenViewer_Previews.self, + "StickerRoomTimelineView_Previews" : StickerRoomTimelineView_Previews.self, + "SwipeRightAction_Previews" : SwipeRightAction_Previews.self, + "SwipeToReplyView_Previews" : SwipeToReplyView_Previews.self, + "TextRoomTimelineView_Previews" : TextRoomTimelineView_Previews.self, + "ThreadDecorator_Previews" : ThreadDecorator_Previews.self, + "TimelineDeliveryStatusView_Previews" : TimelineDeliveryStatusView_Previews.self, + "TimelineItemBubbledStylerView_Previews" : TimelineItemBubbledStylerView_Previews.self, + "TimelineItemDebugView_Previews" : TimelineItemDebugView_Previews.self, + "TimelineItemMenu_Previews" : TimelineItemMenu_Previews.self, + "TimelineItemSendInfoLabel_Previews" : TimelineItemSendInfoLabel_Previews.self, + "TimelineItemStyler_Previews" : TimelineItemStyler_Previews.self, + "TimelineMediaPreviewDetailsView_Previews" : TimelineMediaPreviewDetailsView_Previews.self, + "TimelineMediaPreviewRedactConfirmationView_Previews" : TimelineMediaPreviewRedactConfirmationView_Previews.self, + "TimelineReactionView_Previews" : TimelineReactionView_Previews.self, + "TimelineReadReceiptsView_Previews" : TimelineReadReceiptsView_Previews.self, + "TimelineReplyView_Previews" : TimelineReplyView_Previews.self, + "TimelineStartRoomTimelineView_Previews" : TimelineStartRoomTimelineView_Previews.self, + "TimelineThreadSummaryView_Previews" : TimelineThreadSummaryView_Previews.self, + "TimelineView_Previews" : TimelineView_Previews.self, + "TombstonedAvatarImage_Previews" : TombstonedAvatarImage_Previews.self, + "TypingIndicatorView_Previews" : TypingIndicatorView_Previews.self, + "UnsupportedRoomTimelineView_Previews" : UnsupportedRoomTimelineView_Previews.self, + "UserDetailsEditScreen_Previews" : UserDetailsEditScreen_Previews.self, + "UserIndicatorModalView_Previews" : UserIndicatorModalView_Previews.self, + "UserIndicatorToastView_Previews" : UserIndicatorToastView_Previews.self, + "UserProfileCell_Previews" : UserProfileCell_Previews.self, + "UserProfileScreen_Previews" : UserProfileScreen_Previews.self, + "VerificationBadge_Previews" : VerificationBadge_Previews.self, + "VideoMediaEventsTimelineView_Previews" : VideoMediaEventsTimelineView_Previews.self, + "VideoRoomTimelineView_Previews" : VideoRoomTimelineView_Previews.self, + "VisualListItem_Previews" : VisualListItem_Previews.self, + "VoiceMessageButton_Previews" : VoiceMessageButton_Previews.self, + "VoiceMessageMediaEventsTimelineView_Previews" : VoiceMessageMediaEventsTimelineView_Previews.self, + "VoiceMessagePreviewComposer_Previews" : VoiceMessagePreviewComposer_Previews.self, + "VoiceMessageRecordingButton_Previews" : VoiceMessageRecordingButton_Previews.self, + "VoiceMessageRecordingComposer_Previews" : VoiceMessageRecordingComposer_Previews.self, + "VoiceMessageRecordingView_Previews" : VoiceMessageRecordingView_Previews.self, + "VoiceMessageRoomPlaybackView_Previews" : VoiceMessageRoomPlaybackView_Previews.self, + "VoiceMessageRoomTimelineView_Previews" : VoiceMessageRoomTimelineView_Previews.self, + "WaveformCursorView_Previews" : WaveformCursorView_Previews.self, + ] + } + +// swiftlint:enable all +// swiftformat:enable all diff --git a/ElementX/Sources/UITests/UITestsSignalling.swift b/ElementX/Sources/UITests/UITestsSignalling.swift index fcbd5b7f0..8f707d306 100644 --- a/ElementX/Sources/UITests/UITestsSignalling.swift +++ b/ElementX/Sources/UITests/UITestsSignalling.swift @@ -29,6 +29,16 @@ enum UITestsSignal: Codable, Equatable { /// Posts a notification. case notification(name: Notification.Name) + + case accessibilityAudit(AccessibilityAudit) + enum AccessibilityAudit: Codable, Equatable { + /// Ask the app for the next preview. + case nextPreview + /// Tell the test runner about a loaded preview. + case nextPreviewReady(name: String) + /// Tell the test runner that there are no more previews. + case noMorePreviews + } } enum UITestsSignalError: String, LocalizedError { diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml index 638241276..936901ab8 100644 --- a/ElementX/SupportingFiles/target.yml +++ b/ElementX/SupportingFiles/target.yml @@ -180,6 +180,18 @@ targets: else echo "warning: Sourcery not installed, run swift run tools setup-project" fi + + - name: 🧙 Sourcery - Generate Accessibility Tests + runOnlyWhenInstalling: false + basedOnDependencyAnalysis: false + shell: /bin/sh + script: | + export PATH="$PATH:/opt/homebrew/bin" + if which sourcery >/dev/null; then + sourcery --config Tools/Sourcery/TestablePreviewsDictionary.yml + else + echo "warning: Sourcery not installed, run swift run tools setup-project" + fi postBuildScripts: - name: ⚠️ SwiftLint diff --git a/NSE/SupportingFiles/target.yml b/NSE/SupportingFiles/target.yml index 223eeb939..97f4c2e2d 100644 --- a/NSE/SupportingFiles/target.yml +++ b/NSE/SupportingFiles/target.yml @@ -113,7 +113,7 @@ targets: - path: ../../ElementX/Sources/Other/Pills/PlainMentionBuilder.swift - path: ../../ElementX/Sources/Other/SDKListener.swift - path: ../../ElementX/Sources/Other/SwiftUI/Views/PlaceholderAvatarImage.swift - - path: ../../ElementX/Sources/Other/TestablePreview.swift + - path: ../../ElementX/Sources/Other/TestablePreview/TestablePreview.swift - path: ../../ElementX/Sources/Other/UserAgentBuilder.swift - path: ../../ElementX/Sources/Other/UserPreference.swift - path: ../../ElementX/Sources/Services/ElementCall/ElementCallServiceConstants.swift diff --git a/Tools/Sourcery/TestablePreviewsDictionary.stencil b/Tools/Sourcery/TestablePreviewsDictionary.stencil new file mode 100644 index 000000000..15f764459 --- /dev/null +++ b/Tools/Sourcery/TestablePreviewsDictionary.stencil @@ -0,0 +1,29 @@ +// swiftlint:disable all +// swiftformat:disable all + +import SwiftUI + +{% if argument.mainTarget %} +@testable import {{ argument.mainTarget }} +{% endif %} +{% for import in argument.imports %} +{% if import != "last" %} +import {{ import }} +{% endif %} +{% endfor %} +{% for import in argument.testableImports %} +{% if import != "last" %} +@testable import {{ import }} +{% endif %} +{% endfor %} + +enum TestablePreviewsDictionary { + static let dictionary: [String: any PreviewProvider.Type] = [ + {% for type in types.types where (type.implements.TestablePreview or type.based.TestablePreview or type|annotated:"TestablePreview") and type.name != "TestablePreview" %} + "{{ type.name }}" : {{ type.name }}.self, + {% endfor %} + ] + } + +// swiftlint:enable all +// swiftformat:enable all diff --git a/Tools/Sourcery/TestablePreviewsDictionary.yml b/Tools/Sourcery/TestablePreviewsDictionary.yml new file mode 100644 index 000000000..7b136b61e --- /dev/null +++ b/Tools/Sourcery/TestablePreviewsDictionary.yml @@ -0,0 +1,7 @@ +sources: + include: + - ../../ElementX +templates: + - TestablePreviewsDictionary.stencil +output: + ../../ElementX/Sources/Other/TestablePreview/TestablePreviewsDictionary.swift diff --git a/project.yml b/project.yml index 10f9445e0..2331415de 100644 --- a/project.yml +++ b/project.yml @@ -21,6 +21,7 @@ options: - UnitTests - PreviewTests - UITests + - AccessibilityTests - IntegrationTests - DevelopmentAssets - Secrets @@ -39,6 +40,7 @@ options: - Screens - Other - UITests + - AccessibilityTests postGenCommand: cd Tools/XcodeGen && sh postGenCommand.sh settings: @@ -59,6 +61,7 @@ include: - path: IntegrationTests/SupportingFiles/target.yml - path: NSE/SupportingFiles/target.yml - path: ShareExtension/SupportingFiles/target.yml +- path: AccessibilityTests/SupportingFiles/target.yml # - path: MyAppVariant/override.yml packages: