LoginSignup
6
5

More than 3 years have passed since last update.

TestCafe(3)テストのAPI2(テストの流れとページ情報の参照)

Last updated at Posted at 2020-01-24

記事の概要

 TestCafeについての記述の3回目です。
 今回はテストで何ができるかの概要の確認の為にテスト内容の記述について書いてます。ハンドブック的に使おうと思っているので詳しく知りたい場合はAPIのドキュメントを参照してください。
 APIの説明をを自分なりにかいつまんで書いているので、動作確認はしていません。間違ってたら教えてください。
 なんか、書いてたらAPIの日本語化+補足してるみたいになってしまいました。

テストの概要

 テストの流れはtestメソッドの呼び出しで初期のページを読み込んだ後は基本的に以下のような感じかと思います。
 1. 画面のエレメントや情報を取得する。(今回の記事)
 2. 画面を操作する(入力、クリック、ドラッグなど)
 3. アサーション(入力などのチェック)
 
 そのほか、特殊な処理として以下のようなことができるようです。(必要になれば調べますが現状はできることリストとしての覚書です)
・HTTPリクエストを補足して、ログを出したり仮のレスポンスを返したりすることができる。
・認証処理。ベーシック認証やWindows認証を実行させる
・テストのポーズ
・テストのデバッグ
・iフレームの対応
・ブラウザコンソールメッセージへのアクセス

画面のエレメントや情報を取得する

1.ブラウザやプラットフォーム情報の取得

 ブラウザやOSの情報を取得します。「all」を利用した場合など、ブラウザに応じて処理を分けたい場合に重宝します。テスト関数の引数のテストコントロール「t」のプロパティー「t.browser」の子プロパティから以下の内容が取得できます。

プロパティ 概要
alias 文字列 テスト中のブラウザのエリアス firefox:headless
name 文字列 ブラウザの名称 Chrome
version 文字列 バージョン 77.0.3865.120
platform 文字列 実行環境の種類 desktop、mobile、tablet、otherのいずれか
headless 真偽値 ヘッドレスモードかどうか true:ヘッドレスモード
false:ヘッドレスではない
os オブジェクト OSの名前(nameプロパティ)とバージョン(versionプロパティ) { name: 'macOS', version: '10.15.1' }
engine オブジェクト ブラウザエンジンの名前(nameプロパティ)とバージョン(versionプロパティ) { name: 'Gecko', version: '20100101' }
userAgent 文字列 ユーザーエージェント Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/77.0.3865.120 Safari/537.36
prettyUserAgent 文字列 フォーマットされたブラウザとOSの名前とバージョン Chrome 77.0.3865.75 / macOS 10.14.0

 以下のように条件分岐させるときなどに使います。(サンプルは「fixture.beforeEach」で行っていますが、「test」でも同じ様に使います)

fixture `My fixture`
    .page `https://example.com`
    .beforeEach(async t => {
        if (t.browser.engine.name === 'Blink')
            return;

        // ...
    });

2.セレクタ(テストするWebページのエレメントのハンドルみたいなもの)

 クライアントページのエレメントに関する情報は以下のようなセレクタで取得します。これで取得したオブジェクトを利用して画面を操作したり、エレメントの情報を取得して条件分岐やアサーションを実施します。
 以下はそのコンストラクタです。

 Selector( init [, options] )
引数 概要
init 関数,文字列,Selector,Snapshot,Promise 対象を特定するための関数、文字列、他のセレクタ、スナップショット(*)、プロミス(*)など
options オブジェクト オプション

引数[init]

 セレクタの基本的な検索条件(もしくは方法)で以下のものがあります。

