19 Oracle JETアプリケーションのテストおよびデバッグ

クライアント側アプリケーション用の推奨されるテストおよびデバッグ・ツール・セットを使用して、Oracle JET Webアプリケーションをテストしてデバッグします。

Oracle JETアプリケーションのテスト

テストは、回帰を防ぎ、テスト可能な関数、モジュール、クラスおよびコンポーネントで構成されるアプリケーションの作成を促すことによって、複雑なOracle JETアプリケーションを迅速かつ確実に構築するのに役立ちます。

アプリケーションの開発サイクルで、できるだけ早くテストを記述することをお薦めします。テストを遅らせるほど、アプリケーションの依存関係が増え、テストを開始するのが難しくなります。

テスト・タイプ

Oracle JETアプリケーションをテストする際に考慮する必要がある主なテスト・タイプは3つあります。

  1. ユニット・テスト
    • ユニット・テストでは、特定の関数、クラスまたはコンポーネントへのすべての入力が予期される出力またはレスポンスを生成していることを確認します。

    • これらのテストは、通常、UIレンダリング、ネットワーク・リクエストまたはその他の環境上の懸念を伴わない自己完結型のビジネス・ロジック、コンポーネント、クラス、モジュールまたは関数に適用されます。

      RESTサービスAPIは個別にテストする必要があることに注意してください。

    • ユニット・テストでは、コンポーネントの実装の詳細と依存関係を認識し、テストしたコンポーネントの分離に焦点を当てます。

  2. コンポーネント・テスト
    • コンポーネント・テストでは、個々のコンポーネントが操作可能で、期待どおりに動作できることを確認します。これらのテストでは、ユニット・テストよりも多くのコードがインポートされ、より複雑になり、実行に時間がかかります。

    • コンポーネント・テストでは、コンポーネントのプロパティ、イベント、提供されるスロット、スタイル、クラス、ライフサイクル・フックなどに関連する問題を捕捉します。

    • これらのテストは、コンポーネントの実装の詳細を認識しません。コンポーネントとシステム全体の統合をテストするために、モックアップは最小限に抑えます。

      コンポーネント・テストで子コンポーネントをモックアップしないでください。かわりに、ユーザーがコンポーネントを操作する(たとえば、要素をクリックするなど)ようにコンポーネントと相互作用するテストで、コンポーネントとその子の間の相互作用をチェックします。

  3. エンドツーエンド・テスト
    • エンドツーエンドのテスト(データベースまたはその他のバックエンド・サービスの設定を含むことが多い)では、複数のページにまたがる機能を確認し、本番構築されたJETアプリケーションに対して実際のネットワーク・リクエストを行います。

エンドツーエンドのテストは、個々のコンポーネントだけでなく、アプリケーション全体の機能をテストすることを目的としています。したがって、Oracle JETアプリケーションの特定のコンポーネントをテストする場合は、ユニット・テストおよびコンポーネント・テストを使用します。

ユニット・テスト

ユニット・テストは、最初に実行する最も包括的なテスト形式です。

ユニット・テストの目的は、ソフトウェア・コードの各ユニットが正しくコーディングされ、期待どおりに動作し、関連するすべての入力に対して予想される出力を返すことを確認することです。単位は、アプリケーションのソース・コード内の関数、メソッド、モジュール、オブジェクトまたはその他のエンティティです。

ユニット・テストは、コードの最下位レベルを実行および検証し、個々のエンティティを分離してテストするために作成された小規模で効率的なテストです。機能を分離することで、テスト対象のユニットに関連しない外部依存関係を削除し、障害の原因の可視性を高めます。

ユニット・テストは、コンポーネントのパブリック・アプリケーション・プログラミング・インタフェース(API)と対話し、可能なかぎり多くのコンポーネントのコード・パスを実行するために、必要な多くの異なるテスト・データの組合わせをAPIに渡します。これには、コンポーネントのプロパティ、イベント、メソッド、およびスロットのテストが含まれます。

