Selenium では、フィールドを JavaScript で記述することができます。 例えば
<tr>
<td>verifyText</td>
<td>hoge</td>
<td>javascript{var d = new Date(); d.getFullYear()}</td>
</tr>
は、JavaScript が解釈されて
<tr> <td>verifyText</td> <td>hoge</td> <td>2006</td> </tr>
とみなされます(2006年の場合)。値を動的に決定したいときには便利です。
ところが、これに
<tr>
<td>verifyText</td>
<td>hoge</td>
<td>javascript{var d = new Date();
d.getFullYear()}</td>
</tr>
のように改行を入れてしまうと、IE6 だと動くのですが、Firefox 1.5 だと動かな くなってしまうのに気がつきました。
この原因を調べてみました。
`javascript' というキーワードに反応して JavaScript が実行されるので、 js ファイルに対して `javascript' で grep してみると、selenium-api.js に処理があることが分かりました。Selenium.preprocessParameter がそれで す。
Selenium.prototype.preprocessParameter = function(value) {
var match = value.match(/^javascript\{(.+)\}$/);
if (match && match[1]) {
return eval(match[1]).toString();
}
return this.replaceVariables(value);
}
テストの JavaScript 文に改行を入れたときこの関数に渡ってくる値を alert で見てみました。すると、IE だと改行がなくなっているのに対し、Firefox では改行が そのまま入っているのが分かりました。
preprocessParameter は selenium-executionloop.js の中にある TestLoop.executeCurrentCommand から呼び出されていて、引数には command.target と command.value という値が渡されています。
この command オブジェクトの出自を調べていくと、 selenium-testrunner.js の
function nextCommand() {
var row = currentTest.nextCommand();
if (row == null) {
return null;
}
row.cells[2].originalHTML = row.cells[2].innerHTML;
return new SeleniumCommand(getText(row.cells[0]),
getText(row.cells[1]),
getText(row.cells[2]));
}
にたどりつきます。さらに getText は htmlutils.js で定義されていて、 その定義は次のようになっています。
function getText(element) {
text = "";
if(element.textContent) {
text = element.textContent;
} else if(element.innerText) {
text = element.innerText;
}
// Replace with a space
// TODO - should this be in the match() code instead?
text = text.replace(/\240/g, " ");
return text.trim();
}
これで大本にたどりつきました。 textContent と innerText について IE と Firefox での挙動を調べてみると
という結果になりました。(ちなみに、element.firstChild.nodeValue にしても改行に関しては同じ結果です)
よって元に戻ると、preprocessParameter で
var match = value.match(/^javascript\{(.+)\}$/);
によって javascript の処理をするかどうかを判定する際、 `.' が改行にマッチしないために IE と Firefox によってテストの挙動が変 わっていたということになります。
正規表現でのマッチの際、文字列に改行が含まれうることを考慮して
var match = value.match(/^javascript\{((.|\r?\n)+)\}$/);
にすると、Firefox でも javascript{ ... } の中に改行を含めることができ ました。