種類 概要 サンプル
文字列 CSSのセレクタ文字列 onst usernameInput = Selector('#username');
関数 クライアントサイドで実行させるDOMのアクセス関数 const element = Selector(() => {
return document.getElementById('targetId');< br />});
※この例では[id=targetId]のエレメントを取得しているが、基本的にはWebページのDOMから検索したエレメントを返せばよい
セレクタ ほかに作成したセレクタ
他のセレクタを設定してさらにオプションを追加する様な場合に利用
const ctaButton = Selector('.cta-button');
Selector(ctaButton, { visibilityCheck: true });
スナップショット 他のセレクタから取得した全ての属性と一致するものを取得。取得した属性の一部を変更してから利用することもできるみたい const topMenuSnapshot = await Selector('#top-menu')();
const visibleTopMenu = Selector(topMenuSnapshot, { visibilityCheck: true });
プロミス 引数のあるセレクタで引数を指定したもの? const elementWithIdOrClassName = Selector(value => { return document.getElementById(value) || document.getElementsByClassName(value); });
const submitButton = Selector(elementWithIdOrClassName('main-element')); });

 注意点としてはSelectorで取得したオブジェクトはあくまでTestCafeのオブジェクトであり、決してクライアントページのエレメントオブジェクトではないことに注意してください。(最初そう思ってたので取得したセレクタのプロパティを取ろうとしたら取れなかったという自分の失敗)

引数[options]

 セレクタの取得に対する以下のオプションが指定できます。

オプション 概要
boundTestRun Node.jsのコールバックで利用する場合のオプションの様です。このあたりは今回は調べてません。
dependencies Webページ内で実行する関数を定義した場合、テストスクリプト内の変数や関数を利用できるように依存情報として設定する。(APIのこれのサンプルで「customId」と書かれているのはソースの中では「persistentId 」の記述ミスだと思う)
timeout エレメントの取得に失敗するまでのタイムアウトを設定します。設定するとデフォルトの値(3000)やコマンドオプションや定義ファイルに記述できますが、ここで設定するとこの処理のみその値を利用します。
visibilityCheck visibleのコンポーネントを指定します。無ければエラーになります。ただし「count」等のメソッドではこのオプションは無視されるみたいです。

セレクタのフィルタ

 上で取得したセレクタは複数のエレメントを指していることがあり、一つまたは少数に特定するために以下のフィルタが利用できます。

メソッド 概要
nth(index) index番目
負の値の場合-1が最後尾で前に進む
Selector('ul').nth(2);
Selector('div').nth(-1);
withText(text) or withText(re) 内容にtextで与えた文字を含めたもの。
正規表現(\で括ったリテラル)の場合、正規表現に一致するもの
Selector('label').withText('foo');
Selector('div').withText(/a[b-e]/);
withExactText(text) テキストが完全一致するもの Selector('.container').withExactText('foo');
この場合、「foobar」や「Foo」は一致しない
withAttribute(attrName [, attrValue]) 属性があるかどうか、値が指定されれば値まで一致するもの。
属性名も値も正規表現が使える
Selector('div').withAttribute('myAttr');// 属性に「myAttr」があるもの
Selector('div').withAttribute('attrName', 'foo');// 属性に「attrName='foo'」があるもの
Selector('ul').withAttribute(/[123]z/, /a[0-9]/);// 正規表現の利用
filterVisible() 表示されているもの。
「display:none」や「visibility:hidden」、幅や高さが0のものは対象外
Selector('div').filterVisible();
filterHidden() 表示されていないもの。「filterVisible()」の反対 Selector('label').filterHidden();
filter(cssSelector) cssセレクタが一致するもの Selector('li').filter('.someClass')
filter(filterFn, dependencies) Webページ内で実行する関数を指定してフィルターする。
「dependencies」にはセレクタのコンストラクタと同じように依存性を設定する。
const isNodeOk = (node, idx) => { /.../ };
Selector('ul').filter((node, idx) => {
return isNodeOk(node, idx);
}, { isNodeOk });

セレクタからの相対セレクタの取得

 セレクタからの相対的な位置(親、子、同一階層)のセレクタの取得。