作成するユニット・テストは、次の原則に従う必要があります:

  • 記述しやすい: ユニット・テストはテストの中心です。したがって、多くのテストが記述されるため、通常は簡単に記述できる必要があります。標準のテスト・テクノロジ・スタックと推奨される開発環境を組み合せることで、テストが簡単かつ迅速に記述されます。
  • 読みやすい: 各テストの意図はコメントのみでなく明確に文書化する必要がありますが、コードもその目的を簡単に解釈できるようにする必要があります。障害が発生し、デバッグが必要な場合に備えて、テストを読みやすくしておくことが重要です。
  • 信頼できる: テストは、コンポーネント・コードにバグがない場合は常に合格し、真のバグや未実装の新しい動作がある場合にのみ失敗するようにする必要があります。また、テストは、実行順序に関係なく確実に実行される必要もあります。
  • 高速: テストは迅速に実行され、問題をすぐに開発者に報告できる必要があります。テストの実行が遅い場合は、外部システムに依存しているか、外部システムと対話していることを示している可能性があります。
  • 個別: テストでは、すべてのユニットが正しく検証されていることを確認するだけでなく、障害発生時のバグの検出を支援するために、可能なかぎり小さな作業単位を実行する必要があります。各ユニット・テストでは、個々のテスト・ケースで、検証するコードの単一の属性を個別にターゲットとする必要があります。
  • 独立: 何よりも、ユニット・テストは相互に独立しており、外部の依存関係がなく、実行される環境に関係なく一貫して実行できる必要があります。

ユニット・テストは、結果に影響を及ぼす可能性のある外部変更からユニット・テストを保護するために、コンポーネントによって完全に所有されているコードの検証のみに焦点を当て、そのコンポーネントの外部の動作を検証しないようにします。外部の依存関係が必要な場合は、モックを使用してそのかわりにすることを検討してください。

コンポーネント・テスト

コンポーネント・テストの目的は、個々のコンポーネントが仕様どおりに動作し、操作できることを確認することです。コンポーネントが正しい入力を受け入れ、正しい出力を生成していることの検証に加えて、コンポーネント・テストには、コンポーネントのプロパティ、イベント、スロット、スタイル、クラス、ライフサイクル・フックなどに関連する問題のチェックも含まれます。

コンポーネントは多数のコード単位で構成されているため、コンポーネント・テストは複雑で、ユニット・テストよりも実行に時間がかかります。しかし、避けることはできません。コンポーネント内の個々のユニットは単独では機能しても、一緒に使用すると問題が発生する可能性があるからです。

コンポーネント・テストはクローズボックス・テストの一種です。つまり、テストでは基礎となるコードの詳細を考慮せずにプログラムの動作を評価します。開発後すぐにコンポーネントのテストを開始する必要がありますが、テスト対象のコンポーネントは、まだ開発されていない他のコンポーネントに依存する場合があります。開発ライフサイクル・モデルに応じて、外部の影響を防ぐために、コンポーネント・テストをシステム内の他のコンポーネントから分離して実行できます。

コンポーネントが依存するコンポーネントがまだ開発されていない場合は、実際のコンポーネントではなくダミー・オブジェクトを使用します。これらのダミー・オブジェクトはスタブ(関数と呼ばれます)とコントローラ(関数と呼ばれます)です。

テスト・レベルの深さに応じて、小規模コンポーネント・テストと大規模コンポーネント・テストの2つのタイプのコンポーネント・テストがあります。

コンポーネント・テストを他のコンポーネントから分離して実行する場合、小規模コンポーネント・テストと呼ばれます。小規模コンポーネント・テストでは、コンポーネントの他のコンポーネントとの統合は考慮されません。

コンポーネントを他のコンポーネントから分離せずにコンポーネント・テストを実行する場合、一般に、大規模コンポーネント・テストまたはコンポーネント・テストと呼ばれます。これらのテストは、コンポーネントの機能のフローに依存関係があり、分離できない場合に実行されます。

エンドツーエンド・テスト

エンドツーエンド・テストは、ソフトウェア製品の動作を最初から最後まで調べることで評価する方法です。このアプローチでは、アプリケーションが意図したとおりに動作することを検証し、すべての統合コンポーネントが相互に正しく機能することを確認します。また、エンドツーエンドのテストでは、最適なパフォーマンスを実現するために、製品のシステムの依存関係が定義されます。

