読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり所属会社の見解とは無関係です。 GitHub: takahashikzn

SeleniumのコマンドをjQueryで拡張する

Javascript


Seleniumでは、HTML内の要素を特定する方法はXPathがデフォルトです。
一応、セレクタも使えるようですが、jQueryセレクタに慣れた身としてはかゆいところに手が届かない感じです。


というわけで、jQueryセレクタベースのassertコマンドを作りました。
ライセンスはASLにしますのでご自由にどうぞ。


使い方は簡単。Selenium IDEの設定で『Selenium Core 拡張スクリプト』で以下のファイルを指定するだけです。
言うまでもないことですが、テスト対象のページでjquery.jsがロード済みであることが前提です。

JSのコード

/**
 * @license Copyright (C) 2013 root42 Inc. All rights reserved.
 */
/**
 * @version $Id: user-extensions.js 11461 2013-06-12 11:48:57Z kaz $
 */
"use strict";

/**
 * @private
 * @param {!string} name
 * @return {?}
 */
Selenium.prototype._resolve = function(name) {

    /** @type {?} */
    var win = this.page().getCurrentWindow();

    return win[name] || win.wrappedJSObject[name];
};

/**
 * @private
 * @const
 * @type {!RegExp}
 */
Selenium.prototype._regexMatcher = /m([\!\/\#\%\;\:\^\|])(.*)\1(\w*)/;

/**
 * @private
 * @param {!function(Object)} extractor
 * @param {?} expected
 * @param {?} msg
 */
Selenium.prototype._assert = function(extractor, expected, msg) {

    /** @type {?} */
    var console = this._resolve('console');
    /** @type {!jQuery} */
    var jQuery = this._resolve('jQuery');

    try {
        /** @type {?} */
        var actual = extractor({
            '$': jQuery
        }, console);

        console.info(expected, actual);

        if (((typeof expected) === 'string') && Selenium.prototype._regexMatcher.test(expected)) {

            /** @type {!Array.<!string>} */
            var tokens = expected.match(Selenium.prototype._regexMatcher);

            expected = new RegExp(tokens[2], tokens[3]);
        }

        if (expected instanceof RegExp) {
            actual = expected.test('' + actual);
            expected = true;
        } else {
            actual = '' + actual;
            expected = '' + expected;
        }

        // @see Assertについてはhtmlutils.jsを参照
        // https://code.google.com/p/selenium/source/browse/javascript/selenium-core/scripts/htmlutils.js
        if (msg) {
            msg = jQuery.isFunction(msg) ? msg(expected, actual) : msg;
            Assert.equals(msg, expected, actual);
        } else {
            Assert.equals(expected, actual);
        }
    } catch (e) {
        console.warn(e);
        throw e;
    }
};

/**
 * セレクタにマッチする要素が存在することを検証する。
 * 
 * @public
 * @param {!string} selector
 */
Selenium.prototype.doJqAssertPresent = function(selector) {
    this._assert(function(env) {
        return env.$(selector).length !== 0;
    }, true);
};

/**
 * セレクタにマッチする要素が存在しないことを検証する。
 * 
 * @public
 * @param {!string} selector
 */
Selenium.prototype.doJqAssertNotPresent = function(selector) {
    this._assert(function(env) {
        return env.$(selector).length;
    }, 0);
};

/**
 * セレクタにマッチする要素の数を検証する。
 * 
 * @public
 * @param {!string} selector
 * @param {!number} count
 */
Selenium.prototype.doJqAssertPresentCount = function(selector, count) {
    this._assert(function(env) {
        return env.$(selector).length;
    }, count);
};

/**
 * セレクタにマッチする要素内のテキストが、指定したパターンに一致することを検証する。
 * 
 * @public
 * @param {!string} selector
 * @param {!(string|RegExp)} expected 期待値のパターン。正規表現風文字列(m/.../)は正規表現であるとみなす
 */
Selenium.prototype.doJqAssertTextPresent = function(selector, expected) {
    this._assert(function(env) {
        return env.$(selector).text().trim();
    }, expected);
};

/**
 * セレクタにマッチする要素内のテキストが、指定したパターンに一致しないことを検証する。
 * 
 * @public
 * @param {!string} selector
 * @param {!(string|RegExp)} expected 期待値のパターン。正規表現風文字列(m/.../)は正規表現であるとみなす
 */
Selenium.prototype.doJqAssertTextNotPresent = function(selector, expected) {
    this._assert(function(env) {

        if (((typeof expected) === 'string') && Selenium.prototype._regexMatcher.test(expected)) {

            /** @type {!Array.<!string>} */
            var tokens = expected.match(Selenium.prototype._regexMatcher);

            expected = new RegExp(tokens[2], tokens[3]);
        }

        if (expected instanceof RegExp) {
            return !expected.test(env.$(selector).text().trim());
        } else {
            return env.$(selector).text().trim().indexOf(expected) < 0;
        }
    }, true);
};

/**
 * セレクタにマッチする要素内のテキストが、指定した文字列を含むことを検証する。
 * 
 * @public
 * @param {!string} selector
 * @param {!string} expected 期待値
 */
Selenium.prototype.doJqAssertTextContain = function(selector, expected) {
    this.doJqAssertTextPresent(selector, new RegExp('.*' + expected + '.*', 'g'));
};

/**
 * セレクタにマッチする要素内のテキストが、指定した文字列を含まないことを検証する。
 * 
 * @public
 * @param {!string} selector
 * @param {!string} expected 期待値
 */
Selenium.prototype.doJqAssertTextNotContain = function(selector, expected) {
    this.doJqAssertTextNotPresent(selector, new RegExp('.*' + expected + '.*', 'g'));
};

/**
 * セレクタにマッチする要素をクリックする。
 * 
 * @public
 * @param {!string} selector
 */
Selenium.prototype.doJqClick = function(selector) {
    /** @type {!jQuery} */
    var jQuery = this._resolve('jQuery');
    jQuery(selector).click();
};

テストコード(Selenium)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://jquery.com/" />
<title>test</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">test</td></tr>
</thead><tbody>
<tr>
	<td>open</td>
	<td>http://jquery.com/</td>
	<td></td>
</tr>
<tr>
	<td>jqClick</td>
	<td>.logo:eq(1)</td>
	<td></td>
</tr>
<tr>
	<td>jqAssertPresent</td>
	<td>.logo</td>
	<td></td>
</tr>
<tr>
	<td>jqAssertNotPresent</td>
	<td>.hogehoge</td>
	<td></td>
</tr>
<tr>
	<td>jqAssertPresentCount</td>
	<td>.logo</td>
	<td>5</td>
</tr>
<tr>
	<td>jqAssertTextNotPresent</td>
	<td>html</td>
	<td>m/j[Qq]uely/</td>
</tr>
<tr>
	<td>jqAssertTextNotPresent</td>
	<td>html</td>
	<td>jQuely</td>
</tr>
<tr>
	<td>jqAssertTextPresent</td>
	<td>html</td>
	<td>m!Jquery!i</td>
</tr>
<tr>
	<td>jqAssertTextPresent</td>
	<td>.menu-item:eq(0)</td>
	<td>Download</td>
</tr>
<tr>
	<td>jqAssertTextContain</td>
	<td>html</td>
	<td>jQuery</td>
</tr>
<tr>
	<td>jqAssertTextNotContain</td>
	<td>html</td>
	<td>jQuely</td>
</tr>
</tbody></table>
</body>
</html>