メソッド 概要
find(cssSelector)
find(filterFn, dependencies)
parent()
parent(index)
parent(cssSelector)
parent(filterFn, dependencies)
child()
child(index)
child(cssSelector)
child(filterFn, dependencies)
直下
sibling()
sibling(index)
sibling(cssSelector)
sibling(filterFn, dependencies)
同一階層(兄弟)
nextSibling()
nextSibling(index)
nextSibling(cssSelector)
nextSibling(filterFn, dependencies)
自身以降の同一階層
prevSibling()
prevSibling(index)
prevSibling(cssSelector)
prevSibling(filterFn, dependencies)
自身以前の同一階層

 引数無の場合は全てのエレメントのセレクタになります。 
 引数がある場合は以下のようになります。

引数 概要
index 数値 取得したリストのindex番目のセレクタで0が先頭。負の場合は最後尾からの位置で-1が最後尾。ただし「prevSibling」のみリストは逆順
cssSelector 文字列 cssセレクタが一致するもののみを抽出
filterFn,dependencies 関数、オブジェクト 取得した配列に対してフィルタする関数を指定する。テストスクリプト内の変数や関数を参照する場合は「dependencies」に記述する

 引数で関数を利用する場合は、その関数は以下の書式になります。(サンプルは「prevSibling」の場合)

 Selector('section').prevSibling((node, idx, originNode) => {
    // ここにフィルター処理を記述
});

引数は以下の通りです。

引数 概要
node オブジェクト 取得したリストの個々
idx 数値 配列内での先頭からの位置、0始まり
originNode オブジェクト 関数を実行している元のオブジェクト

セレクタの属性やメソッド

 セレクタは次回掲載予定の画面の操作に使えるほか、以下の属性やメソッドを利用して条件分岐やアサーションに利用します。ドキュメントではセレクタのエレメントの有無や個数と属性取得が別の章になっていますが、ここではまとめて一覧します。
 全てのセレクタに対するものと、エレメントを指すセレクタのみしか使用できないものがあります。

種別 対象 記述 属性 概要
メンバ 全て exist 真偽値 対象のエレメントの存在。
メンバ 全て count 数値 エレメントの個数
メンバ 全て childElementCount 数値 子エレメントの個数
メンバ 全て childNodeCount 数値 子ノードの個数
メンバ 全て hasChildElements 真偽値 子エレメントの存在。
メンバ 全て hasChildNodes 真偽値 子ノードの存在。
メンバ 全て nodeType 列挙 DOMのノードの種類
メンバ 全て textContent 文字列 ノード内の文字列
メソッド 全て hasClass(className) 真偽値 引数「className」を継承しているかどうか
メンバ エレメント attributes オブジェクト エレメントの属性値を{name:value,...}形式で返す。
後述のメソッド「getAttribute」で個々に取得できる
メンバ エレメント boundingClientRect オブジェクト ビューポートに対する相対のエレメントの位置と大きさ。
left、ight、bottom、top、width、heightが取得できます。
後述のメソッド「getBoundingClientRectProperty」で個々に取得できる
メンバ chekubox or radiobuttonエレメント checked 真偽値 チェックされているかどうか
メンバ エレメント classNames  文字列リスト classに設定されているリスト
メンバ エレメント clientHeight 数値 エレメントの高さ。paddingは含むが、スクロールバー、罫線、マージンは含まない。
DOMのエレメントの「clientHeight」属性
メンバ エレメント clientLeft 数値 エレメントの左
DOMのエレメントの「clientLeft」属性
メンバ エレメント clientTop 数値 エレメントの上
DOMのエレメントの「clientTop」 属性
メンバ エレメント clientWidth 数値 エレメントの幅。paddingは含むが、スクロールバー、罫線、マージンは含まない。
DOMのエレメントの「clientWidth」属性
メンバ エレメント focused 真偽値 フォーカスされているかどうか
メンバ エレメント id 文字列 エレメントのID
DOMのエレメントの「id」属性
メンバ エレメント innerText 文字列 表示されるテキスト
DOMのエレメントの「innerText 」属性
メンバ エレメント namespaceURI 文字列 ネームスペースのURI.ネームスペースが無い場合はnullになる
DOMのエレメントの「Element.namespaceURI」
メンバ エレメント offsetHeight 数値 エレメントのpaddingと罫線を含む高さ
DOMのエレメントの「offsetHeight 」属性
メンバ エレメント offsetLeft 数値 エレメントの親の左端からのエレメントの左端までのピクセル数
DOMのエレメントの「offsetLeft 」属性
メンバ エレメント offsetTop 数値 エレメントの親の上端からのエレメントの上端までのピクセル数
DOMのエレメントの「offsetTop 」属性
メンバ エレメント offsetWidth 数値 エレメントのpaddingと罫線を含む幅
DOMのエレメントの「offsetWidth」属性
メンバ Optionエレメント selected 真偽値 optionタグで選択されているものがあるかどうか
メンバ Optionエレメント selectedIndex 数値 optionタグで選択されている要素のインデックス
メンバ エレメント scrollHeight 数値 スクロールして表示されていない部分を含むエレメントの高さ
メンバ エレメント scrollLeft 数値 横方向のスクロール量
メンバ エレメント scrollTop 数値 縦方向のスクロール量
メンバ エレメント scrollWidth 数値 スクロールして表示されていない部分を含むエレメントの幅
メンバ エレメント style オブジェクト エレメントに適用されている最終的なcssの情報
後述のメソッド「getStyleProperty」でも取得できる
メンバ エレメント tagName 文字列 エレメントのタグ名
メンバ inputエレメント value 文字列 inputタグのvalue
メンバ エレメント visible 真偽値 エレメントのvisible状態。display:noneやvisibility:hiddenではなく幅や高さも0でない場合true。それ以外はfalse
メソッド エレメント getStyleProperty(propertyName) オブジェクト 「propertyName」名のcssプロパティーを取得する
メソッド エレメント getAttribute(attributeName) 文字列 「attributeName」名の属性の値を取得する
メソッド エレメント getBoundingClientRectProperty(propertyName) 数値 エレメントのビューポートに対する相対のエレメントの位置と大きさの「propertyName」のメンバの値を取得
メソッド エレメント hasAttribute(attributeName) 真偽値 「attributeName」の属性が設定されているかどうか