エンドツーエンド・テストの主な目的は、実世界のシナリオをシミュレートし、システムとそのコンポーネントが適切に統合されているか、データの一貫性が保たれているかを評価することで、エンド・ユーザー・エクスペリエンスを再現することです。この方法では、ユーザーの視点からシステムのパフォーマンスを検証できます。

エンドツーエンドのテストは、広く採用され、信頼性の高い手法であり、次の利点があります。
  • 包括的なテスト・カバレッジ
  • アプリケーションの正確性の保証
  • 市場投入までの時間の短縮
  • コストの削減
  • バグの特定
現代のソフトウェア・システムは相互接続が進んでおり、様々なサブシステムが存在するため、それらに障害が発生するとシステム全体に悪影響を及ぼす可能性があります。エンドツーエンド・テストは、次の方法でこれらのリスクを回避するのに役立ちます:
  • システムのフローの確認
  • テスト領域のカバレッジの増加
  • サブシステムに関連する問題の特定
エンドツーエンドのテストは、様々な利害関係者にとって有益です:
  • 開発者は、テストの責任を軽減できるため、エンドツーエンド・テストを高く評価しています。
  • テスターは、実世界のシナリオをシミュレートして潜在的な問題を回避するテストを作成できるため、有用性を実感しています。
  • マネージャは、エンドツーエンドのテストによって、失敗するテストがエンド・ユーザーに与える影響を理解できるので、メリットがあります。
エンドツーエンドのテスト・プロセスには、次の4つのステージがあります:
  1. テストの計画: 必要な主要タスク、スケジュールおよびリソースの概説
  2. テストの設計: テスト仕様の作成、テスト・ケースの識別、リスクの評価、使用状況の分析およびテストのスケジューリング
  3. テストの実行: テスト・ケースの実行および結果の文書化
  4. 結果の分析: テスト結果のレビュー、テスト・プロセスの評価、および必要に応じて追加のテストの実行
エンドツーエンド・テストには2つのアプローチがあります:
  • 水平テスト: この方法は複数のアプリケーションでのテストを伴い、多くの場合、単一のERP(エンタープライズ・リソース・プランニング)システムで使用されます。
  • 垂直テスト: このアプローチでは、テストが階層順に実行されるレイヤーでのテストが行われます。この方法は、複雑なコンピューティング・システムの重要なコンポーネントをテストするために使用され、通常はユーザーやインタフェースは関与しません。

エンドツーエンド・テストは通常、完成品およびシステムで行われ、各レビューは完成したシステムのテストとして機能します。システムが予期した出力を生成しない場合、または問題が検出された場合は、2回目のテストが実行されます。この場合、チームはデータを記録して分析し、問題の原因を特定して修正し、再テストする必要があります。

アプリケーションをエンドツーエンドでテストする際は、次のメトリックを考慮してください:
  • テスト・ケース準備ステータス: このメトリックは、計画されたテスト・ケースと比較して、現在準備されているテスト・ケースの進行状況を追跡するために使用されます。
  • テストの進捗追跡: テスト完了率およびテスト・ケースの合格/不合格、実行/未実行および有効/無効のステータスの最新情報を提供するために、テストの進捗状況を週単位で定期的にモニタリングします。
  • 不具合のステータスおよび詳細: 未解決およびクローズ済不具合のパーセントと、重大度および優先度別の不具合の内訳を毎週提供します。
  • 環境可用性: 毎日の稼働時間数とテスト予定時間に関する情報。

コンポジット・コンポーネント・ユニット・テスト

コンポジット・コンポーネントは、ビュー、viewModel、それらを接続するバインディングなど、いくつかの異なる要素で構成されます。ビューはコンポーネントの可視部分であり、ユーザーがコンポーネントと対話する方法ですが、viewModelは、何らかの刺激に応じてコンポーネントの動作を制御します。ビューからviewModelへのバインディングは、ビューとそのユーザー・インタラクションおよびレスポンスで実行されるviewModel動作を結び付けます。

