diff --git a/.claude/rules/prefire-preview.md b/.claude/rules/prefire-preview.md index ea001f134..942facda6 100644 --- a/.claude/rules/prefire-preview.md +++ b/.claude/rules/prefire-preview.md @@ -41,6 +41,8 @@ import Prefire `.prefire.yml` の `testable_imports`(Feature系モジュール)または `imports`(`HometeDomain` など)に列挙されていないモジュールのViewは、生成されたテストから参照できない。 +逆に、そのモジュールの `#Preview` が**すべて `.prefireIgnored()` 付き**なら登録は不要。Prefireは無視されたプレビューを生成コードへ展開しないため、上記1・3のどちらにも触れない(`make check-previews` も `.prefireIgnored()` の付いたブロックは検査しない)。`AppRoot` が実例で、VRT専用ホスト `hometeVRTHost` にFirebaseを引き込まないよう`.prefire.yml` から外してある([ADR-0029](../../doc/adr/0029-vrt-dedicated-host-app-target.md))。`AppRoot` 配下にスナップショットを撮りたいViewを足したくなったら、`HometeUI` かFeature配下へ移すこと。 + ### 4. `contextMenu` / `alert` / `sheet` など提示系モディファイアはPreviewでラップしない VRT(Prefireのスナップショット撮影)は画面を静的にレンダリングするだけなので、`.contextMenu { }` の中身、`.alert(...)`、`.sheet(...)` のように**ユーザー操作(長押し・ボタンタップなど)をトリガーに表示される内容はスナップショットに映らない**。これらでラップした`#Preview`を書いても、実際にはラップの外側(何もトリガーしていない状態の画面)しか撮影されず、中身の見た目はVRTで一切検証できない。 diff --git a/.gitignore b/.gitignore index 519e0472f..548e86f42 100644 --- a/.gitignore +++ b/.gitignore @@ -88,7 +88,7 @@ scripts/appstoreconnect.env Build/ # Prefire generated test file -hometeSnapshotTests/PreviewTests.generated.swift +hometeSnapshotTests/Sources/PreviewTests.generated.swift # Xcode Cloud (machine-local manifest) **/xcshareddata/xcodecloud/ diff --git a/.prefire.yml b/.prefire.yml index f80a12409..e99a96093 100644 --- a/.prefire.yml +++ b/.prefire.yml @@ -1,13 +1,12 @@ test_configuration: - - target: homete - - test_target_path: ${PROJECT_DIR}/hometeSnapshotTests + - target: hometeVRTHost + - test_target_path: ${PROJECT_DIR}/hometeSnapshotTests/Sources - simulator_device: "iPhone17,3" - required_os: 27 - preview_default_enabled: true - template_file_path: generateTestTemplate.stencil - use_grouped_snapshots: true - sources: - - ${PROJECT_DIR}/homete/Views - ${PROJECT_DIR}/LocalPackage/Sources - snapshot_devices: - iPhone 16 @@ -20,7 +19,6 @@ test_configuration: - HometeResources - testable_imports: - HometeUI - - AppRoot - AuthFeature - SettingFeature - HomeFeature diff --git a/CLAUDE.md b/CLAUDE.md index b476aef7b..e945212df 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -212,7 +212,9 @@ launching → notLoggedIn → Sign In with Apple **スナップショットテスト** (`hometeSnapshotTests/`): - ライブラリ: PointFreeのswift-snapshot-testing 1.18.7 - テストプラン: `snapshotTesting.xctestplan`(言語は`-AppleLanguages (ja)`で日本語固定) -- Prefire連携(`.prefire.yml`)でプレビューからテストを生成。対象ソースは `homete/Views` と `LocalPackage/Sources` +- Prefire連携(`.prefire.yml`)でプレビューからテストを生成。対象ソースは `LocalPackage/Sources` +- テストホストはVRT専用の空アプリ `hometeVRTHost`。Firebase/AdMob/RevenueCatをビルドしないためのもの([ADR-0029](doc/adr/0029-vrt-dedicated-host-app-target.md))。描画対象のモジュールは `hometeSnapshotTests` が直接リンクするので、Featureを追加したら `.prefire.yml` の `testable_imports` とテストターゲットのリンク設定の両方を更新する +- `AppRoot` はVRT対象外。スナップショットを撮りたいViewは `HometeUI` かFeature配下に置く - 収録デバイス: iPhone 16 / iPhone SE (2nd generation)、必要OS: 27 - CI上で失敗時は`Build/VRT/SnapshotsFailures`にアップロード @@ -267,6 +269,7 @@ launching → notLoggedIn → Sign In with Apple 1. **`VRT`** - スナップショットテスト - `ci_post_clone.sh`: SPMプラグイン検証スキップ + スナップショット参照ファイル確認 + - スキームは `hometeSnapshotTests`(`homete` スキームだとアプリ本体がビルドされ高速化の効果が出ない) 2. **`Upload Stg TestFlight`** - Stg環境TestFlightアップロード - `ci_post_clone.sh`: `GOOGLESERVICE_INFO` 環境変数から `homete/GoogleService-Info-dev.plist` をデコード配置 diff --git a/LocalPackage/Sources/AppRoot/LaunchScreenView.swift b/LocalPackage/Sources/HometeUI/Components/LaunchScreenView.swift similarity index 73% rename from LocalPackage/Sources/AppRoot/LaunchScreenView.swift rename to LocalPackage/Sources/HometeUI/Components/LaunchScreenView.swift index 043a19024..a30ab592e 100644 --- a/LocalPackage/Sources/AppRoot/LaunchScreenView.swift +++ b/LocalPackage/Sources/HometeUI/Components/LaunchScreenView.swift @@ -1,15 +1,18 @@ // // LaunchScreenView.swift +// LocalPackage // import HometeDomain import HometeResources -import HometeUI import SwiftUI -struct LaunchScreenView: View { +/// 起動状態の判定が終わるまで表示する、アプリ名とアイコンだけの画面 +public struct LaunchScreenView: View { - var body: some View { + public init() {} + + public var body: some View { VStack(spacing: .space16) { Text("Homete") .font(with: .headLineL) diff --git a/ci_scripts/ci_post_clone.sh b/ci_scripts/ci_post_clone.sh index bac93a9d4..93abe515f 100755 --- a/ci_scripts/ci_post_clone.sh +++ b/ci_scripts/ci_post_clone.sh @@ -19,17 +19,9 @@ case "$CI_WORKFLOW" in "VRT") echo "=== VRT workflow ===" - # 開発用xcconfig(AdMob/RevenueCat設定)をsecretからデコードして配置 - # Info.plistのGADApplicationIdentifierがDebug構成のSAMPLE_APP_ID設定を参照しており、 - # このファイルが無いと未定義のままとなる。Google Mobile Ads SDKはリンクされているだけで - # 起動後にApplication IDの妥当性を検証し、無効だとGADInvalidInitializationExceptionで - # クラッシュするため、テストのbootstrapping中に落ちる原因になる - if [ -z "$SECRET_XCCONFIG_DEV" ]; then - echo "ERROR: SECRET_XCCONFIG_DEV environment variable is not set" - exit 1 - fi - echo "$SECRET_XCCONFIG_DEV" | base64 --decode > "$CI_PRIMARY_REPOSITORY_PATH/homete/Resouces/Secret_dev.xcconfig" - echo "✓ Secret_dev.xcconfig decoded and placed" + # Secret_dev.xcconfigのデコードは不要。テストホストをhometeVRTHostに切り替えたことで + # Google Mobile Ads SDKがリンクされなくなり、GADApplicationIdentifier未定義による + # 起動時クラッシュ(GADInvalidInitializationException)が起きなくなったため。 # スナップショット参照ファイルの確認 SNAPSHOT_DIR="$CI_PRIMARY_REPOSITORY_PATH/hometeSnapshotTests/__Snapshots__/PreviewTests.generated" diff --git a/doc/adr/0029-vrt-dedicated-host-app-target.md b/doc/adr/0029-vrt-dedicated-host-app-target.md new file mode 100644 index 000000000..202430ed9 --- /dev/null +++ b/doc/adr/0029-vrt-dedicated-host-app-target.md @@ -0,0 +1,147 @@ +## タイトル: VRT専用のホストアプリターゲットを用意してスナップショットテストのビルド時間を削る + +* **承認済** +* 意思決定者: stotic-dev +* 日付: 2026-09-30 +* 関連: [ADR-0001](0001-spm-multimodule-structure.md) + +## 文脈、背景や問題点の説明 + +VRT(Prefire + swift-snapshot-testing)のテストホストが`homete`アプリターゲットだったため、 +スナップショットを1枚撮るためだけに `AppRoot → HometeInfrastructure → firebase-ios-sdk / +GoogleMobileAds / RevenueCat` の全体をビルドする必要があった。firebase-ios-sdkはSPM経由だと +gRPC・abseil・leveldbをソースからビルドするため、Xcode Cloudの`VRT`ワークフローの所要時間の +大半がスナップショットと無関係なコンパイルに費やされていた。 + +一方、スナップショット対象のViewが属する`Features` / `HometeUI` / `HometeDomain` / +`HometeResources` は、`LocalPackage/Package.swift` 上でこれらのライブラリに一切依存していない。 + +## 決定事項 + +* スナップショットテスト専用のアプリターゲット `hometeVRTHost` を `homete.xcodeproj` に追加し、 + `hometeSnapshotTests` の `TEST_HOST` / `BUNDLE_LOADER` をこちらへ向ける +* `hometeVRTHost` は key window を用意するだけの空の`App`とし、LocalPackageには依存させない +* 描画対象のモジュール(HometeDomain / HometeResources / HometeUI と各Feature)は + `hometeSnapshotTests` 側が直接リンクする +* `AppRoot` はVRTの対象から外す。唯一スナップショットを持っていた `LaunchScreenView` は + `HometeUI` へ移動して維持する(`AppTabView`のプレビューは`.prefireIgnored()`済み) + +### ホストではなくテストバンドルにリンクさせた理由 + +`@testable import`したシンボルをホストアプリ経由(`-bundle_loader`)で解決させる場合、 +ホストが参照していないオブジェクトファイルは静的リンク時に取り込まれない可能性がある。 +従来は`AppRoot`が全Featureを実際に使っていたため成立していたが、空のホストでは成立が保証できない。 +テストバンドル側でリンクすれば、Prefireが生成するテストコードが各プレビューを明示的に参照するため、 +必要なシンボルは必ず取り込まれる。 + +### ローカライズの扱い + +`homete.app` は `Localizable.xcstrings` のコンパイル結果として `ja.lproj` を持つため、 +`-AppleLanguages (ja)` を渡すと `Locale.current` が ja に解決される。`hometeVRTHost` は +文字列カタログを持たないので、`Info.plist` の `CFBundleLocalizations` で `ja` / `en` を明示して +同じ状態を作る。既存の `Localizable.xcstrings` は全エントリが `stale` かつ訳文がキーと同一で、 +表示される文字列には影響しない。 + +## 考慮した選択肢 + +* **VRT専用のホストアプリターゲットを追加する(採用)** +* **VRT専用に別プロジェクト(`.xcodeproj`)を切る** — ビルドされるのはスキームの依存グラフ内だけなので + 高速化の効果は同じである一方、`.xcworkspace` の新設とXcode Cloud側の設定変更が増える +* **Xcode 27.2のJSONプロジェクト形式(`project.xcproj`)で新規プロジェクトを作る** — 作成・変換に + Xcode 27.2が必要で、2026-09-30時点ではbeta(安定版は27.0)。Xcode CloudやCocoaPods/Xcodeproj・ + tuist/XcodeProjなど周辺ツールの対応も揃っていないため見送る。安定版が出た時点で + プロジェクト全体の変換として別途検討する +* **現状維持(hometeをホストのまま使う)** + +## 決定結果 + +### 決定にあたり考慮したメリット + +* VRTの依存グラフから firebase-ios-sdk / GoogleMobileAds / RevenueCat のコンパイル・リンクが外れる +* `ci_scripts/ci_post_clone.sh` の`VRT`分岐で `Secret_dev.xcconfig` をデコードする必要がなくなる。 + これはGoogle Mobile Ads SDKがリンクされているせいで `GADApplicationIdentifier` 未定義だと + 起動時にクラッシュするための回避策だった +* VRTがFirebase設定・広告設定の状態に左右されなくなり、失敗の原因がUIの差分に絞られる + +### 決定にあたり考慮したデメリット + +* アプリターゲットが1つ増え、`homete` と `hometeVRTHost` でビルド設定の二重管理が生じる。 + ただしVRTホストが持つのは起動に最低限必要な設定のみで、機能追加に伴う変更は基本的に発生しない +* スナップショット対象のモジュールを増やしたときに、`.prefire.yml` の `testable_imports` と + `hometeSnapshotTests` のリンク設定の両方を更新する必要がある +* `AppRoot` 配下のViewはVRTの対象外になる。対象にしたい場合は `HometeUI` か Feature へ移す + +### 前提 + +* SPMのパッケージ「解決」は `LocalPackage/Package.swift` の `dependencies` 全件に対して走るため、 + firebase-ios-sdk などの取得時間自体は残る。ここまで削るには `HometeInfrastructure` を + 別パッケージへ切り出す必要があり、本ADRの範囲外とする +* Xcode Cloudの`VRT`ワークフローが `hometeSnapshotTests` スキームを使っていることが前提。 + `homete` スキームを使っている場合は `homete.app` がビルドされ続けるため効果が出ない + +## 実測結果(2026-09-30) + +Xcode Cloud の `VRT` ワークフローで比較した(変更前 Build 548 / 変更後 Build 559)。 + +| | 変更前 | 変更後 | +|---|---|---| +| ビルドしたターゲット数 | 105 | **19** | +| ビルド(build-for-testing) | 80秒 | **40秒** | +| パッケージ解決 | 62秒 | 62秒 | +| テスト成果物(TEST_PRODUCTS) | 76.6 MiB | **26.4 MiB** | +| アクション間の受け渡し | 88秒 | **72秒** | +| テスト実行(220テスト)× 2 | — | 74.0秒 / 73.1秒 | +| テスト1回あたりの起動オーバーヘッド | 42.7秒 | 44.9秒 | +| VRT全体 | 11分34秒 | **9分46秒** | + +Firebase・gRPC・abseil・BoringSSL・leveldb・GoogleMobileAds・RevenueCat・AppRoot・ +HometeInfrastructure がビルド対象から完全に消えた。 + +ただし**Xcode Cloud上での短縮幅は限定的**だった。Xcode Cloud はビルド成果物をキャッシュして +いるため、Firebaseのビルドは変更前でも80秒しかかかっていない。当初想定した「Firebaseの +コンパイルが支配的」はXcode Cloudには当てはまらない。 + +一方**ローカルでは効果が大きい**。キャッシュが無い状態では gRPC・abseil・leveldb を +ソースからビルドし直すため、その分が丸ごと消える。ローカル実測は `build-for-testing` が +コールドで69秒、テストバンドル29MB。 + +### 参照スナップショットをテストバンドルへコピーしない方法 + +`hometeSnapshotTests/__Snapshots__` の参照PNG 61MB が `.xctest` バンドルへコピーされていた +(`CopyPNGFile` 884件)。参照画像はバンドルから読まれないため完全な死荷重で、テスト成果物を +76.6 MiB に膨らませ、build-for-testing → test-without-building の受け渡しを重くしていた。 + +**Xcode 27では、file-system synchronized group 配下のリソースに対して次の2つはどちらも効かない** +(Build 553 / 554 で実測。`CopyPNGFile` が884件のまま、成果物サイズも変化なし)。 + +- `PBXFileSystemSynchronizedBuildFileExceptionSet` の `membershipExceptions` にディレクトリ名を並べる +- テストターゲットの `EXCLUDED_SOURCE_FILE_NAMES` にパターンを指定する(ビルドログに痕跡すら出ない) + +効いたのは**同期グループの範囲自体を狭める**方法。グループの `path` を +`hometeSnapshotTests/Sources` にして、`__Snapshots__` をグループの外に出す。 + +`__Snapshots__` の場所は動かしていないので、`ci_scripts/__Snapshots__` のシンボリックリンク、 +`ci_scripts/*.sh` のパス、`DangerTools/Dangerfile.swift` の参照先はいずれも変更不要。 +884ファイルを `git mv` する案を採らなかったのは、`danger.git.createdFiles` にリネーム先が +全件入り、Dangerが before/after 画像表を884個投稿してしまうため。 + +生成ファイルが `Sources/` 配下へ移ることで `verifySnapshot` のデフォルト(`#filePath` 基準の +`__Snapshots__`)が `Sources/__Snapshots__` を指してしまうので、stencilの +`snapshotDirectoryOverride` をローカルでも明示的に返すようにした。 + +### テストの二重実行は意図的なもの + +VRTはスナップショットテストを2回実行する([ADR-0005](0005-vrt-snapshot-recording-on-xcode-cloud.md))。 +1回目は `ci_post_xcodebuild.sh` 内の record モードで参照を更新してコミットし、2回目のXcode Cloud +公式アクションが記録済みの参照と突き合わせて検証する。**1回目と2回目で描画が揺れるフレーキーな +スナップショットをここで落とせる**ため、実行時間の短縮を理由に一本化してはならない。 + +テスト1回あたり「起動オーバーヘッド約45秒 + テスト実行約74秒」がかかり、これが2回分ある。 +起動オーバーヘッドはテストバンドルを76.6 MiB→26.4 MiB に縮めても変わらなかった +(42.7秒→44.9秒)ので、`xcodebuild test-without-building` の固定コストであり、 +ローカルでも同じ35〜45秒が再現する。 + +## 参考 + +* [Xcodeの新しいJSONプロジェクト形式(Sarunw)](https://sarunw.com/posts/xcode-json-project-format-xcproj/) +* [Xcode 27.2 Beta Release Notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-27_2-release-notes) diff --git a/homete.xcodeproj/project.pbxproj b/homete.xcodeproj/project.pbxproj index 21b332bcf..2164b8f3c 100644 --- a/homete.xcodeproj/project.pbxproj +++ b/homete.xcodeproj/project.pbxproj @@ -7,6 +7,17 @@ objects = { /* Begin PBXBuildFile section */ + 0AA7C0030000000000000001 /* HometeDomain in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000001 /* HometeDomain */; }; + 0AA7C0030000000000000002 /* HometeResources in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000002 /* HometeResources */; }; + 0AA7C0030000000000000003 /* HometeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000003 /* HometeUI */; }; + 0AA7C0030000000000000004 /* AuthFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000004 /* AuthFeature */; }; + 0AA7C0030000000000000005 /* SettingFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000005 /* SettingFeature */; }; + 0AA7C0030000000000000006 /* HomeFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000006 /* HomeFeature */; }; + 0AA7C0030000000000000007 /* CohabitantRegistrationFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000007 /* CohabitantRegistrationFeature */; }; + 0AA7C0030000000000000008 /* HouseworkFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000008 /* HouseworkFeature */; }; + 0AA7C0030000000000000009 /* HouseworkTemplateFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C0020000000000000009 /* HouseworkTemplateFeature */; }; + 0AA7C003000000000000000A /* ContributionFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C002000000000000000A /* ContributionFeature */; }; + 0AA7C003000000000000000B /* FrequentHouseworkFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 0AA7C002000000000000000B /* FrequentHouseworkFeature */; }; 04FD07792F77AEA500BEC61C /* ProjectToolsDummy in Frameworks */ = {isa = PBXBuildFile; productRef = 04FD07782F77AEA500BEC61C /* ProjectToolsDummy */; }; 2E7BCD045508457FA0F6004C /* AppRoot in Frameworks */ = {isa = PBXBuildFile; productRef = 5735E0CC5DF34B1AADF7A805 /* AppRoot */; }; 6E0DD1334786A0EFEF7B2E47 /* hometeNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DE93ECCD98AD81DE182613EE /* hometeNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -20,19 +31,19 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 60F89D8D56005D278633B0D3 /* PBXContainerItemProxy */ = { + 0AA7C001000000000000000B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BCC853ED2DB74BBC00C9A44B /* Project object */; proxyType = 1; - remoteGlobalIDString = B95D5CAD873C0B6430B379E3; - remoteInfo = hometeNotificationService; + remoteGlobalIDString = 0AA7C0010000000000000001; + remoteInfo = hometeVRTHost; }; - BC1BB26C2E909B8C001D168F /* PBXContainerItemProxy */ = { + 60F89D8D56005D278633B0D3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BCC853ED2DB74BBC00C9A44B /* Project object */; proxyType = 1; - remoteGlobalIDString = BCC853F42DB74BBC00C9A44B; - remoteInfo = homete; + remoteGlobalIDString = B95D5CAD873C0B6430B379E3; + remoteInfo = hometeNotificationService; }; /* End PBXContainerItemProxy section */ @@ -51,6 +62,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0AA7C0010000000000000006 /* hometeVRTHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = hometeVRTHost.app; sourceTree = BUILT_PRODUCTS_DIR; }; 04B371962F404CBF00820C62 /* LocalPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = LocalPackage; sourceTree = ""; }; 04B7862D2F4C11800080EFAC /* hometeSnapshotTestsForCI.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = hometeSnapshotTestsForCI.xctestplan; sourceTree = ""; }; BC1BB2682E909B8C001D168F /* hometeSnapshotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = hometeSnapshotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -62,7 +74,14 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 04B7923F2F525C2D0080EFAC /* Exceptions for "hometeSnapshotTests" folder in "hometeSnapshotTests" target */ = { + 0AA7C001000000000000000D /* Exceptions for "hometeVRTHost" folder in "hometeVRTHost" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 0AA7C0010000000000000001 /* hometeVRTHost */; + }; + 04B7923F2F525C2D0080EFAC /* Exceptions for "Sources" folder in "hometeSnapshotTests" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, @@ -86,12 +105,20 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - BC1BB2692E909B8C001D168F /* hometeSnapshotTests */ = { + 0AA7C0010000000000000005 /* hometeVRTHost */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - 04B7923F2F525C2D0080EFAC /* Exceptions for "hometeSnapshotTests" folder in "hometeSnapshotTests" target */, + 0AA7C001000000000000000D /* Exceptions for "hometeVRTHost" folder in "hometeVRTHost" target */, ); - path = hometeSnapshotTests; + path = hometeVRTHost; + sourceTree = ""; + }; + BC1BB2692E909B8C001D168F /* Sources */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 04B7923F2F525C2D0080EFAC /* Exceptions for "Sources" folder in "hometeSnapshotTests" target */, + ); + path = hometeSnapshotTests/Sources; sourceTree = ""; }; BCC853F72DB74BBC00C9A44B /* homete */ = { @@ -113,6 +140,13 @@ /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + 0AA7C0010000000000000003 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 82B9616C86F1F0A719049764 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -128,6 +162,17 @@ files = ( BC4701FB2E9A0F3D006CC530 /* Prefire in Frameworks */, BC1BB2722E909B99001D168F /* SnapshotTesting in Frameworks */, + 0AA7C0030000000000000001 /* HometeDomain in Frameworks */, + 0AA7C0030000000000000002 /* HometeResources in Frameworks */, + 0AA7C0030000000000000003 /* HometeUI in Frameworks */, + 0AA7C0030000000000000004 /* AuthFeature in Frameworks */, + 0AA7C0030000000000000005 /* SettingFeature in Frameworks */, + 0AA7C0030000000000000006 /* HomeFeature in Frameworks */, + 0AA7C0030000000000000007 /* CohabitantRegistrationFeature in Frameworks */, + 0AA7C0030000000000000008 /* HouseworkFeature in Frameworks */, + 0AA7C0030000000000000009 /* HouseworkTemplateFeature in Frameworks */, + 0AA7C003000000000000000A /* ContributionFeature in Frameworks */, + 0AA7C003000000000000000B /* FrequentHouseworkFeature in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -160,8 +205,9 @@ BC7469462DBCBE71007E4222 /* PrivacyInfo.xcprivacy */, BC5204662DB7BEFD0097472D /* homete.xctestplan */, BCC853F72DB74BBC00C9A44B /* homete */, - BC1BB2692E909B8C001D168F /* hometeSnapshotTests */, + BC1BB2692E909B8C001D168F /* Sources */, F8D395659848FE53C42FCA71 /* hometeNotificationService */, + 0AA7C0010000000000000005 /* hometeVRTHost */, BCB8DB162E37B3F900FFB4E1 /* Frameworks */, BCC853F62DB74BBC00C9A44B /* Products */, ); @@ -173,6 +219,7 @@ BCC853F52DB74BBC00C9A44B /* homete.app */, BC1BB2682E909B8C001D168F /* hometeSnapshotTests.xctest */, DE93ECCD98AD81DE182613EE /* hometeNotificationService.appex */, + 0AA7C0010000000000000006 /* hometeVRTHost.app */, ); name = Products; sourceTree = ""; @@ -180,6 +227,28 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 0AA7C0010000000000000001 /* hometeVRTHost */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0AA7C0010000000000000007 /* Build configuration list for PBXNativeTarget "hometeVRTHost" */; + buildPhases = ( + 0AA7C0010000000000000002 /* Sources */, + 0AA7C0010000000000000003 /* Frameworks */, + 0AA7C0010000000000000004 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 0AA7C0010000000000000005 /* hometeVRTHost */, + ); + name = hometeVRTHost; + packageProductDependencies = ( + ); + productName = hometeVRTHost; + productReference = 0AA7C0010000000000000006 /* hometeVRTHost.app */; + productType = "com.apple.product-type.application"; + }; B95D5CAD873C0B6430B379E3 /* hometeNotificationService */ = { isa = PBXNativeTarget; buildConfigurationList = FE3760CC2E7AA66E0ECA1415 /* Build configuration list for PBXNativeTarget "hometeNotificationService" */; @@ -216,15 +285,26 @@ ); dependencies = ( 04B783712F4996860080EFAC /* PBXTargetDependency */, - BC1BB26D2E909B8C001D168F /* PBXTargetDependency */, + 0AA7C001000000000000000C /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - BC1BB2692E909B8C001D168F /* hometeSnapshotTests */, + BC1BB2692E909B8C001D168F /* Sources */, ); name = hometeSnapshotTests; packageProductDependencies = ( BC1BB2712E909B99001D168F /* SnapshotTesting */, BC4701FA2E9A0F3D006CC530 /* Prefire */, + 0AA7C0020000000000000001 /* HometeDomain */, + 0AA7C0020000000000000002 /* HometeResources */, + 0AA7C0020000000000000003 /* HometeUI */, + 0AA7C0020000000000000004 /* AuthFeature */, + 0AA7C0020000000000000005 /* SettingFeature */, + 0AA7C0020000000000000006 /* HomeFeature */, + 0AA7C0020000000000000007 /* CohabitantRegistrationFeature */, + 0AA7C0020000000000000008 /* HouseworkFeature */, + 0AA7C0020000000000000009 /* HouseworkTemplateFeature */, + 0AA7C002000000000000000A /* ContributionFeature */, + 0AA7C002000000000000000B /* FrequentHouseworkFeature */, ); productName = hometeSnapshotTests; productReference = BC1BB2682E909B8C001D168F /* hometeSnapshotTests.xctest */; @@ -274,11 +354,14 @@ }; BC1BB2672E909B8C001D168F = { CreatedOnToolsVersion = 26.0; - TestTargetID = BCC853F42DB74BBC00C9A44B; + TestTargetID = 0AA7C0010000000000000001; }; BCC853F42DB74BBC00C9A44B = { CreatedOnToolsVersion = 16.3; }; + 0AA7C0010000000000000001 = { + CreatedOnToolsVersion = 27.0; + }; }; }; buildConfigurationList = BCC853F02DB74BBC00C9A44B /* Build configuration list for PBXProject "homete" */; @@ -306,11 +389,19 @@ BCC853F42DB74BBC00C9A44B /* homete */, BC1BB2672E909B8C001D168F /* hometeSnapshotTests */, B95D5CAD873C0B6430B379E3 /* hometeNotificationService */, + 0AA7C0010000000000000001 /* hometeVRTHost */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 0AA7C0010000000000000004 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 12804B26EC8EB4A8AFC8A8AC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -364,6 +455,13 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 0AA7C0010000000000000002 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 04A98FB34612E2DC2FDF7D06 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -388,6 +486,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 0AA7C001000000000000000C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0AA7C0010000000000000001 /* hometeVRTHost */; + targetProxy = 0AA7C001000000000000000B /* PBXContainerItemProxy */; + }; 04B783712F4996860080EFAC /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = 04B783702F4996860080EFAC /* PrefireTestsPlugin */; @@ -401,14 +504,108 @@ target = B95D5CAD873C0B6430B379E3 /* hometeNotificationService */; targetProxy = 60F89D8D56005D278633B0D3 /* PBXContainerItemProxy */; }; - BC1BB26D2E909B8C001D168F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BCC853F42DB74BBC00C9A44B /* homete */; - targetProxy = BC1BB26C2E909B8C001D168F /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 0AA7C0010000000000000008 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 56LYVN6DMF; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = hometeVRTHost/Info.plist; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometekure.vrthost; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0AA7C0010000000000000009 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 56LYVN6DMF; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = hometeVRTHost/Info.plist; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometekure.vrthost; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 0AA7C001000000000000000A /* Stg */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 56LYVN6DMF; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = hometeVRTHost/Info.plist; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometekure.vrthost; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 6.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Stg; + }; 04B961F02FB8235200ECAB4B /* Stg */ = { isa = XCBuildConfiguration; buildSettings = { @@ -528,7 +725,7 @@ DEVELOPMENT_TEAM = 56LYVN6DMF; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = hometeSnapshotTests/Info.plist; + INFOPLIST_FILE = hometeSnapshotTests/Sources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometeSnapshotTests; @@ -543,7 +740,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/homete.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/homete"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hometeVRTHost.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hometeVRTHost"; }; name = Stg; }; @@ -631,7 +828,7 @@ DEVELOPMENT_TEAM = 56LYVN6DMF; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = hometeSnapshotTests/Info.plist; + INFOPLIST_FILE = hometeSnapshotTests/Sources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometeSnapshotTests; @@ -646,7 +843,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/homete.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/homete"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hometeVRTHost.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hometeVRTHost"; }; name = Debug; }; @@ -659,7 +856,7 @@ DEVELOPMENT_TEAM = 56LYVN6DMF; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = hometeSnapshotTests/Info.plist; + INFOPLIST_FILE = hometeSnapshotTests/Sources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = taichi.satou.hometeSnapshotTests; @@ -674,7 +871,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/homete.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/homete"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hometeVRTHost.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hometeVRTHost"; }; name = Release; }; @@ -944,6 +1141,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 0AA7C0010000000000000007 /* Build configuration list for PBXNativeTarget "hometeVRTHost" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0AA7C0010000000000000008 /* Debug */, + 0AA7C0010000000000000009 /* Release */, + 0AA7C001000000000000000A /* Stg */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; BC1BB26E2E909B8C001D168F /* Build configuration list for PBXNativeTarget "hometeSnapshotTests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1025,6 +1232,50 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 0AA7C0020000000000000001 /* HometeDomain */ = { + isa = XCSwiftPackageProductDependency; + productName = HometeDomain; + }; + 0AA7C0020000000000000002 /* HometeResources */ = { + isa = XCSwiftPackageProductDependency; + productName = HometeResources; + }; + 0AA7C0020000000000000003 /* HometeUI */ = { + isa = XCSwiftPackageProductDependency; + productName = HometeUI; + }; + 0AA7C0020000000000000004 /* AuthFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = AuthFeature; + }; + 0AA7C0020000000000000005 /* SettingFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = SettingFeature; + }; + 0AA7C0020000000000000006 /* HomeFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = HomeFeature; + }; + 0AA7C0020000000000000007 /* CohabitantRegistrationFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = CohabitantRegistrationFeature; + }; + 0AA7C0020000000000000008 /* HouseworkFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = HouseworkFeature; + }; + 0AA7C0020000000000000009 /* HouseworkTemplateFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = HouseworkTemplateFeature; + }; + 0AA7C002000000000000000A /* ContributionFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = ContributionFeature; + }; + 0AA7C002000000000000000B /* FrequentHouseworkFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = FrequentHouseworkFeature; + }; 04B783702F4996860080EFAC /* PrefireTestsPlugin */ = { isa = XCSwiftPackageProductDependency; package = BC4701F92E9A0F3D006CC530 /* XCRemoteSwiftPackageReference "Prefire" */; diff --git a/hometeSnapshotTests/Info.plist b/hometeSnapshotTests/Sources/Info.plist similarity index 100% rename from hometeSnapshotTests/Info.plist rename to hometeSnapshotTests/Sources/Info.plist diff --git a/hometeSnapshotTests/generateTestTemplate.stencil b/hometeSnapshotTests/Sources/generateTestTemplate.stencil similarity index 90% rename from hometeSnapshotTests/generateTestTemplate.stencil rename to hometeSnapshotTests/Sources/generateTestTemplate.stencil index eeae7d5a6..87c84e6d0 100644 --- a/hometeSnapshotTests/generateTestTemplate.stencil +++ b/hometeSnapshotTests/Sources/generateTestTemplate.stencil @@ -29,13 +29,24 @@ import SnapshotTesting #endif /// Xcode Cloud では CI_PRIMARY_REPOSITORY_PATH 配下の ci_scripts/__Snapshots__ を参照する。 - /// ローカル開発では nil を返し、verifySnapshot のデフォルト(#file 基準)を使用する。 + /// + /// ローカルでも明示的に指定する。参照PNGは hometeSnapshotTests/__Snapshots__ にあるが、 + /// この生成ファイルは hometeSnapshotTests/Sources/ に置かれるため、verifySnapshot の + /// デフォルト(#filePath 基準の __Snapshots__)だと Sources/__Snapshots__ を見てしまい、 + /// 参照PNGを二重に作ってしまう。__Snapshots__ を Sources/ の外に出しているのは、 + /// テストターゲットの同期グループに含めて .xctest バンドルへ61MBのPNGをコピーさせない + /// ためである(doc/adr/0029)。 private var snapshotDirectoryOverride: String? { - guard ProcessInfo.processInfo.environment["CI_XCODE_CLOUD"] == "TRUE", - let repositoryPath = ProcessInfo.processInfo.environment["CI_PRIMARY_REPOSITORY_PATH"] else { - return nil + if ProcessInfo.processInfo.environment["CI_XCODE_CLOUD"] == "TRUE", + let repositoryPath = ProcessInfo.processInfo.environment["CI_PRIMARY_REPOSITORY_PATH"] { + return "\(repositoryPath)/ci_scripts/__Snapshots__" } - return "\(repositoryPath)/ci_scripts/__Snapshots__" + return URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .appendingPathComponent("__Snapshots__") + .appendingPathComponent("PreviewTests.generated") + .path } /// 参照PNGを再記録する専用ワークフロー(doc/adr/0005)でのみ SNAPSHOT_TESTING_RECORD が diff --git a/hometeSnapshotTestsForCI.xctestplan b/hometeSnapshotTestsForCI.xctestplan index 54240996b..57f6a5af8 100644 --- a/hometeSnapshotTestsForCI.xctestplan +++ b/hometeSnapshotTestsForCI.xctestplan @@ -33,8 +33,8 @@ ], "targetForVariableExpansion" : { "containerPath" : "container:homete.xcodeproj", - "identifier" : "BCC853F42DB74BBC00C9A44B", - "name" : "homete" + "identifier" : "0AA7C0010000000000000001", + "name" : "hometeVRTHost" } }, "testTargets" : [ diff --git a/hometeVRTHost/HometeVRTHostApp.swift b/hometeVRTHost/HometeVRTHostApp.swift new file mode 100644 index 000000000..75f1a8660 --- /dev/null +++ b/hometeVRTHost/HometeVRTHostApp.swift @@ -0,0 +1,24 @@ +// +// HometeVRTHostApp.swift +// hometeVRTHost +// + +import SwiftUI + +/// VRT(スナップショットテスト)専用のホストアプリ。 +/// +/// 描画対象のViewはhometeSnapshotTests側がLocalPackageの各モジュールを直接リンクして持つ。 +/// このターゲットはkey windowを用意するためだけに存在し、LocalPackageには一切依存しない。 +/// +/// hometeアプリをホストにすると AppRoot → HometeInfrastructure 経由で +/// Firebase / AdMob / RevenueCat のビルドが丸ごと必要になり、VRTの実行時間を押し上げる。 +@main +struct HometeVRTHostApp: App { + + var body: some Scene { + WindowGroup { + EmptyView() + } + } + +} diff --git a/hometeVRTHost/Info.plist b/hometeVRTHost/Info.plist new file mode 100644 index 000000000..62e157e16 --- /dev/null +++ b/hometeVRTHost/Info.plist @@ -0,0 +1,18 @@ + + + + + + CFBundleDevelopmentRegion + en + CFBundleLocalizations + + en + ja + + UIDesignRequiresCompatibility + + + diff --git a/scripts/check-prefire-previews.py b/scripts/check-prefire-previews.py index 2ecbd3560..0c789831c 100755 --- a/scripts/check-prefire-previews.py +++ b/scripts/check-prefire-previews.py @@ -85,12 +85,19 @@ def collect_inaccessible_symbols(lines: list[str]) -> dict[str, int]: def collect_preview_blocks(lines: list[str]) -> list[tuple[int, int]]: + """`.prefireIgnored()`が付いていない`#Preview`ブロックの範囲を返す。 + + `.prefireIgnored()`が付いたプレビューはPrefireが生成コードへ展開しないので、 + モジュールが`.prefire.yml`に未登録でも、private/fileprivateなシンボルを + 参照していても、VRTのビルドは壊れない。 + """ blocks: list[tuple[int, int]] = [] index = 0 while index < len(lines): if lines[index].lstrip().startswith("#Preview"): end = find_block_end(lines, index) - blocks.append((index, end)) + if not any(".prefireIgnored()" in line for line in lines[index:end + 1]): + blocks.append((index, end)) index = end + 1 continue index += 1 diff --git a/snapshotTesting.xctestplan b/snapshotTesting.xctestplan index a4af4d701..480ffca1b 100644 --- a/snapshotTesting.xctestplan +++ b/snapshotTesting.xctestplan @@ -19,8 +19,8 @@ ], "targetForVariableExpansion" : { "containerPath" : "container:homete.xcodeproj", - "identifier" : "BCC853F42DB74BBC00C9A44B", - "name" : "homete" + "identifier" : "0AA7C0010000000000000001", + "name" : "hometeVRTHost" }, "testTimeoutsEnabled" : true },