そのほかセレクタに関する記述

 そのほかセレクタについて以下の記述がありますが、ここでは説明しませんので興味があればドキュメントのAPIを見てください。(必要になった時に加筆するかも)
 ・ セレクタに独自の属性を追加する
 ・ Edgeに対する制限
 ・ 以下のフレームワークに対する情報
  React
  Angular
  AngularJS
  Vue
  Aurelia

2.ブラウザページでスクリプトを実行して情報を取得(クライアント関数)

 上記のセレクタのメンバ やメソッドでは取得できない情報をWebページから取得する場合、以下のクライアントサイドスクリプトで取得します。
 

ClientFunction( fn [, options] )

引数 概要
fn 関数 Webページ内で実行する処理
options オブジェクト オプション

クライアントで実行する処理

 以下はWebページでのURLを取得するサンプルです。

test('My Test', async t => {
    const location = await getWindowLocation();
});

クライアントで非同期処理を実行したい場合

 クライアントで非同期処理を実行したい場合、Promiseを利用して以下の様に記述し、取得したPromiseの結果に応じた処理を記述するようです。

const performAsyncOperation = ClientFunction(() => {
    return new Promise(resolve => {
        window.setTimeout(resolve, 500); // some async operations
    });
});
// この後、thenメソッドで結果に応じた処理を記述する

定義せずに1回限りのクライアント処理を行う方法

 1回限りのクライアント関数を定義して実行するのが無駄に感じるので、これは結構使えそうです。即時関数みたいのものですね。

t.eval( fn [, options] )

 以下は「document.documentURI」を取得している例です。

test('My Test', async t => {
    const docURI = await t.eval(() => document.documentURI);
});

クライアント関数での制限

 ・クライアント関数内では「async」「await」は使えません。
 ・テストのスコープ外の変数は使えません。

その他のAPIの概要

 APIには以下の事も記述されていますが、私は使いそうにないので調べてません。必要なら知れべてください。

 ・クライアント関数内で別のスクリプトをインポートする方法
 ・Node.jsでのコールバックの方法

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5