diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 000000000..f12da909b --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,40 @@ +name: Integration tests + +on: + schedule: + - cron: '0 3 * * 1-5' + + workflow_dispatch: + +jobs: + integration_tests: + name: Integration Tests + runs-on: macos-12 + + concurrency: + # Only allow a single run of this workflow on each branch, automatically cancelling older runs. + group: integration-tests-${{ github.head_ref }} + cancel-in-progress: true + + steps: + - uses: actions/checkout@v3 + + - uses: actions/cache@v3 + with: + path: vendor/bundle + key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: | + ${{ runner.os }}-gems- + + - name: Bundle install + run: | + bundle config path vendor/bundle + bundle install --jobs 4 --retry 3 + + - name: Run tests + run: bundle exec fastlane integration_tests + env: + INTEGRATION_TESTS_HOST: ${{ secrets.INTEGRATION_TESTS_HOST }} + INTEGRATION_TESTS_USERNAME: ${{ secrets.INTEGRATION_TESTS_USERNAME }} + INTEGRATION_TESTS_PASSWORD: ${{ secrets.INTEGRATION_TESTS_PASSWORD }} + diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml index 4d4d69442..97028d3c3 100644 --- a/.github/workflows/release-alpha.yml +++ b/.github/workflows/release-alpha.yml @@ -1,4 +1,4 @@ -name: Build alpha release +name: Alpha release on: @@ -34,7 +34,7 @@ jobs: # Common setup - name: Brew bundle run: - brew bundle + brew update && brew bundle && brew upgrade - name: Bundle install run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c318ecd62..a0f628561 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,6 +33,10 @@ jobs: restore-keys: | ${{ runner.os }}-gems- + - name: Brew bundle + run: + brew update && brew bundle && brew upgrade + - name: Bundle install run: | bundle config path vendor/bundle diff --git a/.swiftlint.yml b/.swiftlint.yml index e1a825031..8edf7ba67 100755 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -15,6 +15,8 @@ opt_in_rules: included: - ElementX - Tools/Scripts/Templates +excluded: + - IntegrationTests line_length: warning: 250 diff --git a/Brewfile b/Brewfile index 5d725b32f..dc68e7c46 100644 --- a/Brewfile +++ b/Brewfile @@ -1,5 +1,6 @@ brew "xcodegen" brew "swiftgen" +brew "swiftformat" brew "imagemagick" #brew "swiftlint" # Fails on the CI: `Target /usr/local/bin/swiftlint Target /usr/local/bin/swiftlint already exists`. Installed through https://github.com/actions/virtual-environments/blob/main/images/macos/macos-12-Readme.md#linters \ No newline at end of file diff --git a/Brewfile.lock.json b/Brewfile.lock.json index 2b96976ab..ba6a9bf4a 100644 --- a/Brewfile.lock.json +++ b/Brewfile.lock.json @@ -2,103 +2,132 @@ "entries": { "brew": { "xcodegen": { - "version": "2.28.0", + "version": "2.31.0", "bottle": { "rebuild": 0, "root_url": "https://ghcr.io/v2/homebrew/core", "files": { "arm64_monterey": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:fa493f26e65f0bb0c6be559a395efb84009d842d55035c8fcfd7bcc35096fd17", - "sha256": "fa493f26e65f0bb0c6be559a395efb84009d842d55035c8fcfd7bcc35096fd17" + "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:9c0d59b3c9c2b8bd8b847895341494783a64fc6e883219fb9c5f42e66e883e7a", + "sha256": "9c0d59b3c9c2b8bd8b847895341494783a64fc6e883219fb9c5f42e66e883e7a" }, "arm64_big_sur": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:54ce7cba17293f6eabd644af8c8855ca5ac46f4e8475e5a1a961053d31061210", - "sha256": "54ce7cba17293f6eabd644af8c8855ca5ac46f4e8475e5a1a961053d31061210" + "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:4c776a7bca4b8221318f658441f7c5528dda2c91f6e58f66f6dba11c78f02671", + "sha256": "4c776a7bca4b8221318f658441f7c5528dda2c91f6e58f66f6dba11c78f02671" }, "monterey": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:261df12ea22b281c6683113755a95887213aec51a345851d3671eec6a82dd169", - "sha256": "261df12ea22b281c6683113755a95887213aec51a345851d3671eec6a82dd169" + "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:80b230d284ef71667ccf98d4ca25ef246049e38986e03daf0926a14e51f52f08", + "sha256": "80b230d284ef71667ccf98d4ca25ef246049e38986e03daf0926a14e51f52f08" }, "big_sur": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:24936b2f648842c026cc0da57ac4d2a04669a1bd459af06d20acfbfa3a1c33da", - "sha256": "24936b2f648842c026cc0da57ac4d2a04669a1bd459af06d20acfbfa3a1c33da" + "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:88c179e5e29319e89782b18dfadeddb1237005163904dd08477559b2e306b95d", + "sha256": "88c179e5e29319e89782b18dfadeddb1237005163904dd08477559b2e306b95d" }, "catalina": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:d7b4298a5833f5c2abaa8f19cd60f1da2f13379b9534d67746ac5a37b754e1bd", - "sha256": "d7b4298a5833f5c2abaa8f19cd60f1da2f13379b9534d67746ac5a37b754e1bd" + "url": "https://ghcr.io/v2/homebrew/core/xcodegen/blobs/sha256:0d96563eaf9badacd9ce1d0c6fc9445d88bd33017a8ad4259da8552020207140", + "sha256": "0d96563eaf9badacd9ce1d0c6fc9445d88bd33017a8ad4259da8552020207140" } } } }, "swiftgen": { - "version": "6.5.1", + "version": "6.6.2", "bottle": { "rebuild": 0, "root_url": "https://ghcr.io/v2/homebrew/core", "files": { "arm64_monterey": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:bf3abab4eac9a3886d79d6eb625b1d010c4490cd04391d02a78d44ea67ffbc5f", - "sha256": "bf3abab4eac9a3886d79d6eb625b1d010c4490cd04391d02a78d44ea67ffbc5f" - }, - "arm64_big_sur": { - "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:ea599c0ad955644eb3f946360603090f0b05b859c892ccb94d85795eb68612d6", - "sha256": "ea599c0ad955644eb3f946360603090f0b05b859c892ccb94d85795eb68612d6" + "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:22d90e985b8a6ab49311800eeb7ab721f4872bc85a60b44b7ad57954453569c8", + "sha256": "22d90e985b8a6ab49311800eeb7ab721f4872bc85a60b44b7ad57954453569c8" }, "monterey": { "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:ea47c833c24c992ecba7fff825d94efd15ed4be586c6c39188fdad1c11605f2f", - "sha256": "ea47c833c24c992ecba7fff825d94efd15ed4be586c6c39188fdad1c11605f2f" - }, - "big_sur": { - "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:d23540aaccbe68f26fc50260a29904afa1e84f97c678e76d4c842927215e91e9", - "sha256": "d23540aaccbe68f26fc50260a29904afa1e84f97c678e76d4c842927215e91e9" + "url": "https://ghcr.io/v2/homebrew/core/swiftgen/blobs/sha256:3c158aecb7ced0c489ef11f6a4c15a9d1449a40ad554388a0310116f510ec316", + "sha256": "3c158aecb7ced0c489ef11f6a4c15a9d1449a40ad554388a0310116f510ec316" } } } }, "imagemagick": { - "version": "7.1.0-32", + "version": "7.1.0-45", "bottle": { "rebuild": 0, "root_url": "https://ghcr.io/v2/homebrew/core", "files": { "arm64_monterey": { "cellar": "/opt/homebrew/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:a000a3d98820aad5aba1d1b27967c992a680af6073d3776c5615ad85c65cfe5b", - "sha256": "a000a3d98820aad5aba1d1b27967c992a680af6073d3776c5615ad85c65cfe5b" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:59b175f274e796a0f426c09fd4bfbd6a2def28ed23e2c80c2dca36d16dd44d71", + "sha256": "59b175f274e796a0f426c09fd4bfbd6a2def28ed23e2c80c2dca36d16dd44d71" }, "arm64_big_sur": { "cellar": "/opt/homebrew/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:cd8e156ab68b436afaafee16362814886217d420ff25ebe5a026ef7f84594fb5", - "sha256": "cd8e156ab68b436afaafee16362814886217d420ff25ebe5a026ef7f84594fb5" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:ff67c8a22b12c2e9499981142fcbdd399ed6a49d86eb14b0cae8fb879551c590", + "sha256": "ff67c8a22b12c2e9499981142fcbdd399ed6a49d86eb14b0cae8fb879551c590" }, "monterey": { "cellar": "/usr/local/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:ca5f4b21069ba55a8721dc979c93854b4d9083b08d4d998569563f03eeabf246", - "sha256": "ca5f4b21069ba55a8721dc979c93854b4d9083b08d4d998569563f03eeabf246" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:5c3ee32115784d230675ac64372651f4701a84ea7f920a88a6141a504d7ae090", + "sha256": "5c3ee32115784d230675ac64372651f4701a84ea7f920a88a6141a504d7ae090" }, "big_sur": { "cellar": "/usr/local/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:1602ec46afbe6cd6eef61605d904db05277637de1e55a262973657d6ce48c62e", - "sha256": "1602ec46afbe6cd6eef61605d904db05277637de1e55a262973657d6ce48c62e" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:249e5aa8c3f0518af1696503283c446600a65d86d3eb945e5c449b92a7bc8a1a", + "sha256": "249e5aa8c3f0518af1696503283c446600a65d86d3eb945e5c449b92a7bc8a1a" }, "catalina": { "cellar": "/usr/local/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:cba2739bf96a77e5e7502ffb86561fcb8c546e1bdfc3ab1bed45b6feecf7030e", - "sha256": "cba2739bf96a77e5e7502ffb86561fcb8c546e1bdfc3ab1bed45b6feecf7030e" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:ee57cb93ab5da15954fd6cabcd0e509589504f4c44f308319ac163b03fa1096a", + "sha256": "ee57cb93ab5da15954fd6cabcd0e509589504f4c44f308319ac163b03fa1096a" }, "x86_64_linux": { "cellar": "/home/linuxbrew/.linuxbrew/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:8f3597d568169af3d0121c35407274444cb626167980a7e135d12b8867594d3a", - "sha256": "8f3597d568169af3d0121c35407274444cb626167980a7e135d12b8867594d3a" + "url": "https://ghcr.io/v2/homebrew/core/imagemagick/blobs/sha256:c7b396c47cb3c65fbc5ac1904afbd42594f49d82920249a5beb1779514097d1b", + "sha256": "c7b396c47cb3c65fbc5ac1904afbd42594f49d82920249a5beb1779514097d1b" + } + } + } + }, + "swiftformat": { + "version": "0.49.17", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:4b7f2dbc6e2d69c55e556339fd37bcb9b5085ffb26e18ece57f6614f68f71d9a", + "sha256": "4b7f2dbc6e2d69c55e556339fd37bcb9b5085ffb26e18ece57f6614f68f71d9a" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:6762a1f50c474ace807cbe505c40ec83e07d95f3a709b862b55a4aee358bcbc2", + "sha256": "6762a1f50c474ace807cbe505c40ec83e07d95f3a709b862b55a4aee358bcbc2" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:46ab8382cc299980caf2aa48ca4e08cf3b3052432959e2bd02ca190f168f563b", + "sha256": "46ab8382cc299980caf2aa48ca4e08cf3b3052432959e2bd02ca190f168f563b" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:0145b1f25c402c6d3f4b022a1ec3fc1469b3d61428bc9f47405e2124cffda100", + "sha256": "0145b1f25c402c6d3f4b022a1ec3fc1469b3d61428bc9f47405e2124cffda100" + }, + "catalina": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:bc210385a7a34bd8babd475927d698e38feb6d9b6bc267f159acd67e90542380", + "sha256": "bc210385a7a34bd8babd475927d698e38feb6d9b6bc267f159acd67e90542380" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:326c9a8cedeeb429315d94638a5c03a764194b346a2781fe858d5cb83d93662d", + "sha256": "326c9a8cedeeb429315d94638a5c03a764194b346a2781fe858d5cb83d93662d" } } } @@ -108,11 +137,11 @@ "system": { "macos": { "monterey": { - "HOMEBREW_VERSION": "3.4.10", + "HOMEBREW_VERSION": "3.5.9", "HOMEBREW_PREFIX": "/opt/homebrew", - "Homebrew/homebrew-core": "42c7b6d3e3d3699c34f49b91f602def69ca1ac4d", + "Homebrew/homebrew-core": "07a632ac7825f25d181f47bed9e7ed8663d1d931", "CLT": "13.0.0.0.1.1627064638", - "Xcode": "13.3.1", + "Xcode": "13.4.1", "macOS": "12.3.1" } } diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 41813ae5a..86c9de522 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 0602FA07557F580086782A9E /* UserIndicatorPresentationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FA072E995316CD18BC29313 /* UserIndicatorPresentationContext.swift */; }; 066A1E9B94723EE9F3038044 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EBB5D698CE9A25BB553A2D /* Strings.swift */; }; 06E93B2E3B32740B40F47CC5 /* ElementNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF4B39D52CAE7D21D276ABEE /* ElementNavigationController.swift */; }; + 07240B7159A3990C4C2E8FFC /* LoginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D256FEE2F1AF1E51D39B622 /* LoginTests.swift */; }; 072BA9DBA932374CCA300125 /* MessageComposerTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */; }; 0B1F80C2BF7D223159FBA82C /* ImageAnonymizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6045E825AE900A92D61FEFF0 /* ImageAnonymizerTests.swift */; }; 0C38C3E771B472E27295339D /* SessionVerificationModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB9A17AC512A7EF4B106E5 /* SessionVerificationModels.swift */; }; @@ -41,6 +42,7 @@ 1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4549FCB53F43DB0B278374BC /* TemplateScreen.swift */; }; 157E5FDDF419C0B2CA7E2C28 /* TimelineItemBubbledStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A2932515EA11D3DD8A3506 /* TimelineItemBubbledStylerView.swift */; }; 15D1F9C415D9C921643BA82E /* UserIndicatorRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61B73D5E21F524A9BE44448D /* UserIndicatorRequest.swift */; }; + 1702981A8085BE4FB0EC001B /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33116993D54FADC0C721C1F /* Application.swift */; }; 172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */; }; 17CC4FB64F3A670F43ECBE5F /* UITestsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCA431E6EDD71F7067B5F9E7 /* UITestsRootView.swift */; }; 187E18F21EF4DA244E436E58 /* BugReportViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28959C7DB36C7688A01D4045 /* BugReportViewModelProtocol.swift */; }; @@ -57,10 +59,12 @@ 226027BE23AF64FA61C7A4C0 /* TimelineStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */; }; 22DADD537401E79D66132134 /* NavigationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4173A48FD8542CD4AD3645C /* NavigationRouter.swift */; }; 237FC70AA257B935F53316BA /* SessionVerificationControllerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D7E514F9DE4E3D72FDCAD /* SessionVerificationControllerProxy.swift */; }; + 23B2CD5A06B16055BDDD0994 /* ApplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44D8C8431416EB8DFEC7E235 /* ApplicationTests.swift */; }; 24906A1E82D0046655958536 /* MessageComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18CF12478983A5EB390FB26 /* MessageComposer.swift */; }; 24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */; }; 2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; }; 28410F3DE89C2C44E4F75C92 /* MockBugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E7BF8F7BB1021F889C6483 /* MockBugReportService.swift */; }; + 290FDB0FFDC2F1DDF660343E /* TestMeasurementParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */; }; 297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */; }; 29AEE68A604940180AB9EBFF /* MockRoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDAC8895AB2B77B47703AE /* MockRoomSummary.swift */; }; 29EE1791E0AFA1ABB7F23D2F /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 1BCD21310B997A6837B854D6 /* GZIP */; }; @@ -73,6 +77,7 @@ 2F94054F50E312AF30BE07F3 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40B21E611DADDEF00307E7AC /* String.swift */; }; 2FE4EEF780553B25A446BBFB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFFA5FD06AAAC4AF544B594E /* AppDelegate.swift */; }; 30122AB3484AC6C3A7F6A717 /* ActivityIndicatorView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64F3A3D0DF86ED5A241AB05 /* ActivityIndicatorView.xib */; }; + 308BD9343B95657FAA583FB7 /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = AD2AC190E55B2BD4D0F1D4A7 /* SwiftyBeaver */; }; 3097A0A867D2B19CE32DAE58 /* UIKitBackgroundTaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF1FFC3336EB23374BBBFCC /* UIKitBackgroundTaskService.swift */; }; 313382FC5D38064EAAA35CB2 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D1CC633517D695FEC54208 /* FileManager.swift */; }; 33B4E59D408AE6E02323EE41 /* NoticeRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDA364DFFC3AC71C4771251 /* NoticeRoomMessage.swift */; }; @@ -92,6 +97,7 @@ 3D325A1147F6281C57BFCDF6 /* EventBrief.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4411C0DA0087A1CB143E96FA /* EventBrief.swift */; }; 3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DC38E64A5ED3FDB201029A /* BugReportService.swift */; }; 3ED2725734568F6B8CC87544 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; }; + 3F2148F11164C7C5609984EB /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 19CD5B074D7DD44AF4C58BB6 /* SwiftState */; }; 418B4AEFD03DC7A6D2C9D5C8 /* EventBriefFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36322DD0D4E29D31B0945ADC /* EventBriefFactory.swift */; }; 41DFDD212D1BE57CA50D783B /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 997C7385E1A07E061D7E2100 /* GZIP */; }; 438FB9BC535BC95948AA5F34 /* SettingsViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2F9D5C39A4494D19F33E38 /* SettingsViewModelProtocol.swift */; }; @@ -129,6 +135,7 @@ 5E1FCC43B738941D5A5F1794 /* SplashScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B73A8C3118EAC7BF3F3EE7A /* SplashScreenViewModelProtocol.swift */; }; 5F1FDE49DFD0C680386E48F9 /* TemplateViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B80895CE021B49847BD7D74 /* TemplateViewModelProtocol.swift */; }; 5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7109E709A7738E6BCC4553E6 /* Localizable.strings */; }; + 60ED66E63A169E47489348A8 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 2B788C81F6369D164ADEB917 /* GZIP */; }; 617624A97BDBB75ED3DD8156 /* RoomScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */; }; 6298AB0906DDD3525CD78C6B /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 7731767AE437BA3BD2CC14A8 /* Sentry */; }; 62BBF5BE7B905222F0477FF2 /* MediaSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8210612D17A39369480FC183 /* MediaSource.swift */; }; @@ -190,12 +197,14 @@ 8D9F646387DF656EF91EE4CB /* RoomMessageFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F37AB24AF5A006521D38D1 /* RoomMessageFactoryProtocol.swift */; }; 90DF83A6A347F7EE7EDE89EE /* AttributedStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */; }; 90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D52BAA5BADB06E5E8C295D /* Assets.swift */; }; + 9219640F4D980CFC5FE855AD /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 536E72DCBEEC4A1FE66CFDCE /* target.yml */; }; 93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; }; 93BA4A81B6D893271101F9F0 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; }; 94A65DD8A353DF112EBEF67A /* SessionVerificationControllerProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D56469A9EE0CFA2B7BA9760 /* SessionVerificationControllerProxyProtocol.swift */; }; 94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; }; 94E062D08E27B0387658E364 /* SplashScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5CF94E124616FD89424B73 /* SplashScreenViewModelTests.swift */; }; 964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; }; + 97189E495F0E47805D1868DB /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; }; 9738F894DB1BD383BE05767A /* ElementSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1027BB9A852F445B7623897F /* ElementSettings.swift */; }; 978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */; }; 989029A28C9E2F828AD6658A /* AppIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 16DC8C5B2991724903F1FA6A /* AppIcon.pdf */; }; @@ -223,7 +232,9 @@ A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; }; A8EC7C9D886244DAE9433E37 /* SessionVerificationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C18FAAD59AE7F1462D817E /* SessionVerificationViewModel.swift */; }; + AAF0BBED840DF4A53EE85E77 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = C2C69B8BA5A9702E7A8BC08F /* MatrixRustSDK */; }; AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9760103CF316DF68698BCFE6 /* LaunchScreen.storyboard */; }; + AB4C5D62A21AD712811CE8CD /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68232D336E2B546AD95B78B5 /* XCUIElement.swift */; }; ABF3FAB234AD3565B214309B /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */; }; ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D2D0A6F1ABC99D29462FB84 /* AuthenticationCoordinatorUITests.swift */; }; B037C365CF8A58A0D149A2DB /* AuthenticationIconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97755C01C3971474EFAD5367 /* AuthenticationIconImage.swift */; }; @@ -276,12 +287,14 @@ DFF7D6A6C26DDD40D00AE579 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = F012CB5EE3F2B67359F6CC52 /* target.yml */; }; E0A4DCA633D174EB43AD599F /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; }; E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; }; + E481C8FDCB6C089963C95344 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 527578916BD388A09F5A8036 /* DTCoreText */; }; E5895C74615CBE8462FB840F /* SessionVerificationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF86010A0A719A9A50EEC59 /* SessionVerificationCoordinator.swift */; }; E81EEC1675F2371D12A880A3 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61ADFB893DEF81E58DF3FAB9 /* MockRoomTimelineController.swift */; }; EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885D8C42DD17625B5261BEFF /* MediaProvider.swift */; }; EA31DD9043B91ECB8E45A9A6 /* ScreenshotDetectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03C9D319676F3C0DC6B0203 /* ScreenshotDetectorTests.swift */; }; EA65360A0EC026DD83AC0CF5 /* AuthenticationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6CA5F386C7701C129398945 /* AuthenticationCoordinator.swift */; }; EBD6C79705B3DDB2F7E5F554 /* UserSessionStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1B52D0ABBA7091A991CAFE /* UserSessionStoreProtocol.swift */; }; + EC280623A42904341363EAAF /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 886A0A498FA01E8EDD451D05 /* Sentry */; }; EE4F5601356228FF72FC56B6 /* MockClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F40F48279322E504153AB0D /* MockClientProxy.swift */; }; EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */; }; EEC40663922856C65D1E0DF5 /* KeychainControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */; }; @@ -294,15 +307,24 @@ F656F92A63D3DC1978D79427 /* AppAuth in Frameworks */ = {isa = PBXBuildFile; productRef = AA4E1BEB4E9BC2467006E12B /* AppAuth */; }; F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */; }; F78C57B197DA74735FEBB42C /* EventBriefFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92B61C243325DC76D3086494 /* EventBriefFactoryProtocol.swift */; }; + F99FB21EFC6D99D247FE7CBE /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = D82E84F90358CC1118E6034B /* Introspect */; }; FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; }; FC6B7436C3A5B3D0565227D5 /* ActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF05352F28D4E7336228E9F4 /* ActivityIndicatorView.swift */; }; FCB640C576292BEAF7FA3B2E /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F395A2E917115C7AAF7F34 /* SplashViewController.swift */; }; + FCD3F2B82CAB29A07887A127 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DE8DC9B3FBA402117DC4C49F /* Kingfisher */; }; FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1593DD87F974F8509BB619 /* ElementAnimations.swift */; }; FE79E2BCCF69E8BF4D21E15A /* RoomMessageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA154570F693D93513E584C1 /* RoomMessageFactory.swift */; }; FFD3E4FF948E06C7585317FC /* TimelineStyler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892E29C98C4E8182C9037F84 /* TimelineStyler.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 4448BD77D7203616C4FAD26A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = AC22997D58D612146053154D /* Project object */; + proxyType = 1; + remoteGlobalIDString = C0FAEB81CFD9776CD78CE489; + remoteInfo = ElementX; + }; 4D8DD8FE84794CA168A8499A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AC22997D58D612146053154D /* Project object */; @@ -344,6 +366,7 @@ 0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelProtocol.swift; sourceTree = ""; }; 0F7A812F160E75B69A9181A2 /* SplashScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenCoordinator.swift; sourceTree = ""; }; 1027BB9A852F445B7623897F /* ElementSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementSettings.swift; sourceTree = ""; }; + 1059E2AE7878CF7820592637 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = ""; }; 105D16E7DB0CCE9526612BDD /* bn-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "bn-IN"; path = "bn-IN.lproj/Localizable.strings"; sourceTree = ""; }; 109C0201D8CB3F947340DC80 /* WeakDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakDictionary.swift; sourceTree = ""; }; @@ -384,6 +407,7 @@ 2B80895CE021B49847BD7D74 /* TemplateViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateViewModelProtocol.swift; sourceTree = ""; }; 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskProtocol.swift; sourceTree = ""; }; 2CF9FE7E0CF9F40D1509E63A /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = bg; path = bg.lproj/Localizable.stringsdict; sourceTree = ""; }; + 2D256FEE2F1AF1E51D39B622 /* LoginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginTests.swift; sourceTree = ""; }; 2EEB64CC6F3DF5B68736A6B4 /* AlertInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertInfo.swift; sourceTree = ""; }; 31B01468022EC826CB2FD2C0 /* LoginModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginModels.swift; sourceTree = ""; }; 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModel.swift; sourceTree = ""; }; @@ -421,6 +445,7 @@ 4470B8CB654B097D807AA713 /* ToastViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastViewPresenter.swift; sourceTree = ""; }; 4488F5F92A64A137665C96CD /* pa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pa; path = pa.lproj/Localizable.strings; sourceTree = ""; }; 44AEEE13AC1BF303AE48CBF8 /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/Localizable.strings; sourceTree = ""; }; + 44D8C8431416EB8DFEC7E235 /* ApplicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationTests.swift; sourceTree = ""; }; 453E722A43D092C06FB8E3FA /* tzm */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tzm; path = tzm.lproj/Localizable.strings; sourceTree = ""; }; 4549FCB53F43DB0B278374BC /* TemplateScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreen.swift; sourceTree = ""; }; 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = ""; }; @@ -451,6 +476,7 @@ 5221DFDF809142A2D6AC82B9 /* RoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreen.swift; sourceTree = ""; }; 529513218340CC8419273165 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; 534A5C8FCDE2CBC50266B9F2 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = gl; path = gl.lproj/Localizable.stringsdict; sourceTree = ""; }; + 536E72DCBEEC4A1FE66CFDCE /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 55BC11560C8A2598964FFA4C /* bs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bs; path = bs.lproj/Localizable.strings; sourceTree = ""; }; 55D7187F6B0C0A651AC3DFFA /* in */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = in; path = in.lproj/Localizable.strings; sourceTree = ""; }; 56F01DD1BBD4450E18115916 /* LabelledActivityIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelledActivityIndicatorView.swift; sourceTree = ""; }; @@ -483,6 +509,7 @@ 6654859746B0BE9611459391 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Localizable.stringsdict; sourceTree = ""; }; 667DD3A9D932D7D9EB380CAA /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sk; path = sk.lproj/Localizable.stringsdict; sourceTree = ""; }; 66F2402D738694F98729A441 /* RoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProvider.swift; sourceTree = ""; }; + 68232D336E2B546AD95B78B5 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; 68706A66BBA04268F7747A2F /* ActivityIndicatorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorPresenter.swift; sourceTree = ""; }; 6920A4869821BF72FFC58842 /* MockMediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaProvider.swift; sourceTree = ""; }; 6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProvider.swift; sourceTree = ""; }; @@ -561,7 +588,9 @@ 997783054A2E95F9E624217E /* kaa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kaa; path = kaa.lproj/Localizable.strings; sourceTree = ""; }; 99DE232F24EAD72A3DF7EF1A /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = kab; path = kab.lproj/Localizable.stringsdict; sourceTree = ""; }; 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceProtocol.swift; sourceTree = ""; }; + 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestMeasurementParser.swift; sourceTree = ""; }; 9C5E81214D27A6B898FC397D /* ElementX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = ""; }; + 9C7F7DE62D33C6A26CBFCD72 /* IntegrationTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModel.swift; sourceTree = ""; }; 9D7D706FFF438CAF16F44D8C /* ServerSelectionCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionCoordinator.swift; sourceTree = ""; }; 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIConstants.swift; sourceTree = ""; }; @@ -656,6 +685,7 @@ D1A9CCCF53495CF3D7B19FCE /* MockSessionVerificationControllerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSessionVerificationControllerProxy.swift; sourceTree = ""; }; D29EBCBFEC6FD0941749404D /* NavigationRouterStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRouterStore.swift; sourceTree = ""; }; D31DC8105C6233E5FFD9B84C /* element-x-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "element-x-ios"; path = .; sourceTree = SOURCE_ROOT; }; + D33116993D54FADC0C721C1F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; D4DA544B2520BFA65D6DB4BB /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; D653265D006E708E4E51AD64 /* HomeScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenCoordinator.swift; sourceTree = ""; }; D67CBAFA48ED0B6FCE74F88F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = ""; }; @@ -712,6 +742,22 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 60823A8E409E27661824D510 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AAF0BBED840DF4A53EE85E77 /* MatrixRustSDK in Frameworks */, + E481C8FDCB6C089963C95344 /* DTCoreText in Frameworks */, + 97189E495F0E47805D1868DB /* KeychainAccess in Frameworks */, + FCD3F2B82CAB29A07887A127 /* Kingfisher in Frameworks */, + F99FB21EFC6D99D247FE7CBE /* Introspect in Frameworks */, + 308BD9343B95657FAA583FB7 /* SwiftyBeaver in Frameworks */, + 3F2148F11164C7C5609984EB /* SwiftState in Frameworks */, + 60ED66E63A169E47489348A8 /* GZIP in Frameworks */, + EC280623A42904341363EAAF /* Sentry in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD30252A70288BD4BF476ED7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -919,6 +965,7 @@ 99B9B46F2D621380428E68F7 /* ElementX */, A4852B57D55D71EEBFCD931D /* UnitTests */, C0FAC17D4DD7D3A502822550 /* UITests */, + 8A9C09B6A392465E03B8D1B1 /* IntegrationTests */, 823ED0EC3F1B6CF47D284011 /* Tools */, 9413F680ECDFB2B0DDB0DEF2 /* Packages */, 681566846AF307E9BA4C72C6 /* Products */, @@ -995,6 +1042,18 @@ path = Tests; sourceTree = ""; }; + 4EC4EBBC4F6885775F198875 /* Sources */ = { + isa = PBXGroup; + children = ( + D33116993D54FADC0C721C1F /* Application.swift */, + 44D8C8431416EB8DFEC7E235 /* ApplicationTests.swift */, + 2D256FEE2F1AF1E51D39B622 /* LoginTests.swift */, + 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */, + 68232D336E2B546AD95B78B5 /* XCUIElement.swift */, + ); + path = Sources; + sourceTree = ""; + }; 4F43EBE458FBE634996AD7C6 /* View */ = { isa = PBXGroup; children = ( @@ -1046,6 +1105,15 @@ path = View; sourceTree = ""; }; + 6765932445C053E15E63C29A /* SupportingFiles */ = { + isa = PBXGroup; + children = ( + 1059E2AE7878CF7820592637 /* Info.plist */, + 536E72DCBEEC4A1FE66CFDCE /* target.yml */, + ); + path = SupportingFiles; + sourceTree = ""; + }; 679E9837ECA8D6776079D16E /* RoomScreen */ = { isa = PBXGroup; children = ( @@ -1062,6 +1130,7 @@ isa = PBXGroup; children = ( 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */, + 9C7F7DE62D33C6A26CBFCD72 /* IntegrationTests.xctest */, F506C6ADB1E1DA6638078E11 /* UITests.xctest */, AAC9344689121887B74877AF /* UnitTests.xctest */, ); @@ -1219,6 +1288,15 @@ path = Session; sourceTree = ""; }; + 8A9C09B6A392465E03B8D1B1 /* IntegrationTests */ = { + isa = PBXGroup; + children = ( + 4EC4EBBC4F6885775F198875 /* Sources */, + 6765932445C053E15E63C29A /* SupportingFiles */, + ); + path = IntegrationTests; + sourceTree = ""; + }; 8F9A844EB44B6AD7CA18FD96 /* HTMLParsing */ = { isa = PBXGroup; children = ( @@ -1711,6 +1789,35 @@ productReference = 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */; productType = "com.apple.product-type.application"; }; + D3DB351B7FBE0F49649171FC /* IntegrationTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B7DCEF0CC298791B0EC4CA84 /* Build configuration list for PBXNativeTarget "IntegrationTests" */; + buildPhases = ( + D831C59C840FB7B2C1C028A0 /* Sources */, + C394D4118F7D345ABE288479 /* Resources */, + 60823A8E409E27661824D510 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 421359F1BC0A1816DD34A2BB /* PBXTargetDependency */, + ); + name = IntegrationTests; + packageProductDependencies = ( + C2C69B8BA5A9702E7A8BC08F /* MatrixRustSDK */, + 527578916BD388A09F5A8036 /* DTCoreText */, + 2B43F2AF7456567FE37270A7 /* KeychainAccess */, + DE8DC9B3FBA402117DC4C49F /* Kingfisher */, + D82E84F90358CC1118E6034B /* Introspect */, + AD2AC190E55B2BD4D0F1D4A7 /* SwiftyBeaver */, + 19CD5B074D7DD44AF4C58BB6 /* SwiftState */, + 2B788C81F6369D164ADEB917 /* GZIP */, + 886A0A498FA01E8EDD451D05 /* Sentry */, + ); + productName = IntegrationTests; + productReference = 9C7F7DE62D33C6A26CBFCD72 /* IntegrationTests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1726,6 +1833,9 @@ C0FAEB81CFD9776CD78CE489 = { DevelopmentTeam = 7J4U792NQT; }; + D3DB351B7FBE0F49649171FC = { + TestTargetID = C0FAEB81CFD9776CD78CE489; + }; }; }; buildConfigurationList = 7AE41FCCF9D1352E2770D1F9 /* Build configuration list for PBXProject "ElementX" */; @@ -1817,7 +1927,7 @@ D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */, 80B898A3AD2AC63F3ABFC218 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */, A08925A9D5E3770DEB9D8509 /* XCRemoteSwiftPackageReference "sentry-cocoa" */, - F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, + E9C4F3A12AA1F65C13A8C8EB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, 6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */, 25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */, ); @@ -1825,6 +1935,7 @@ projectRoot = ""; targets = ( C0FAEB81CFD9776CD78CE489 /* ElementX */, + D3DB351B7FBE0F49649171FC /* IntegrationTests */, 0E28CD62691FDBC63147D5E3 /* UITests */, 32C23C8D224D46EFE62AFAD0 /* UnitTests */, ); @@ -1874,6 +1985,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C394D4118F7D345ABE288479 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9219640F4D980CFC5FE855AD /* target.yml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -2223,6 +2342,18 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D831C59C840FB7B2C1C028A0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1702981A8085BE4FB0EC001B /* Application.swift in Sources */, + 23B2CD5A06B16055BDDD0994 /* ApplicationTests.swift in Sources */, + 07240B7159A3990C4C2E8FFC /* LoginTests.swift in Sources */, + 290FDB0FFDC2F1DDF660343E /* TestMeasurementParser.swift in Sources */, + AB4C5D62A21AD712811CE8CD /* XCUIElement.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -2231,6 +2362,11 @@ target = C0FAEB81CFD9776CD78CE489 /* ElementX */; targetProxy = 4D8DD8FE84794CA168A8499A /* PBXContainerItemProxy */; }; + 421359F1BC0A1816DD34A2BB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C0FAEB81CFD9776CD78CE489 /* ElementX */; + targetProxy = 4448BD77D7203616C4FAD26A /* PBXContainerItemProxy */; + }; 468963EFD503D7DFAD238754 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = C0FAEB81CFD9776CD78CE489 /* ElementX */; @@ -2653,6 +2789,42 @@ }; name = Release; }; + AAE81BF8DCDB30B237B10C3E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = IntegrationTests/SupportingFiles/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.element.elementx.integration.tests; + PRODUCT_NAME = IntegrationTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = ElementX; + }; + name = Debug; + }; + F0A74453D306F668178A859E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = IntegrationTests/SupportingFiles/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.element.elementx.integration.tests; + PRODUCT_NAME = IntegrationTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = ElementX; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2683,6 +2855,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + B7DCEF0CC298791B0EC4CA84 /* Build configuration list for PBXNativeTarget "IntegrationTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AAE81BF8DCDB30B237B10C3E /* Debug */, + F0A74453D306F668178A859E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; F1B67CF63C1231AEB14D70E6 /* Build configuration list for PBXNativeTarget "UITests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -2775,9 +2956,9 @@ minimumVersion = 7.2.0; }; }; - F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { + E9C4F3A12AA1F65C13A8C8EB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing.git"; + repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing"; requirement = { kind = upToNextMajorVersion; minimumVersion = 1.9.0; @@ -2801,6 +2982,11 @@ package = D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */; productName = Kingfisher; }; + 19CD5B074D7DD44AF4C58BB6 /* SwiftState */ = { + isa = XCSwiftPackageProductDependency; + package = 6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */; + productName = SwiftState; + }; 1BCD21310B997A6837B854D6 /* GZIP */ = { isa = XCSwiftPackageProductDependency; package = 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */; @@ -2808,9 +2994,19 @@ }; 21C83087604B154AA30E9A8F /* SnapshotTesting */ = { isa = XCSwiftPackageProductDependency; - package = F34594223DB1E7DCE48F92B8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; + package = E9C4F3A12AA1F65C13A8C8EB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; productName = SnapshotTesting; }; + 2B43F2AF7456567FE37270A7 /* KeychainAccess */ = { + isa = XCSwiftPackageProductDependency; + package = 61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */; + productName = KeychainAccess; + }; + 2B788C81F6369D164ADEB917 /* GZIP */ = { + isa = XCSwiftPackageProductDependency; + package = 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */; + productName = GZIP; + }; 36B7FC232711031AA2B0D188 /* DTCoreText */ = { isa = XCSwiftPackageProductDependency; package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */; @@ -2831,6 +3027,11 @@ package = D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */; productName = Kingfisher; }; + 527578916BD388A09F5A8036 /* DTCoreText */ = { + isa = XCSwiftPackageProductDependency; + package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */; + productName = DTCoreText; + }; 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */ = { isa = XCSwiftPackageProductDependency; package = C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */; @@ -2856,6 +3057,11 @@ package = 61916C63E3F5BD900F08DA0C /* XCRemoteSwiftPackageReference "KeychainAccess" */; productName = KeychainAccess; }; + 886A0A498FA01E8EDD451D05 /* Sentry */ = { + isa = XCSwiftPackageProductDependency; + package = A08925A9D5E3770DEB9D8509 /* XCRemoteSwiftPackageReference "sentry-cocoa" */; + productName = Sentry; + }; 9573B94B1C86C6DF751AF3FD /* SwiftState */ = { isa = XCSwiftPackageProductDependency; package = 6582B5AF3F104B0F7E031E7D /* XCRemoteSwiftPackageReference "SwiftState" */; @@ -2885,11 +3091,31 @@ package = 4CE94127E27181B8B72188F0 /* XCRemoteSwiftPackageReference "AppAuth-iOS" */; productName = AppAuth; }; + AD2AC190E55B2BD4D0F1D4A7 /* SwiftyBeaver */ = { + isa = XCSwiftPackageProductDependency; + package = 25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */; + productName = SwiftyBeaver; + }; B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */ = { isa = XCSwiftPackageProductDependency; package = 80B898A3AD2AC63F3ABFC218 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */; productName = MatrixRustSDK; }; + C2C69B8BA5A9702E7A8BC08F /* MatrixRustSDK */ = { + isa = XCSwiftPackageProductDependency; + package = 80B898A3AD2AC63F3ABFC218 /* XCRemoteSwiftPackageReference "matrix-rust-components-swift" */; + productName = MatrixRustSDK; + }; + D82E84F90358CC1118E6034B /* Introspect */ = { + isa = XCSwiftPackageProductDependency; + package = 9A472EE0218FE7DCF5283429 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; + productName = Introspect; + }; + DE8DC9B3FBA402117DC4C49F /* Kingfisher */ = { + isa = XCSwiftPackageProductDependency; + package = D283517192CAC3E2E6920765 /* XCRemoteSwiftPackageReference "Kingfisher" */; + productName = Kingfisher; + }; FD43A50D9B75C9D6D30F006B /* SwiftyBeaver */ = { isa = XCSwiftPackageProductDependency; package = 25B4484A6A20B9F1705DEEDA /* XCRemoteSwiftPackageReference "SwiftyBeaver" */; diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 45cf2b1b5..e901af35d 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -66,7 +66,7 @@ { "identity" : "matrix-rust-components-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/matrix-org/matrix-rust-components-swift.git", + "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { "revision" : "1358c9c2a85cfb5fc1bfadce13565e02618725d4", "version" : "1.0.13-alpha" diff --git a/ElementX.xcodeproj/xcshareddata/xcschemes/ElementX.xcscheme b/ElementX.xcodeproj/xcshareddata/xcschemes/ElementX.xcscheme index 4688a008b..71cb21353 100644 --- a/ElementX.xcodeproj/xcshareddata/xcschemes/ElementX.xcscheme +++ b/ElementX.xcodeproj/xcshareddata/xcschemes/ElementX.xcscheme @@ -27,7 +27,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "NO" + shouldUseLaunchSchemeArgsEnv = "YES" codeCoverageEnabled = "YES" onlyGenerateCoverageForSpecifiedTargets = "YES"> diff --git a/ElementX.xcodeproj/xcshareddata/xcschemes/IntegrationTests.xcscheme b/ElementX.xcodeproj/xcshareddata/xcschemes/IntegrationTests.xcscheme new file mode 100644 index 000000000..fc614d259 --- /dev/null +++ b/ElementX.xcodeproj/xcshareddata/xcschemes/IntegrationTests.xcscheme @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ElementX.xcodeproj/xcshareddata/xcschemes/UITests.xcscheme b/ElementX.xcodeproj/xcshareddata/xcschemes/UITests.xcscheme index 473637b86..f475d7ac6 100644 --- a/ElementX.xcodeproj/xcshareddata/xcschemes/UITests.xcscheme +++ b/ElementX.xcodeproj/xcshareddata/xcschemes/UITests.xcscheme @@ -27,16 +27,14 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> - - + + diff --git a/ElementX.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme b/ElementX.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme index 8c1433ea5..7edcae007 100644 --- a/ElementX.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme +++ b/ElementX.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme @@ -27,10 +27,19 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES" codeCoverageEnabled = "YES" onlyGenerateCoverageForSpecifiedTargets = "NO" - shouldUseLaunchSchemeArgsEnv = "YES" systemAttachmentLifetime = "keepNever"> + + + + @@ -43,15 +52,6 @@ - - - - diff --git a/ElementX/Sources/Generated/Assets.swift b/ElementX/Sources/Generated/Assets.swift index 7438510d7..3ba8d0efa 100644 --- a/ElementX/Sources/Generated/Assets.swift +++ b/ElementX/Sources/Generated/Assets.swift @@ -8,6 +8,9 @@ #elseif os(tvOS) || os(watchOS) import UIKit #endif +#if canImport(SwiftUI) + import SwiftUI +#endif // Deprecated typealiases @available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0") @@ -74,6 +77,13 @@ internal struct ImageAsset { return result } #endif + + #if canImport(SwiftUI) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) + internal var swiftUIImage: SwiftUI.Image { + SwiftUI.Image(asset: self) + } + #endif } internal extension ImageAsset.Image { @@ -92,6 +102,26 @@ internal extension ImageAsset.Image { } } +#if canImport(SwiftUI) +@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) +internal extension SwiftUI.Image { + init(asset: ImageAsset) { + let bundle = BundleToken.bundle + self.init(asset.name, bundle: bundle) + } + + init(asset: ImageAsset, label: Text) { + let bundle = BundleToken.bundle + self.init(asset.name, bundle: bundle, label: label) + } + + init(decorative asset: ImageAsset) { + let bundle = BundleToken.bundle + self.init(decorative: asset.name, bundle: bundle) + } +} +#endif + // swiftlint:disable convenience_type private final class BundleToken { static let bundle: Bundle = { diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift index 70cde4138..5ed002569 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift @@ -101,6 +101,7 @@ struct HomeScreen: View { .font(.headline) .fontWeight(.bold) .foregroundColor(.primary) + .accessibilityIdentifier("userDisplayNameView") } } diff --git a/ElementX/Sources/Services/Client/ClientError.swift b/ElementX/Sources/Services/Client/ClientError.swift index 379b8c4f1..6718dc99b 100644 --- a/ElementX/Sources/Services/Client/ClientError.swift +++ b/ElementX/Sources/Services/Client/ClientError.swift @@ -27,12 +27,10 @@ extension AuthenticationError { var code: MatrixErrorCode { guard case let .Generic(message) = self else { return .unknown } - for code in MatrixErrorCode.allCases { - if message.contains(code.rawValue) { - return code - } + guard let first = MatrixErrorCode.allCases.first(where: { message.contains($0.rawValue) }) else { + return .unknown } - - return .unknown + + return first } } diff --git a/Gemfile.lock b/Gemfile.lock index dd0049df5..36741fb8c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -180,8 +180,6 @@ GEM nanaimo (0.3.0) naturally (2.2.1) netrc (0.11.0) - nokogiri (1.13.8-arm64-darwin) - racc (~> 1.4) nokogiri (1.13.8-x86_64-linux) racc (~> 1.4) optparse (0.1.1) diff --git a/IntegrationTests/Sources/Application.swift b/IntegrationTests/Sources/Application.swift new file mode 100644 index 000000000..034581e1e --- /dev/null +++ b/IntegrationTests/Sources/Application.swift @@ -0,0 +1,46 @@ +// +// Application.swift +// IntegrationTests +// +// Created by Stefan Ceriu on 26/07/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import XCTest + +struct Application { + @discardableResult static func launch() -> XCUIApplication { + let app = XCUIApplication() + app.launch() + return app + } +} + +extension XCUIApplication { + var homeserver: String { + guard let homeserver = ProcessInfo.processInfo.environment["INTEGRATION_TESTS_HOST"], + homeserver.count > 0 else { + return "default" + } + + return homeserver + } + + var username: String { + guard let username = ProcessInfo.processInfo.environment["INTEGRATION_TESTS_USERNAME"], + username.count > 0 else { + return "default" + } + + return username + } + + var password: String { + guard let password = ProcessInfo.processInfo.environment["INTEGRATION_TESTS_PASSWORD"], + password.count > 0 else { + return "default" + } + + return password + } +} diff --git a/IntegrationTests/Sources/ApplicationTests.swift b/IntegrationTests/Sources/ApplicationTests.swift new file mode 100644 index 000000000..04e8aa82d --- /dev/null +++ b/IntegrationTests/Sources/ApplicationTests.swift @@ -0,0 +1,29 @@ +// +// ApplicationTests.swift +// IntegrationTests +// +// Created by Stefan Ceriu on 27/07/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import XCTest + +class ApplicationTests: XCTestCase { + func testLaunchPerformance() throws { + let parser = TestMeasurementParser() + + parser.capture(testCase: self) { + self.measure(metrics: [XCTApplicationLaunchMetric()]) { + Application.launch() + } + } + + guard let actualDuration = parser.valueForMetric(.appLaunch) else { + XCTFail("Couldn't retrieve app launch duration") + return + } + + let expectedDuration = 2.75 + XCTAssertLessThanOrEqual(actualDuration, expectedDuration) + } +} diff --git a/IntegrationTests/Sources/LoginTests.swift b/IntegrationTests/Sources/LoginTests.swift new file mode 100644 index 000000000..62d3f68fe --- /dev/null +++ b/IntegrationTests/Sources/LoginTests.swift @@ -0,0 +1,81 @@ +// +// LoginTest.swift +// IntegrationTests +// +// Created by Stefan Ceriu on 25/07/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import XCTest + +class LoginTests: XCTestCase { + let expectedDuration = 30.0 + + func testLoginFlow() throws { + let parser = TestMeasurementParser() + parser.capture(testCase: self) { + self.measure(metrics: [XCTClockMetric()]) { + self.runLoginLogoutFlow() + } + } + + guard let actualDuration = parser.valueForMetric(.clockMonotonicTime) else { + XCTFail("Couldn't retrieve duration") + return + } + + XCTAssertLessThanOrEqual(actualDuration, expectedDuration) + } + + private func runLoginLogoutFlow() { + let app = Application.launch() + + let getStartedButton = app.buttons["Get started"] + + XCTAssertTrue(getStartedButton.waitForExistence(timeout: 5.0)) + getStartedButton.tap() + + let editHomeserverButton = app.buttons["editServerButton"] + XCTAssertTrue(editHomeserverButton.waitForExistence(timeout: 5.0)) + editHomeserverButton.tap() + + let homeserverTextField = app.textFields["addressTextField"] + XCTAssertTrue(homeserverTextField.waitForExistence(timeout: 5.0)) + + homeserverTextField.clearAndTypeText(app.homeserver) + + let confirmButton = app.buttons["confirmButton"] + XCTAssertTrue(confirmButton.exists) + confirmButton.tap() + + let usernameTextField = app.textFields["usernameTextField"] + XCTAssertTrue(usernameTextField.exists) + + usernameTextField.tap() + usernameTextField.typeText(app.username) + + let passwordTextField = app.secureTextFields["passwordTextField"] + XCTAssertTrue(confirmButton.exists) + + passwordTextField.tap() + passwordTextField.typeText(app.password) + + let nextButton = app.buttons["nextButton"] + XCTAssertTrue(nextButton.exists) + XCTAssertTrue(nextButton.isEnabled) + + nextButton.tap() + + let profileButton = app.buttons["userDisplayNameView"] + XCTAssertTrue(profileButton.waitForExistence(timeout: expectedDuration)) + profileButton.tap() + + let logoutButton = app.buttons["logoutButton"] + XCTAssertTrue(logoutButton.waitForExistence(timeout: 5.0)) + logoutButton.tap() + + let logoutSheetButton = app.buttons["Sign out"].firstMatch + XCTAssertTrue(logoutSheetButton.waitForExistence(timeout: 5.0)) + logoutSheetButton.tap() + } +} diff --git a/IntegrationTests/Sources/TestMeasurementParser.swift b/IntegrationTests/Sources/TestMeasurementParser.swift new file mode 100644 index 000000000..47d065f36 --- /dev/null +++ b/IntegrationTests/Sources/TestMeasurementParser.swift @@ -0,0 +1,120 @@ +// +// TestMeasurementParser.swift +// IntegrationTests +// +// Created by Stefan Ceriu on 28/07/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import XCTest + +enum TestMeasurementParserMetric: String { + case appLaunch = "Duration (AppLaunch)" + case clockMonotonicTime = "Clock Monotonic Time" + case cpuTime = "CPU Time" + case memoryPeakPhysical = "Memory Peak Physical" + case memoryPhysical = "Memory Physical" + case cpuInstructionsRetired = "CPU Instructions Retired" + case diskLogicalWrites = "Disk Logical Writes" + case cpuCycles = "CPU Cycles" + + var regexValue: String { + switch self { + case .appLaunch: + return rawValue.replacingOccurrences(of: "(", with: "\\(").replacingOccurrences(of: ")", with: "\\)") + default: + return rawValue + } + } +} + +/// This class is responsible for extracting XCTest measurement run results from stderr in lieu of an official API +/// Heavily inspired by https://stackoverflow.com/questions/54814422/how-to-extract-performance-metrics-measured-by-measureblock-in-xctest +class TestMeasurementParser { + private let pipe = Pipe() + private let regex: NSRegularExpression + private var results = [String: Double]() + + init() { + do { + let pattern = """ + \\[(\ + \(XCTestMeasurementParserMetric.appLaunch.regexValue)|\ + \(XCTestMeasurementParserMetric.clockMonotonicTime.regexValue)|\ + \(XCTestMeasurementParserMetric.cpuTime.regexValue)|\ + \(XCTestMeasurementParserMetric.memoryPeakPhysical.regexValue)|\ + \(XCTestMeasurementParserMetric.memoryPhysical.regexValue)|\ + \(XCTestMeasurementParserMetric.cpuInstructionsRetired.regexValue)|\ + \(XCTestMeasurementParserMetric.diskLogicalWrites.regexValue)|\ + \(XCTestMeasurementParserMetric.cpuCycles.regexValue)\ + ), \ + (s|kB|kI|kC)\\] \ + average: ([0-9\\.]*), + """ + + regex = try NSRegularExpression(pattern: pattern, + options: .caseInsensitive) + } catch { + fatalError("Invalid regular expression") + } + } + + /// Running an XCTest measure block within this will enable the `XCTestMeasurementParser` to read resulting values from stderr and store them locally + /// - Parameters: + /// - testCase: we need the test case so that we can add and wait for an expectation on it, allowing the capturing to finish + /// - block: should contain the normal test steps and measure block + func capture(testCase: XCTestCase, block: @escaping () -> Void) { + results.removeAll() + + // Save original output + let original = dup(STDERR_FILENO) + + // Configure `stderr` so that it's not buffered + setvbuf(stderr, nil, _IONBF, 0) + + dup2(pipe.fileHandleForWriting.fileDescriptor, STDERR_FILENO) + + pipe.fileHandleForReading.readabilityHandler = { [weak self] handle in + guard let self = self else { + return + } + + let string = String(data: handle.availableData, encoding: .utf8) ?? "\n" + self.regex.matches(in: string, options: .reportCompletion, range: NSRange(location: 0, length: string.count)).forEach { + if let nameIndex = Range($0.range(at: 1), in: string), + let averageIndex = Range($0.range(at: 3), in: string) { + let name = String(string[nameIndex]) + let average = Double(string[averageIndex]) + + self.results[name] = average + } + } + + // Print to stdout because stderr is piped + print("\(string)") + } + + block() + + // Revert + fflush(stderr) + dup2(original, STDERR_FILENO) + close(original) + + // Allow the parser to finish + let expectation = testCase.expectation(description: "Wait for the results to be gathered") + DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { + expectation.fulfill() + } + + testCase.waitForExpectations(timeout: 10.0) + } + + /// Retrieve the recorded average value for a particular metric + /// - Parameter metric: Needs to match one of the metrics passed in the XCTest measure metrics array + /// - Returns: The resulting average value + func valueForMetric(_ metric: XCTestMeasurementParserMetric) -> Double? { + results[metric.rawValue] + } +} diff --git a/IntegrationTests/Sources/XCUIElement.swift b/IntegrationTests/Sources/XCUIElement.swift new file mode 100644 index 000000000..e4942cf30 --- /dev/null +++ b/IntegrationTests/Sources/XCUIElement.swift @@ -0,0 +1,25 @@ +// +// XCUElement.swift +// ElementX +// +// Created by Stefan Ceriu on 27/07/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import XCTest + +extension XCUIElement { + func clearAndTypeText(_ text: String) { + guard let stringValue = value as? String else { + XCTFail("Tried to clear and type text into a non string value") + return + } + + tap() + + let deleteString = String(repeating: XCUIKeyboardKey.delete.rawValue, count: stringValue.count) + + typeText(deleteString) + typeText(text) + } +} diff --git a/IntegrationTests/SupportingFiles/Info.plist b/IntegrationTests/SupportingFiles/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/IntegrationTests/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/IntegrationTests/SupportingFiles/target.yml b/IntegrationTests/SupportingFiles/target.yml new file mode 100644 index 000000000..f82273c71 --- /dev/null +++ b/IntegrationTests/SupportingFiles/target.yml @@ -0,0 +1,50 @@ +name: IntegrationTests + +targets: + IntegrationTests: + type: bundle.ui-testing + platform: iOS + + dependencies: + - target: ElementX + - package: MatrixRustSDK + linkType: static + - package: DTCoreText + linkType: static + - package: KeychainAccess + linkType: static + - package: Kingfisher + linkType: static + - package: Introspect + linkType: static + - package: SwiftyBeaver + linkType: static + - package: SwiftState + linkType: static + - package: GZIP + linkType: static + - package: Sentry + linkType: static + + info: + path: ../SupportingFiles/Info.plist + + settings: + base: + PRODUCT_NAME: IntegrationTests + PRODUCT_BUNDLE_IDENTIFIER: io.element.elementx.integration.tests + debug: + release: + + scheme: + testTargets: + - IntegrationTests + + environmentVariables: + INTEGRATION_TESTS_HOST: ${INTEGRATION_TESTS_HOST} + INTEGRATION_TESTS_USERNAME: ${INTEGRATION_TESTS_USERNAME} + INTEGRATION_TESTS_PASSWORD: ${INTEGRATION_TESTS_PASSWORD} + + sources: + - path: ../Sources + - path: ../SupportingFiles diff --git a/UITests/Sources/AuthenticationCoordinatorUITests.swift b/UITests/Sources/AuthenticationCoordinatorUITests.swift index 90f4f4bd6..e18b66220 100644 --- a/UITests/Sources/AuthenticationCoordinatorUITests.swift +++ b/UITests/Sources/AuthenticationCoordinatorUITests.swift @@ -58,10 +58,13 @@ class AuthenticationCoordinatorUITests: XCTestCase { app.typeText("87654321") // Login Screen: Tap next - app.buttons["nextButton"].tap() + let nextButton = app.buttons["nextButton"] + XCTAssertTrue(nextButton.waitForExistence(timeout: 2.0)) + XCTAssertTrue(nextButton.isEnabled) + nextButton.tap() // Then login should fail. - XCTAssertTrue(app.alerts.element.waitForExistence(timeout: 1), "An error alert should be shown when attempting login with invalid credentials.") + XCTAssertTrue(app.alerts.element.waitForExistence(timeout: 2.0), "An error alert should be shown when attempting login with invalid credentials.") } func testSelectingOIDCServer() { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 2f63063fc..8c6072d97 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -73,7 +73,6 @@ lane :adhoc do end lane :tests do - run_tests( project: "ElementX.xcodeproj", scheme: "UnitTests" @@ -82,7 +81,7 @@ lane :tests do run_tests( project: "ElementX.xcodeproj", scheme: "UITests", - devices: ["iPhone 13 Pro Max (15.5)", "iPad (9th generation) (15.5)"], + devices: ["iPhone 13 Pro Max", "iPad (9th generation)"], ensure_devices_found: true, prelaunch_simulator: true, output_directory: "fastlane/test_output/", @@ -98,6 +97,14 @@ lane :tests do end +lane :integration_tests do + run_tests( + scheme: "IntegrationTests", + devices: ["iPhone 13 Pro"], + ensure_devices_found: true, + ) +end + private_lane :config_xcodegen_alpha do target_file_path = "../ElementX/SupportingFiles/target.yml" data = YAML.load_file target_file_path diff --git a/fastlane/README.md b/fastlane/README.md index 68c6de1b4..af59b057a 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -45,6 +45,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do +### integration_tests + +```sh +[bundle exec] fastlane integration_tests +``` + + + ---- This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. diff --git a/project.yml b/project.yml index e8ed162c1..52442dc63 100644 --- a/project.yml +++ b/project.yml @@ -12,7 +12,7 @@ options: iOS: "15.0" macOS: "12.0" groupOrdering: - - order: [ElementX, UnitTests, UITests, Tools] + - order: [ElementX, UnitTests, UITests, IntegrationTests, Tools] - pattern: ElementX order: [Sources, Resources, SupportingFiles] - pattern: Sources @@ -28,6 +28,7 @@ include: - path: ElementX/SupportingFiles/target.yml - path: UnitTests/SupportingFiles/target.yml - path: UITests/SupportingFiles/target.yml + - path: IntegrationTests/SupportingFiles/target.yml packages: MatrixRustSDK: @@ -64,5 +65,5 @@ packages: url: https://github.com/getsentry/sentry-cocoa majorVersion: 7.15.0 SnapshotTesting: - url: https://github.com/pointfreeco/swift-snapshot-testing.git + url: https://github.com/pointfreeco/swift-snapshot-testing majorVersion: 1.9.0