通常、コンポーネントのユニット・テストには2つのアプローチがあります:

  1. ビューのテストまたはDOM(ドキュメント・オブジェクト・モデル)テストは、ユーザーがクリック、入力、表示可能な要素を介してコンポーネントと一般的にやり取りする場合とほぼ同じ方法で、コンポーネントのUIと相互作用します。ビューに記述されたバインディングが原因でコントローラ内のアクションを起動する場合がありますが、その目的は動作ではなく、バインド自体が正しいアクションを呼び出すことを検証することです。
  2. ViewModelのテストでは、コンポーネントのコントローラ・レイヤーのみに焦点を当てます。このタイプのテストでは、コントローラ・クラスをインスタンス化し、動作をアサートするためにそのパブリック関数を呼び出します。コントローラが外部モジュールに対して持つ依存関係は、テストがviewModelコードのみを対象とするようすべてモックアウトされます。このテストは、ビューとは独立して行われます。このテストは、コントローラ関数を呼び出すためにビューと対話しません。むしろ、関数を直接呼び出し、呼出しの結果に対してアサーションを実行します。

ノート:

ビュー・ツーviewModelバインディングは相互作用への鍵であり、各刺激に対してコールされるものを定義します。ただし、通常は統合時にのみテストされ、ユニット・テスト時にはテストされません。

直接viewModelテストを使用してコンポジット・コンポーネントをユニット・テストすることをお薦めします。これは、公開されているコードの最小部分(API)に焦点を当てています。コンポジット・コンポーネントの場合、パブリックAPIはviewModelで定義され、カスタムWeb要素に表示されます。これにより、ブラウザを介してコンポーネント全体を実行し、UIをレンダリングせずに、viewModelメソッドをテストできます。ViewModelテストでは、テストでメソッドへの入力を指定でき、出力の正確性を調べることができます。この形式のテストでは、UIとの直接的な対話は推奨されません。かわりに、コンポーネントが実行される環境をシミュレートすることをお薦めします。

ユニット・テストでは、コンポーネントのパブリックな側面を検証する必要があります。APIで公開されるものは次のとおりです:
  • プロパティ
  • イベント
  • メソッド
  • スロット
APIに加えて、コンポジットのその他の側面には、次のものがあります:
  • アクセシビリティ
  • セキュリティ
  • ローカライゼーション
  • ユーザーの操作
これらは通常、パブリックAPIの一部として定義されませんが、テストを通じて検証する必要があります。

バインディングが正しく適用されるようにユーザー・イベントをシミュレートするなど、viewModelテストのみではコンポーネントのすべての側面をカバーできない場合があります。これらのシナリオでは、DOMまたはWebDriverを介したビュー・テストを使用できます。

Oracle JETテスト・テクノロジ・スタックについて

Oracle JETアプリケーションをテストするための推奨テクノロジ・スタックには、Karma、Mocha、ChaiおよびSinonが含まれます。

開発者によるアプリケーションのテストおよびこれらのテクノロジの活用を支援するために、JET 15のリリースではojet add testingコマンドがOracle JET CLIに追加されました。このコマンドは、アプリケーションのテスト環境を構成し、JETコンポーネントをテストするためのフレームワークを設定します。アプリケーションがテスト用に構成されると、推奨テスト・テクノロジ・スタックを使用してテストを記述および実行できます。

  1. Karmaは、NodeJSで実行されるJavaScriptのテスト・ランナーです。HTTPサーバーを実行して、起動および管理するブラウザ・インスタンスでプロジェクト・ファイルを使用できるようにします。Karmaは、必要なファイルをブラウザにロードし、テスト・コードに対してソース・コードを実行します。

    ノート:

    異なるブラウザは異なるDOM実装を持つことができるため、大多数のユーザーに対してアプリケーションが適切に動作することを確認する場合は、ほとんどの主要なブラウザに対するテストが不可欠です。

    Karmaは、メイン構成ファイルkarma.conf.jsで指定されたファイルの変更についてモニターし、テスト・サーバーにシグナルを送信してテスト実行をトリガーし、接続されているすべてのブラウザにテスト・コードを再度実行するように通知します。サーバーは各ブラウザのテスト結果を収集し、CLIで開発者に提示します。

    基本的に、KarmaはブラウザとMochaの両方を起動します。Mochaはテストを実行します。

  2. MochaはJavaScriptテスト・フレームワークで、テストが記述されるライブラリです。テスト・スイートとケースの宣言を可能にします。グローバルにインストールしてプロジェクトの開発依存関係として設定することも、テスト・ケースをWebブラウザで直接実行するように設定することもできます。

    Mochaテストは順次実行されるため、捕捉されなかった例外を正しいテスト・ケースにマッピングしながら、柔軟で正確なレポートを作成できます。Mochaは、テストの終了後にコールバックを呼び出す機能を使用して非同期テストを簡略化し、コールバックを省略して同期テストを可能にします。

  3. Chaiは、NodeJSおよび任意のブラウザのアサーション・ライブラリで、任意のJavaScriptテスト・フレームワークと組み合せることができるます。開発者が選択できるインタフェースがいくつかあり、Chaiで記述するテストは英語の文法に似ています。

  4. モックが必要な場合は、オブジェクトや関数のモックを可能にするライブラリであるSinonを使用し、外部依存関係を必要とせずにテストを実行できるようにすることをお薦めします。

