自動フロントエンドテストは素晴らしいです。コードを使用してテストを作成してページにアクセスしたり、1つのコンポーネントのみをロードしたり、テストコードをクリックしたり、ユーザーのようにテキストを入力したりしてから、インタラクション後にアプリケーションの状態についてアサーションを作成できます。これにより、テストで説明されているすべてがアプリケーションで予想どおりに機能することを確認できます。
この投稿は、自動UIテストの構成要素の1つについてであるため、事前の知識はあまり想定していません。すでに基本に精通している場合は、最初のいくつかのセクションを自由にスキップしてください。
テストを書くときに知るのに役立つ古典的なパターンがあります:配置、行動、主張。フロントエンドテストでは、これは以下を実行するテストファイルに変換されます。
対話するものを指定してから、後でページで確認するものを指定する際に、使用する必要があるDOMの部分をターゲットにするために、さまざまな要素ロケーターを使用できます。
ロケーターは、要素のID、要素のテキストコンテンツ、または.blog-post> div.container> div> p:nth-child(12)などのCSSセレクターのようなものです。テストランナーのその要素を識別できる要素については、ロケーターになることができます。おそらくその最後のCSSセレクターからすでに言うことができるように、ロケーターには多くの品種があります。
しばしば、脆性または安定しているという点でロケーターを評価します。一般に、要素の周りのコードが時間の経過とともに変化していても、テストが必要な要素を常に見つけることができるように、可能な限り最も安定した要素ロケーターを望んでいます。とはいえ、すべてのコストで安定性を最大化すると、実際にテストを弱める防御的なテスト作成につながる可能性があります。私たちは、テストを気にしたいものと一致する、脆性と安定性の組み合わせを持つことで最も価値を得ます。
このように、要素ロケーターはダクトテープのようなものです。それらは一方向に本当に強く、もう一方の方向に簡単に裂けるはずです。私たちのテストは、アプリケーションに重要でない変更が行われた場合に合わせて合格し続ける必要がありますが、テストで指定したことと矛盾する重要な変更が発生した場合、それらは容易に失敗するはずです。
まず、実際の人が自分の仕事をするための指示を書いているふりをしましょう。 Gate InspectorがGate Inspectors、Incに雇われたばかりです。それらを成功させたい場合は、おそらく次のようなメモを書くことはありません。
黄色い家を通り過ぎて、マイクの母親の友人のヤギがその時間を逃した畑にぶつかるまで続けてから、左に曲がって、通りの向こう側の家の前のゲートがあなたが開いているかどうかを教えてください。
これらの方向は、長いCSSセレクターまたはXPathをロケーターとして使用するようなものです。それはもろい - そしてそれは「悪い種類の脆い」です。黄色の家が塗り直されてステップを繰り返すと、ゲートが見つかりなくなり、あきらめることを決定するかもしれません(またはこの場合、テストは失敗します)。
同様に、マイクの母親の友人のヤギの状況について知らない場合は、正しい参照ポイントで停止して、どのゲートをチェックするかを知ることはできません。これがまさに「悪い種類の脆い」を悪くするものです。テストはあらゆる種類の理由で壊れる可能性があり、これらの理由はどれもゲートの使いやすさとは何の関係もありません。
それでは、別のフロントエンドテストを行いましょう。これははるかに安定しています。結局のところ、合法的にこのエリアでは、特定の道路上のすべてのゲートは、メーカーからの一意のシリアル番号を持つことになっています。
シリアル番号1234のゲートに移動し、開いているかどうかを確認します。
これは、IDで要素を見つけるようなものです。より安定しており、1つのステップにすぎません。最後のテストからの失敗のすべてのポイントが削除されました。このテストは、そのIDを持つゲートが予想どおりに開いていない場合にのみ失敗します。
結局のところ、2つのゲートは同じ道路に同じIDを持つべきではありませんが、実際にはどこにも施行されておらず、ある日、道路上の別のゲートは同じIDで終わります。
そのため、次回新しく雇われたゲートインスペクターが「ゲート1234」をテストするとき、彼らは他の人を最初に見つけ、今では間違った家を訪れて間違ったものをチェックしています。テストが失敗する可能性があるか、さらに悪いことに:そのゲートが予想どおりに機能する場合、テストは依然として合格しますが、意図した被験者をテストしていません。それは誤った自信を提供します。ゲートの泥棒によって、夜中に元のターゲットゲートが盗まれたとしても、通過し続けるでしょう。
このような事件の後、IDが思ったほど安定していないことは明らかです。そのため、次のレベルの考え方を行い、ゲートの内側で、テスト用の特別なIDが必要だと判断します。この1つのゲートに特別なIDを配置するための技術を送信します。新しいテストの指示は次のようになります:
テストID「My-Favorite-Gate」でゲートに移動し、開いているかどうかを確認します。
これは、一般的なデータテスト属性を使用するようなものです。このような属性は、コードで自動化されたテストで使用することを意図しており、変更または削除しないでください。ゲートにその属性がある限り、あなたは常にゲートを見つけます。 IDSと同様に、ユニークさはまだ強制されていませんが、もう少し可能性があります。
これは、あなたが得ることができる限り脆性から遠く離れており、ゲートの機能を確認します。テストのために意図的に追加した属性以外は何にも依存しません。しかし、ここに隠れているのは少し問題があります…
これはゲートのユーザーインターフェイステストですが、ロケーターはユーザーがゲートを見つけるために使用しないものです。
この架空の郡では、人々が住所を見ることができるように家に印刷する必要があることが判明したため、それは逃した機会です。したがって、すべてのゲートにはユニークな人間に面したラベルが必要であり、そうでない場合はそれ自体が問題です。
テストIDでゲートを見つけると、ゲートが塗り直され、家番号が覆われていることが判明した場合、テストはまだ合格します。しかし、門の全体のポイントは、人々が家にアクセスすることです。言い換えれば、ユーザーが見つけることができない作業ゲートは、まだテストの失敗である必要があり、この問題を明らかにすることができるロケーターが必要です。
初日のゲートインスペクターのこのテスト指示の別のパスは次のとおりです。
ハウスナンバー40のゲートに移動し、開いているかどうかを確認します。
これは、テストに値を追加するロケーターを使用します。ユーザーも依存するものに依存します。これはゲートのラベルです。テストが実際にテストしたい相互作用に到達する前に、テストが失敗する潜在的な理由を追加します。しかし、この場合、ロケーターはユーザーの観点から意味があるため、これを「脆い」と肩をすくめてはなりません。ゲートがラベルで見つからない場合、それが開くかどうかは関係ありません - これは「良い種類の脆い」です。
多くのフロントエンドテストアドバイスは、DOM構造に依存するロケーターの書き込みを避けることを指示しています。これは、開発者が時間の経過とともにコンポーネントとページをリファクタリングできることを意味し、新しい構造に追いつくためにテストを更新することなく、ユーザー向けのワークフローが壊れていないことをテストに確認できます。この原則は有用ですが、フロントエンドテストでは無関係なDOM構造に依存するロケーターを書き込むことを避けるべきだと言って、少し微調整します。
アプリケーションを正しく機能させるには、DOMはいつでも画面上にあるコンテンツの性質と構造を反映する必要があります。この理由の1つは、アクセシビリティです。この意味で正しいDOMは、支援技術が適切に解析し、ブラウザによってレンダリングされたコンテンツを見ていないユーザーに説明するのがはるかに簡単です。 Dom StructureとPlane Old HTMLは、支援技術に依存しているユーザーの独立性に大きな違いをもたらします。
フロントエンドテストをスピンアップして、アプリの連絡先形式に何かを送信しましょう。これにはサイプレスを使用しますが、ロケーターを選択する原則は、要素を見つけるためにDOMを使用するすべてのフロントエンドテストフレームワークに戦略的に適用されます。ここでは、要素を見つけ、テストを入力し、フォームを送信し、「ありがとう」状態に到達したことを確認します。
//?お勧めしません cy.get( '#name')。type( 'mark') cy.get( '#コメント')。タイプ( 'テストコメント') cy.get( '。submit-btn')。クリック() cy.get( '。ありがとう')。( 'be.visible')
これら4行にはあらゆる種類の暗黙の主張があります。 cy.get()は、要素がDOMに存在することを確認しています。特定の時間の後に要素が存在しない場合、テストは失敗しますが、タイプやクリックなどのアクションは、アクションを取る前に他の何かによって目に見える、有効になり、遮られていないことを確認します。
したがって、このような簡単なテストでも「無料で」多くのことを得ることができますが、私たち(およびユーザー)があまり気にしていないものにいくつかの依存関係を導入しました。特にdiv.main> p:nth-child(3)> span.is-a-buttonなどのセレクターと比較して、私たちがチェックしている特定のIDとクラスは十分に安定しているように見えます。これらの長いセレクターは非常に具体的であるため、DOMを軽微な変更すると、機能が壊れているためではなく、要素が見つからないためにテストが失敗する可能性があります。
しかし、#Nameのような短いセレクターでさえ、3つの問題があります。
問題1と2の場合、推奨されるソリューションは、多くの場合、テスト専用に追加されるHTMLで専用のデータ属性を使用することです。これは、テストがDOM構造に依存せず、開発者がコンポーネントを中心にコードを変更するため、データテスト= "name-field"を適切な入力要素に添付している限り、テストは更新を必要とせずに合格し続けるためです。
ただし、これは問題3に対処するものではありません。ユーザーにとって無意味なものに依存するフロントエンドの相互作用テストがまだあります。
要素ロケーターは、ロケーターに関する何かがユーザーエクスペリエンスにとって重要であるため、実際に依存したいものに依存する場合に意味があります。インタラクティブな要素の場合、使用するのに最適なセレクターは要素のアクセス可能な名前であると主張します。このようなものは理想的です:
//?推奨 cy.getByLabelText( 'name')。type( 'mark')
この例では、サイプレステストライブラリのbylabeltextヘルパーを使用しています。 (実際、あらゆる形式でテストライブラリを使用している場合、おそらくこのようなアクセス可能なロケーターの書き込みをすでに支援しています。)
これは、組み込みのチェック(Cy.Type()コマンドを介して無料で入手できるようになったため、フォームフィールドのアクセシビリティが含まれるため有用です。すべてのインタラクティブな要素には、支援技術にさらされるアクセス可能な名前が必要です。これは、たとえば、スクリーンリーダーのユーザーが、必要な情報を入力するために入力しているフォームフィールドがどのようなものに呼ばれるかをどのように知っているかです。
通常、フォームフィールドにこのアクセス可能な名前を提供する方法は、通常、IDによってフィールドに関連付けられたラベル要素を使用します。 Cypress Testing LibraryのGetByLabelTextコマンドは、フィールドが適切にラベル付けされていることを確認しますが、フィールド自体がラベルを持つことが許可されている要素であることを確認します。したがって、たとえば、ラベルが存在しているにもかかわらず、divのラベルが無効なHTMLであるため、次のHTMLはtype()コマンドが試行される前に正しく失敗します。
<label for="my-custom-input"> editable div element:</label> <div contentedable="true"></div>
これは無効なHTMLであるため、ScreenReaderソフトウェアはこのラベルをこのフィールドに正しく関連付けることはできません。これを修正するために、マークアップを更新して、実際の入力要素を使用します。
<label for="my-real-input"> real input:</label>
これは素晴らしいです。 DOMに編集された後にこの時点でテストが失敗した場合、それは要素の配置方法に無関係な構造が変化するためではなく、私たちの編集が、私たちのフロントエンドテストが明示的に気にするDOMの一部を破るために何かをしたためです。
非対話要素については、思考キャップを載せる必要があります。 DOMがまったく問題でない場合は、常に私たちのために存在するデータCyまたはデータテストの属性に戻る前に、少し判断をしてみましょう。
一般的なロケーターに浸る前に、覚えておいてください:DOMの状態は、Web開発者としての私たちの全体のものです(少なくとも、そうだと思います)。そして、DOMは、視覚的にページを経験していないすべての人のためにUXを駆動します。そのため、多くの場合、テストロケーターに含めることができるコードで使用できる、または使用できる意味のある要素があるかもしれません。
そして、そうでない場合、なぜなら。たとえば、アプリケーションコードはすべてdivやスパンなどの一般的なコンテナです。テストを追加しながら、最初にアプリケーションコードを修正することを検討する必要があります。それ以外の場合、テストでは、一般的な容器が予想され、望ましいことを実際に指定するリスクがあり、誰かがそのコンポーネントをよりアクセスしやすくするのが少し難しくなります。
このトピックは、組織でのアクセシビリティがどのように機能するかについてのワームの缶を開きます。多くの場合、誰もそれについて話しておらず、それが私たちの会社の実践の一部ではない場合、私たちはフロントエンドの開発者としてのアクセシビリティを真剣に受け止めていません。しかし、一日の終わりには、私たちはデザインの「正しいマークアップ」とは何か、そしてそれを決定する際に何を考慮すべきかについて専門家になるはずです。 「Connect.tech 2021からの講演で、「アクセシブルなvueの研究と書き込み」と呼ばれる私の講演で、この側面についてもっと議論します。
上で見たように、私たちが伝統的にインタラクティブだと考えている要素では、フロントエンドテストに簡単に構築できる非常に良い経験則があります。インタラクティブな要素には、要素に正しく関連付けられた知覚可能なラベルが必要です。したがって、インタラクティブなものはすべて、テストするときに、必要なラベルを使用してDOMから選択する必要があります。
メインのような基本的なランドマークを除いて、何でもテキストを表示するほとんどのコンテンツレンダリング要素のように、インタラクティブとは考えていない要素の場合、灯台の監査障害を引き起こしません。しかし、マークアップは、それを見ることができない人にコンテンツの性質と構造を説明していないため、テクノロジーを支援するのに非常に有益でも役立つことはありません。 (これを極端に採用するには、マヌエルマチゾビッチの優れたブログ投稿「完璧な灯台のスコアで可能な限り最もアクセスできないサイトを構築してください」をご覧ください。)
私たちがレンダリングするHTMLは、コンテンツを視覚的に知覚していない人に重要なコンテキスト情報を伝える場所です。 HTMLはDOMの構築に使用され、DOMはブラウザのアクセシビリティツリーを作成するために使用され、アクセシビリティツリーは、ソフトウェアを使用して障害者に取得できるコンテンツとアクションを表現するためにあらゆる種類の支援技術を使用できるAPIです。多くの場合、スクリーンリーダーは私たちが考える最初の例ですが、アクセシビリティツリーは、特にウェブページを点字に変えるディスプレイなど、他のテクノロジーでも使用できます。
自動化されたアクセシビリティチェックは、コンテンツに適したHTMLを実際に作成したかどうかはわかりません。 HTMLの「正しさ」は、アクセシビリティツリーで伝える必要があると考える情報について開発者に作成している判断コールです。
その呼び出しを行ったら、自動化されたフロントエンドテストにかけるのにどれだけ適しているかを判断できます。
ステータスARIAの役割を持つコンテナが、連絡先フォームの「ありがとう」とエラーメッセージングを保持すると判断したとしましょう。これは、フォームの成功または失敗のフィードバックをスクリーンリーダーによって発表できるように素晴らしいかもしれません。 .thank-youおよび.errorのCSSクラスを適用して、視覚状態を制御できます。
この要素を追加してUIテストを作成したい場合、テストがフォームに記入して提出した後、このようなアサーションを書くことができます。
//?お勧めしません cy.get( '。ありがとう')。( 'be.visible')
または、このような非脆性がまだ意味のないセレクターを使用するテストでさえ:
//?お勧めしません cy.get( '[data-test]')。
両方ともcy.contains()を使用して書き直すことができます。
//?推奨 cy.contains( '[role = "status"]'、 'ありがとう、私たちはあなたのメッセージを受け取りました') 。
これにより、予想されるテキストが表示され、適切な種類の容器内にあったことが確認されます。以前のテストと比較して、これは実際の機能を検証するという点ではるかに価値があります。このテストの一部が失敗した場合、メッセージと要素セレクターの両方が私たちにとって重要であり、簡単に変更するべきではないため、知りたいと思います。
ここでは、多くの追加コードがなくても間違いなくいくつかのカバレッジを獲得しましたが、別の種類の脆性も導入しました。テストには普通の英語の文字列があります。つまり、「ありがとう」メッセージが「手を差し伸べてくれてありがとう!」のようなものに変わる場合を意味します。このテストは突然失敗します。他のすべてのテストでも同じです。ラベルの書き方にわずかな変更では、そのラベルを使用して要素をターゲットにするテストを更新する必要があります。
コードで行うのと同じように、フロントエンドテストでこれらの文字列に同じ真実のソースを使用することで、これを改善できます。そして、私たちが現在、私たちのコンポーネントのHTMLに人間の読み取り可能な文が埋め込まれているなら…今、私たちはそこからそのようなものを引き出す理由があります。
魔法の数字(またはそれほど励みに、「無名の数値定数」)は、古き良き1.023033などの計算の最終結果にとって重要なコードで時々見られる超固有の値です。しかし、その数は無効ではないため、その重要性は不明であるため、それが何をしているのかは不明です。多分それは税金を適用します。たぶんそれは私たちが知らないいくつかのバグを補います。知るか?
いずれにせよ、同じことがフロントエンドのテストにも当てはまり、一般的なアドバイスは、明確さがないため、魔法の数字を避けることです。コードレビューは、多くの場合、それらをキャッチし、数字が何であるかを尋ねます。定数に移動できますか?また、値が複数の場所を再利用する場合も同じことをします。どこでも値を繰り返すのではなく、変数に保存し、必要に応じて変数を使用できます。
ユーザーインターフェイスを長年にわたって書くと、HTMLまたはテンプレートファイルのテキストコンテンツが他のコンテキストでマジック番号に非常に似ていると表示されました。コードを通して絶対値をすべて入れていますが、実際には、これらの値を他の場所に保存して、ビルド時に(または状況に応じてAPIを介して)持ち込む方が便利かもしれません。
これにはいくつかの理由があります:
{{content [currentlanguage] .contactform.name}}
const text = content.en.contactfrom //これを1回行い、ファイル内のすべてのテストはそれから読むことができます cy.contains(text.nameLabel、 '[role = "status"]')。( 'be.visible')
すべての状況は異なりますが、文字列の定数のシステムを持つことは、堅牢なUIテストを作成するときに巨大な資産です。お勧めします。次に、翻訳または動的コンテンツが私たちの状況に必要になった場合、私たちはそれに対してよりよく準備されています。
テストでテキスト文字列をインポートすることに対する良い議論を聞いたことがあります。たとえば、テスト自体がコンテンツソースとは独立して予想されるコンテンツを指定する場合、テストがより読みやすく、一般的に優れている人もいます。
それは公正なポイントです。コンテンツはより多くの編集レビュー/公開モデルを通じて制御する必要があると思うので、私はこれにあまり説得されていません。そして、テストが書かれたときに正しい特定の文字列ではなく、ソースからの予想されるコンテンツがレンダリングされたかどうかをテストに確認する必要があります。しかし、多くの人々がこれについて私に反対します、そして、私はチーム内でトレードオフが理解されている限り、どちらの選択も受け入れられると言います。
とはいえ、フロントエンドのコンテンツからコードをより一般的に分離することをお勧めします。また、コンポーネントテストで文字列をインポートしたり、エンドツーエンドテストでインポートしたりしないように、混合して一致させることも有効な場合があります。これにより、複製を保存し、コンポーネントが正しいコンテンツを表示しながら、編集、ユーザー向けの感覚で、予想されるテキストを独立して主張するフロントエンドテストがまだあります。
[data-test = "success-message"]のようなCSSセレクターは依然として有用であり、常に使用されるのではなく、意図的な方法で使用すると非常に役立ちます。私たちの判断では、要素をターゲットにする意味のあるアクセス可能な方法がないということである場合、データテスト属性が依然として最良の選択肢です。たとえば、テストを書いている日にDOM構造がたまたまそうであるように、たまたま偶然の一致に応じて、それらははるかに優れており、テストスタイルのテストスタイルの「3番目のDivの2番目のリスト」に戻ります。
また、コンテンツが動的であると予想される場合もあり、テストで使用するために真実の一般的な源から文字列を簡単につかむ方法もありません。これらの状況では、データテスト属性は、私たちが気にする特定の要素に到達するのに役立ちます。たとえば、アクセシビリティに優しいアサーションと組み合わせることができます。
cy.get( 'h2 [data-test = "intro-subheading"]')
ここでは、イントロサブヘッドのデータテスト属性を持っているものを見つけたいと考えていますが、それが私たちが期待しているものであれば、それがH2要素であるべきであると主張することをテストで許可します。データテスト属性は、何らかの理由でそのH2の内容がテスト時に知られていない場合、ページ上にある可能性のある他のH2ではなく、関心のある特定のH2を取得するために使用されます。
コンテンツを知っている場合でも、データ属性を使用して、アプリケーションがそのコンテンツを適切な場所にレンダリングすることを確認することができます。
cy.contains( 'h2 [data-test = "intro-subheading"]'、 'Welcome to Testing!')
データテストセレクターは、ページの特定の部分に到達し、その中でアサーションを作成するための利便性にもなります。これは次のようになる可能性があります。
cy.get( 'article [data-test = "ablum-card-blur-great-escape"]')。(()=> { cy.contains( 'h2'、 'great Escape')。 cy.contains( 'P'、 '1995アルバムBy Blur')。 cy.get( '[data-test = "stars"]')。 })
その時点で、このコンテンツをターゲットにする他の良い方法が非常によくあるかもしれないので、私たちはいくつかのニュアンスに入ります。それは単なる例です。しかし、一日の終わりには、そのような詳細について心配することは、少なくとも私たちがテストしているHTMLに埋め込まれたアクセシビリティ機能をある程度理解しており、テストにそれらを含めることを望んでいるので、それは良いことです。
フロントエンドテストは、どの要素と対話するか、どのようなコンテンツを期待するかをテストにどのように伝えるかについて思いやりがある場合、より多くの価値をもたらします。インタラクティブコンポーネントをターゲットにするには、アクセス可能な名前を好む必要があります。特定の要素名、ARIAの役割などを、それらが機能に関連する場合は、非対話コンテンツに含める必要があります。これらのロケーターは、実用的な場合、強度と脆性の適切な組み合わせを作成します。
そしてもちろん、他のすべてについては、データテストがあります。
以上がフロントエンドテストロケーターを最大化しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。