質問の歴史
プログレッシブWebアプリ(PWA)は、Service Workersを利用してネットワークリクエストをインターセプトし、オフラインで使用するためにアセットをキャッシュすることで、ネイティブアプリケーションとWebアプリケーションの境界をぼかします。初期のWebテスト手法は、継続的な接続を前提としましたが、現代のアプリケーションは、飛行機モードや地下鉄トンネル、農村部の接続不良エリアでも機能する必要があります。この進化は、クライアントサイドデータベース(IndexedDBなど)が一時的なバッファではなく、主要なデータソースとして機能するという、複雑な状態管理の課題を導入しました。これにより、ブラウザのストレージ回避ポリシーや非同期の同期キューを考慮した新しい検証アプローチが必要となります。
問題
従来の手動テストは、理想的なネットワーク条件下での機能検証に重点を置いており、キャッシュ更新中の競合条件や、Safariがストレージを消去したときの静かなデータ損失、あるいはデバイスのバッテリーを消耗させるBackground Sync APIにおける無限再試行ループなどの重要な失敗モードを見逃してしまうことがよくあります。テスターは、オフライン使用の「ハッピーパス」だけでなく、ネットワーク分断中に複数のデバイスインスタンスが同じカートやドキュメントを変更する際に発生するマージ競合を検証する必要があります。さらに、Service Workerのライフサイクル管理は、適切にトリガーされない限り更新が無期限に保留される可能性があり、ユーザーが古いアプリケーションバージョンに留まってしまうという独自の複雑さをもたらします。
解決策
包括的な方法論は、プログラム可能なネットワークプロキシを使用して、断続的な接続をシミュレートするマルチデバイステストシナリオを調整することが必要です。その際、Chrome DevToolsのApplicationパネルでService Workerの状態とIndexedDBの変更をモニタリングします。テスターは、デバイスの容量を人工的に満たしてQuotaExceededErrorハンドリングを引き起こす「ストレージプレッシャー」テストを実施し、Safariのインテリジェントトラッキング防止機能が重要なユーザーデータを早期にクリアしないことを確認するために、数日にわたる長寿命テストを行う必要があります。さらに、競合解決アルゴリズムを検証するには、複数のブラウザ間で同時のアクションを実行して、ChromeのBackground Sync実装とSafariのより制限されたストレージポリシーの間で運用の一貫性を確保する必要があります。
問題
あるeコマースのPWAは、ユーザーがモバイルとデスクトップデバイスの間を切り替えた後、あるいは商品カタログのキャッシュを更新できなかったアプリケーションの更新後に、ショッピングカートを失ったという sporadic な苦情を報告しました。調査の結果、Service WorkerがCacheStorageから古いHTMLシェルを提供しており、IndexedDBがカートの状態を保持していることが明らかとなりましたが、ユーザーがブラウザを強制終了した際にBackground Syncイベントがドロップされていたため、同期が行われていませんでした。この問題に加え、iOS Safariユーザーは、iOS 16での七日間の非アクティブ後に完全なデータ損失を経験しましたが、アプリケーションにはこの静かな排出を検出するフォールバックメカニズムが不足していました。
解決策 1: 孤立デバイステスト
このアプローチは、ネットワーク干渉なしに各デバイスを独立してクリーンなブラウザプロファイルで検証することを含みます。主な利点は、標準のブラウザDevToolsを利用した簡単な実行ができ、再現可能な手順を簡単に文書化できることです。しかし、この方法では、2つのクライアントが同時に競合するカートの変更を同期しようとする際のタイミング依存の競合条件をキャッチできず、実世界の使用パターンでのみ現れるSafariの独自のストレージ制約を完全に無視します。したがって、このアプローチは競合解決ロジックに関して誤ったネガティブを生み出すため、主な方法論としては却下されました。
解決策 2: 自動ネットワークスロットリング
自動ネットワークスロットリングは、PuppeteerまたはPlaywrightスクリプトを利用して、遅延を正確に制御しながらオフライン状態をプログラム的にシミュレートします。これにより、回帰テストの高い再現性が提供されますが、Safariの独自のストレージ回避ヒューリスティクスやユーザーが主導する「履歴を消去」アクションを再現することはできません。さらに、自動スクリプトは、低電力条件下でのBackground Syncのリトライバックオフのようなバッテリー関連の動作を逃すことがあります。このソリューションはスモークテストに採用されましたが、実際のデバイス制約をモデル化できないため、リリース認証には不十分と見なされました。
解決策 3: 制御された混沌の研究所
制御された混沌の研究所は、パケット損失を注入するためにLinuxのtcを実行するプログラム可能なWi-Fiルーターを搭載した物理デバイスタワーを確立します。これにより、ネットワーク分断とストレージプレッシャーの本物の複製ができ、Safariの実際のITP挙動を長期にわたりテストすることが可能です。また、2人のテスターが同時に同じカートアイテムを変更したときのリアルタイムの競合解決UIも検証します。リソース集約的ではありますが、これは、フレキシブルな接続中にBackground Syncが重複するチェックアウトリクエストをキューイングするという重要な欠陥を発見したため、選択されました。
結果
この方法論の実施に続いて、チームはカートのマージのための「最終更新」ベクトルクロックアルゴリズムを導入し、全デバイスで「同期保留中」バッジを表示しました。そして、リトライしたBackground Syncイベントからの重複課金を防ぐために、サーバーサイドの冪等性キーが導入されました。展開後、カート放棄率が40パーセント減少し、その後の高トラフィックイベントの間に重複した取引の苦情は0件でした。
ブラウザが古いバージョンを「待機」状態に保っているとき、Service Workerを強制的に更新するにはどうすればよいですか?
多くの候補者は、ページをリフレッシュする(F5)ことで新しいService Workerを即座にインストールできると考えていますが、実際には、ブラウザはすべてのタブが閉じられるまで古いワーカーをアクティブなままにして、バージョンの一貫性を確保しています。正しい手動テストには、Chrome DevToolsのApplication > Service Workersを開き、「待機をスキップ」をクリックして更新をシミュレートし、その後「activate」イベントが古いCacheStorageエントリをクリアしながらIndexedDBのユーザーデータを保持することを検証する必要があります。テスターはまた、「更新可能」というトーストが表示されることを確認し、ページがフォーム入力を失うことなくリロードされることを検証することで、ユーザーエクスペリエンスを検証する必要があります。このライフサイクルのニュアンスを見逃すと、新しいバージョンがアクティブであると信じながら、古いコードをテストすることになります。
Background SyncとPeriodic Background Syncのテストの違いは何ですか、なぜSafariの動作が異なるのですか?**
Background Syncは、接続が戻るまでチェックアウト送信などの個別アクションを遅延させ、ブラウザがネットワークを検出したときにすぐに発火しますが、一方でPeriodic Background Syncは、ユーザーのインタラクションなしにエンゲージメントヒューリスティクスに基づいてコンテンツを積極的に取得します。Background Syncをテストするには、Chrome DevToolsのネットワークを「オフライン」に設定し、そのアクションを実行し、接続を復元し、ApplicationパネルでSyncイベントが成功裏に完了するか、指数バックオフのリトライをするかを監視します。Periodic Background Syncでは、Chromeフラグを有効にし、サイトのエンゲージメントスコアを高くシミュレートする必要があり、プリフェッチが発生することを検証し、APIが利用できない場合にiOSが優雅に劣化することを保証する必要があります。候補者はしばしばこれらのAPIを混同したり、SafariがPeriodic Background Syncをサポートしていると仮定したりして、テストされていないフォールバックコードパスを引き起こします。
Safariのインテリジェントトラッキング防止機能がストレージを消去したとき、IndexedDBの動作をどのように検証しますか?**
SafariのITPは、クロスサイトトラッキングを防ぐため、ユーザーの非アクティブな期間が7日を超えると、スクリプト書き込み可能なストレージをクリアしますが、これはChromeには存在せず、システム時計を調整するか、WebKitデバッグAPIを使用しないとシミュレーションが難しい動作です。候補者はしばしばIndexedDBを単一のセッション内でのみテストし、「七日間の排出」シナリオを完全に見逃し、アプリが排出後にサーバーからデータを優雅に再取得することを検証できません。適切なテストには、排出を手動でトリガーし、その後アプリケーションが空のデータベース状態を処理する(適切なユーザーメッセージを表示し、エラーなくデータを再構築する)ことを確認する必要があります。さらに、QuotaExceededError例外がアプリケーションをクラッシュさせないように処理されることを確認するために、StorageManager.persist() APIリクエストをテストする必要があります。これはFirefoxでは永続的なストレージ権限の要求を促しますが、Safariでは異なる動作をするためです。