UI自動化テストでは、Selenium WebDriverOracle® JavaScript Extension Toolkit (Oracle JET) WebDriverとともに使用することをお薦めします。

テスト用のOracle JETアプリケーションの構成

ojet add testingコマンド

ojet add testing CLIコマンドを使用して、JETコンポーネントのテストに必要なフレームワークおよびライブラリを設定することで、Oracle JETアプリケーションにテスト機能を追加します。

アプリケーションのルート・ディレクトリのターミナル・ウィンドウからコマンドを実行します。アプリケーションのテスト環境を構成したら、テスト・ランナーとしてKarmaを使用し、テストを記述するためにMochaとChaiを使用してアプリケーションのテストを続行できます。また、Sinonを使用して、テスト用のスパイ、スタブおよびモックを含めることもできます。

ojet add testingコマンドによって実行される構成では、アプリケーション内にいくつかの重要なテスト・ディレクトリおよびファイルも作成されます。

test-configフォルダがアプリケーションのルート・ディレクトリに追加されます。これには、テストに必要な3つの構成ファイル(karma.conf.jstest-main.jsおよびtsconfig.json)が含まれています。Karma構成ファイルkarma.conf.jsはテストの主な構成ファイル、test-main.jsはKarmaによってロードされるRequireJS構成ファイル、tsconfig.jsonはテスト・ファイルのTypeScript構成ファイルです。

さらに、既存のコンポーネントでテスト・ファイルがチェックされます。テストを含むファイル(仕様ファイルと呼ばれる)の拡張子は、ツールで認識されるように.spec.tsにする必要があります。仕様ファイルがコンポーネントにない場合、それらが挿入されます。仕様ファイルは、コンポーネント・フォルダの__tests__フォルダ内にあります(/src/ts/jet-composites/oj-calculate-value/__tests__など)。このフォルダは、コンポーネント用に記述したテスト・ファイルを保持しており、デフォルトでは、ダミー・テストを含む3つのテスト・ファイル(oj-calculate-value-knockout.spec.tsoj-calculate-value-ui.spec.tsおよびoj-calculate-value-viewmodel.spec.ts)を使用して作成されます。

ノート:

プロジェクトでojet add testingコマンドを実行した後に新しいコンポーネントまたはパックをコマンドラインから作成すると、__tests__フォルダおよびファイルがデフォルトで挿入されます。

テスト・デモ

