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{ ... } の中に改行を含めることができ ました。