ここでは、ojet add testingコマンドを使用して、Oracle JETアプリケーションのテスト環境を構成します。このテスト・デモで使用されるアプリケーションには、ユーザーが発行した2つの数値を取得し、その合計を計算して、アプリのダッシュボードに結果を表示する計算機コンポーネントが含まれます。アプリケーションのテスト環境を設定したら、計算機コンポーネントでテストを実行します。

  1. 最初に、JET-Test-Example.zipをダウンロードして作業ディレクトリに解凍します。アプリケーションのルート・ディレクトリでターミナル・ウィンドウを開き、ojet restoreコマンドを実行します。
  2. アプリケーションのディレクトリ構造を確認します。/src/ts/jet-compositesディレクトリに、oj-calculate-valueコンポーネントがあります。テスト用にアプリケーションを構成した後、計算機コンポーネントで実行するテストは、アプリケーションのルート・ディレクトリにテキスト・ファイルoj-calculate-value-viewmodel-spec-ts.txtとして含まれます。

    ojet serveコマンドを使用してアプリケーションを実行し、計算機コンポーネントが期待どおりに動作することを手動でテストします。

    計算機コンポーネントを含むテスト・デモ・アプリケーション

    ノート:

    プロジェクトでテストを実行する前に、まずojet buildまたはojet serveを実行する必要があります。そうしないと、テストが失敗します。
  3. アプリケーションのルート・ディレクトリのターミナル・ウィンドウからojet add testingコマンドを実行します。

    アプリケーションのディレクトリ構造で、test-configフォルダがアプリケーションのルート・ディレクトリに追加され、__tests__フォルダが/src/ts/jet-composites/oj-calculate-valueディレクトリに追加されたことがわかります。

  4. アプリケーションのルート・ディレクトリ内のファイルoj-calculate-value-viewmodel-spec-ts.txtの名前をoj-calculate-value-viewmodel.spec.tsに変更し、\src\ts\jet-composites\oj-calculate-value\__tests__ディレクトリ内の同じ名前のファイルを置き換えます。このファイルには、oj-calculate-valueコンポーネントのviewModel用にChaiで記述された3つのサンプル・ユニット・テストが含まれています。
  5. テストを実行します。コマンドラインにスクリプトnpm run testを入力し、ターミナル・ウィンドウの結果を確認します。コマンドラインに表示されるテストの実行結果。
  6. テストの実行後に、アプリケーションのルート・ディレクトリに作成されたcoverageディレクトリを確認します。これには、oj-calculate-value-viewModel.js.htmlファイルが含まれており、ブラウザで開いてテスト実行の詳細を表示できます。

自動テストでのBusyContext APIの使用

コンポーネントや他の条件がなんらかのアクションを完了するまで待機してからそれを操作するには、BusyContextを使用します。

BusyContext APIの目的は、非同期操作の順次依存性に対応することです。通常は、テストの自動化でアニメーションの完了、JETページのロード、データのフェッチなどが完了するまで待機するとき、BusyContextを使用します。

ノート:

テスト中はアニメーションを無効にしないでください。テストは、アプリケーションでユーザーに表示され、発生する内容に基づいて実行する必要があります。たとえば、アニメーションをオフにすると、アニメーションが有効になっている場合にのみ出現する競合状態が検出される可能性がなくなります。

待機のシナリオ

ビジー・コンテキストAPIでは、すべてのビジー状態が解決する、またはタイムアウト期間が経過するまで遮断されます。4つの主な待機のシナリオがあります。

  • アニメーション効果を実装するコンポーネント

  • RESTエンドポイントからデータをフェッチするコンポーネント

  • RequireJSでロードされたOracle JETライブラリなどのブートストラップ・ファイルをロードするページ

  • アプリケーション・ドメイン・ロジックと関連付けられたブロッキング状態など、Oracle JETに制限されない顧客定義のシナリオ

ビジー・コンテキストの範囲の決定

ビジー・コンテキスト上で待機するための最初のステップは、待機条件を決定することです。ビジー・コンテキストの粒度の範囲をページ全体に設定するか、または特定のDOM要素に範囲を制限することができます。ビジー・コンテキストには文書のDOM構造を反映した階層的な依存関係があり、ページのコンテキストがルートになります。ユーザーの特定のシナリオに応じて、次のビジネス・コンテキストの範囲のいずれかをターゲットに指定します。

  • ページに対して範囲を指定

    ページ・ビジー・コンテキストを選択してページ全体を表します。通常、自動化の開発者は、自動化を開始する前にページが完全にロードされるまで待機する必要があります。また、自動化の開発者は、通常、単一のOracle JETコンポーネントではなく複数のコンポーネントを含むアプリケーションの機能をテストしたいと考えます。

    var busyContext = Context.getPageContext().getBusyContext();
  • 直近のDOM要素に対して範囲を指定

    特定のコンポーネントの操作が完了するまでアプリケーションが待機する必要がある場合は、DOMノードを範囲とするビジー・コンテキストを選択します。たとえば、アプリケーション・フローの次のタスクを開始する前にojPopupが開閉アニメーションを完了するのを待機する場合などです。data-oj-contextマーカー属性を使用して、DOMサブツリーのビジー・コンテキストを定義します。

    <div id="mycontext" data-oj-context>
      ...
      <!-- JET content -->
      ...
    </div>
    
    var node = document.querySelector("#mycontext");
    var busyContext = Context.getContext(node).getBusyContext();    
    

準備完了状態

ビジー・コンテキストを取得したら、次のステップではビジー状態を調査します。BusyContextには、準備完了状態を調査するためのisReady()およびwhenReady()という2つの操作があります。isReady()メソッドでは、ビジー・コンテキストの状態がただちに返されます。whenReady()メソッドでは、ビジー状態が解決した、またはタイムアウト期間が経過したときに解決されるPromiseが返されます。

次の例は、WebDriverとともにisReady()を使用する方法を示しています。

public static void waitForJetPageReady(WebDriver webDriver, long timeoutInMillis)
{
  try
  {
    final WebDriverWait wait = new WebDriverWait(webDriver, timeoutInMillis / _THOUSAND_MILLIS);
    // Eat any WebDriverException
    // "ExpectedConditions.jsReturnsValue" will continue to be called if it doesn't return a value.
    // /ExpectedConditions.java#L1519
    wait.ignoring(WebDriverException.class);
    wait.until(ExpectedConditions.jsReturnsValue(_PAGE_WHEN_READY_SCRIPT));
  }

  catch (TimeoutException toe)
  {
    String evalString = "return Context.getPageContext().getBusyContext().getBusyStates().join('\\n');";
    Object busyStatesLog = ((JavascriptExecutor)webDriver).executeScript(evalString);
    String retValue = "";
    if (busyStatesLog != null){
      retValue = busyStatesLog.toString();
      Assert.fail("waitForJetPageReady failed - !Context.getPageContext().getBusyContext().isReady() - busyStates: " +
        retValue);  }
}
 
// The assumption with the page when ready script is that it will continue to execute until a value is returned or
// reached the timeout period.
//
// There are three areas of concern:
// 1) Has the app opt'd in on the whenReady wait for bootstrap?
// 2) If the app has opt'd in on the jet whenReady strategy for bootstrap "('oj_whenReady' in window)",
// wait until jet core is loaded and have a ready state.
// 3) If not opt-ing in on jet whenReady bootstrap, make the is ready check if jet core has loaded. If jet core is
// not loaded, we assume it is not a jet page.

// Check to determine if the page is participating in the jet whenReady bootstrap wait period.

static private final String _BOOTSTRAP_WHEN_READY_EXP = "(('oj_whenReady' in window) && window['oj_whenReady'])";
 
// Assumption is we must wait until jet core is loaded and the busy state is ready.
static private final String _WHEN_READY_WITH_BOOTSTRAP_EXP =
"(window['oj'] && window['oj']['Context'] && Context.getPageContext().getBusyContext().isReady() ?" +
" 'ready' : '')";

// Assumption is the jet libraries have already been loaded. If they have not, it's not a Jet page.
// Return jet missing in action "JetMIA" if jet core is not loaded.
static private final String _WHEN_READY_NO_BOOTSTRAP_EXP =
"(window['oj'] && window['oj']['Context'] ? " +
"(Context.getPageContext().getBusyContext().isReady() ? 'ready' : '') : 'JetMIA')";

// Complete when ready script
static private final String _PAGE_WHEN_READY_SCRIPT =
"return (" + _BOOTSTRAP_WHEN_READY_EXP + " ? " + _WHEN_READY_WITH_BOOTSTRAP_EXP + " : " +
_WHEN_READY_NO_BOOTSTRAP_EXP + ");";

次の例は、QUnitとともにwhenReady()を使用する方法を示しています。

// Utility function for creating a promise error handler
function getExceptionHandler(assert, done, busyContext)
{
  return function (reason)
    {
      if (reason && reason['busyStates'])
      {
        // whenReady timeout
        assert.ok(false, reason.toString());
      }
      else
      {
        // Unhandled JS Exception
        var msg = reason ? reason.toString() : "Unknown Reason";
        if (busyContext)
          msg += "\n" + busyContext;
        assert.ok(false, msg);
      }

      // invoke done callback
      if (done)
        done();
    };
};

QUnit.test("popup open", function (assert)

{
  // default whenReady timeout used when argument is not provided
  Context.setBusyContextDefaultTimeout(18000);

  var done = assert.async();
  assert.expect(1);

  var popup = document.getElementById("popup1");  
                                                                                  
  // busy context scoped for the popup
  var busyContext = Context.getContext(popup).getBusyContext();
  var errorHandler = getExceptionHandler(assert, done, busyContext);

  popup.open("#showPopup1");

  busyContext.whenReady().then(function ()
  {
    assert.ok(popup.isOpen(), "popup is open");
    popup.close();
    busyContext.whenReady().then(function ()
    {
      done();
    }).catch(errorHandler);
  }).catch(errorHandler);
});

待機条件の作成

JETコンポーネントでは、ビジー・コンテキストを使用してブロッキング操作が伝達されます。ビジー・コンテキストの任意の範囲にビジー状態を追加して、非同期データ・フェッチなどの操作を遮断できます。

次の大まかなステップで、ビジー・コンテキストを追加する方法を示します:

  1. 範囲指定されたビジー・コンテキストを作成します。

  2. ビジー状態をビジー・コンテキストに追加します。ビジー状態の目的を説明する説明を追加する必要があります。ビジー状態によって、ビジー状態を削除する時間になったらコールされる解決関数が返されます。

    ビジー・コンテキストの依存関係は、ビジー状態が初めて追加される時点で決定されます。ビジー・コンテキストが追加された後でDOMノードの親が変更された場合は、コンテキストではすべての親のDOMコンテキストとの依存性が維持されます。

  3. ビジー状態で保護される必要がある操作を実行します。通常、これらは他のアプリケーション・フローがその完了のために依存している非同期操作です。

  4. 操作が完了したらビジー状態を解決します。

アプリケーションはビジー状態を解除する役割を担っています。アプリケーションは、ビジー状態と関連付けられている解決関数への参照を管理し、ビジー状態を解除するためにコールされる必要があります。ビジー状態が解決される前に、ビジー・コンテキストが適用されるDOMノードが文書から削除される場合は、ビジー状態は親なしとなり、解決されません。

Oracle JETアプリケーションのデバッグ

Oracle JET WebアプリケーションはJavaScriptまたはTypescriptで記述されたクライアント側のHTML5アプリケーションであるため、好みのブラウザのデバッグ機能を使用できます。

Webアプリケーションのデバッグ

Oracle JETアプリケーションをデバッグするには、ソース・コード・エディタおよびブラウザの開発者ツールを使用します。

Chrome、Edge、Firefoxなどの広く使用されているブラウザ用の開発者ツールには、ブラウザで実行されるOracle JETアプリケーションの検査およびデバッグに役立つ様々な機能が備わっています。これらの開発者ツールの使用方法の詳細は、ご使用のブラウザのドキュメントを参照してください。

デフォルトでは、ojet buildおよびojet serveコマンドはOracle JETライブラリのデバッグ・バージョンを使用します。(ojet buildまたはojet serveコマンドに--releaseパラメータを追加して) Oracle JETアプリケーションをリリース・モードで構築または提供する場合、アプリケーションでは縮小バージョンのOracle JETライブラリが使用されます。リリース・モードで構築したOracle JETアプリケーションをデバッグする場合、--optimize=noneパラメータを使用すると、改行と空白が保持されて、縮小された出力が読みやすくなります:

ojet build --release --optimize=none
ojet serve --release --optimize=none

--optimize=noneパラメータを使用しない場合、ブラウザの開発者ツールには、縮小されたソース・ファイルを「プリティ・プリント」して読みやすくするためのオプションが用意されています。

また、アプリケーションのデバッグにさらに役立つブラウザ拡張機能をインストールできる場合もあります。

最後に、Visual Studio Codeなどのソース・コード・エディタを使用する場合は、Oracle JETアプリケーションの開発およびデバッグを支援するために提供されているデバッグ・ツールについてよく理解してください。