From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- files/ja/mozilla/projects/mochitest/index.html | 220 ++++++++++ .../projects/mochitest/specialpowers/index.html | 471 +++++++++++++++++++++ 2 files changed, 691 insertions(+) create mode 100644 files/ja/mozilla/projects/mochitest/index.html create mode 100644 files/ja/mozilla/projects/mochitest/specialpowers/index.html (limited to 'files/ja/mozilla/projects/mochitest') diff --git a/files/ja/mozilla/projects/mochitest/index.html b/files/ja/mozilla/projects/mochitest/index.html new file mode 100644 index 0000000000..e649f3c059 --- /dev/null +++ b/files/ja/mozilla/projects/mochitest/index.html @@ -0,0 +1,220 @@ +--- +title: Mochitest +slug: Mozilla/Projects/Mochitest +tags: + - Automated testing + - Developing Mozilla +translation_of: Mozilla/Projects/Mochitest +--- +

Mochitestは、MochiKit JavaScriptライブラリに基づいて構築された自動テストフレームワークです。これはMozillaによって利用されている、後退バグの自動テストフレームワークの一つです。テストはテストハーネスに対して、JavaScriptの関数を用いて成功あるいは失敗の旨を報告します。

+

Mochitestのユニークな特長は、Webページの形で書かれたテストを、完全なブラウザ環境の中でChrome(に昇格した)特権付きで実行できるという点です。これは、他のフレームワークでできることよりも非常に多くの事をテストの中のJavaScriptでできるようにします。通常のスクリプトが可能な事(DOM操作など)に加えて、テストのスクリプトはXPCOMコンポーネントやサービス、そしてブラウザそれ自体にすらもアクセスする事ができます。これによって、例えば、入力が意図されたとおりの結果をもたらすかどうかを確認するために、ブラウザのユーザーインターフェースに対してユーザによる入力をシミュレートして渡すなどのことができます。

+

Mochitestにおける、テストの成否を通知するためのJavaScript関数の呼び出し方は、いくつかの種類のテストに対しては不向きです。(Chrome特権付きの)JavaScriptによってテストできるような内容だけが、このフレームワークを使ってテストできます。創造性を発揮する事によって、あなたが最初に考えているよりもずっとたくさんの事ができますが、しかし、例えばスクリプトではないC++のコンポーネントを直接テストするようなMocihkitテストを書く事は不可能です(それを行うにはコンパイル済みコードのテストを使ってください)。

+

テストを実行する

+

MozillaのビルドマシンはMochitestをビルドの過程の一つとして実行します。そのため、誰かがソースコードにコミットした変更が何かを壊していれば、それを極めて迅速に知る事ができます。しかし依然として、あらゆる新しい危険性のあるコードをコミットする前には、あなた自身の手でMochitestを走らせておくべきです。あなたも、避けられるなら、ツリーを壊して他のみんなの時間を無駄にさせる元凶になどなりたくないでしょう? :-)

+

テストスイート全体を実行する

+

Mochitestを実行するには、まずあなたが行った変更を含めてMozillaをビルドします。次に、以下のようにします:

+ +

Image:Mochitest.png

+

注意: テストを実行している間は、ブラウザウィンドウがフォーカスされた状態を保つべきです。そうでないと、いくつかのテストが失敗する事があります(例えば{{ Bug(330705) }}のテストがそうです)。Linuxユーザは、ダミーのXサーバを使う事でその状態を保存する事ができます(後述のXの出力を迂回させる手順を参照してください)。

+

テストを選択して実行する

+

テストを一つだけ実行する場合(あなたが書いたばかりの新しいテストなど)や、Mochitestスイート全体のうち一部分だけを実行する場合は、runtests.pyの--test-pathオプションを使って、実行したいテストまたはサブディレクトリを指定してください。例えば、Mozillaのソースツリーの{{ Source("content/base/test/test_CrossSiteXHR.html", "test_CrossSiteXHR.html") }}のテストだけを実行したい場合は、以下のようなコマンドを使う事になります:

+
TEST_PATH=content/base/test/test_CrossSiteXHR.html make -C $(OBJDIR) mochitest-plain
+
+

あるいは、mochitest-plain targetがサポーとされていないブランチでは以下のようにします:

+
python runtests.py --test-path=content/base/test/test_CrossSiteXHR.html
+

{{ Source("content/svg/") }}の中にあるすべてのテストを実行する場合は、以下のコマンドを使います:

+
TEST_PATH=content/svg/ make -C $(OBJDIR) mochitest-plain
+
+

--test-pathによって指定されるパスは、Mozillaのソースツリー内のテストまたはディレクトリへの物である事に注意してください。パスがディレクトリの場合、そのディレクトリおよびすべてのサブディレクトリ内のテストが読み込まれます。

+

{{ h3_gecko_minversion("Gecko 2.0 およびそれ以降で特定のテストを実行する", "2.0") }}

+

Gecko 2.0 {{ geckoRelease("2.0") }} から、mochitest-1 から mochitest-5 までを make コマンドで簡単に実行できるようになりました。例:

+
make mochitest-1
+
+

これによって、すべてのテストスイートを実行したり、トライサーバの buildbot のコードを調べて特定のテストだけを実行するための書き方を調べる代わりに、buildbot の挙動を真似る事ができます。

+

個々のテストのデバッグ

+

ある1つのテストについてデバッグする必要が生じた場合に、そのテストだけを実行するために、Firefox にデバッガをアタッチし、デバッガがアタッチされた状態でテストを含むページをリロードするのにも、前述の方法が利用できます。もし問題が起こる前にデバッガをアタッチする事が難しい場合には(例えば、テストが読み込まれた時にブラウザがクラッシュするような場合)、以下のようにしてテストスイート全体をまず最初に実行できます:

+
python $OBJDIR/_tests/testing/mochitest/runtests.py
+
+

この時、デバッガをアタッチして、新しいタブを開き、"http://mochi.test:8888/tests/PATH/TO/MY/TEST" のようにテストを手動で指定することができます。例: "http://mochi.test:8888/tests/modules...ginstream.html"

+

あるいは、あなたはmochitestの実行時にデバッガを指定するよう試みるかもしれません:

+
TEST_PATH='...' EXTRA_TEST_ARGS='--debugger=gdb' make mochitest-plain
+
+

引数の --debuggerArgs と --debuggerInteractive も参照してください。

+

エラーを探す

+

予期されない失敗を探すには、「TEST-UNEXPECTED-FAIL」という文字列を検索してください。最終的なテストの実行結果の要約を見るには「SimpleTest FINISHED」を検索してください。連結されたログではMochitestの出力は最後にあるとは限らないので、すべてのTinderboxのログをまとめて見る時に、後者は特に便利です。

+

結果のロギング

+

テストの実行による出力は、コンソールおよび(または)ファイルに送る事ができます(デフォルトでは、結果はブラウザ上にのみ表示されます)。出力の詳細さはいくつかのレベルで指定できます。DEBUG、INFO、WARNING、ERROR、FATALの各レベルがあり、DEBUGでは出力は最も詳細(すべて出力)になり、FATALでは出力は最も少なく(テストを中断させるようなイベントが発生した時だけメッセージを出力)なります。

+

ファイルにログを保存するには --log-file=ファイルのパス オプションを使います。デフォルトではファイルへのログ出力レベルはINFOですが、--file-level=レベル オプションを使う事でレベルを変更できます。

+

コンソールへのログ出力を有効にするには、--console-level=レベル オプションを使います。

+

例えば、テスト実行時の出力を ~/mochitest.log というファイルにDEBUGレベルの詳細さで保存したい場合は以下のようになります:

+
python runtests.py --log-file=~/mochitest.log --file-level=DEBUG
+
+

Xの出力を迂回させる

+

テスト実行中のコンピュータでユーザが行うあらゆる他の操作による影響を防ぐために、テストは必ずフォーカスされたウィンドウの中で実行されなくてはなりません。Linuxユーザはスイートに指示を与える事で、不可視の仮想デスクトップを使うようにすることができます。もしXvfbがインストールされている、またはインストールできる場合は、以下のコマンドは現在のセッションをブロックすることなくテストを実行します。:

+
nice xvfb-run python _tests/testing/mochitest/runtests.py --log-file=./mochitest-plain.log --file-level=DEBUG --autorun --close-when-done --console-level=DEBUG
+
+

他に可能な設定については、{{ Bug(434365) }}で議論されています。

+

runtests.pyのその他のオプション

+

runtests.pyスクリプトは他にもいくつかのオプションを解釈します。それらの一覧を見るには --help オプションを使ってください。ちなみに、--chrome--browser-chrome--a11yの各オプションについては個別のドキュメントがあります。

+

テストを書く

+

Mochitest用のテストファイルは、いくつかの条件についてテストを行うJavaScriptを含んだシンプルなHTML、XHTML、またはXULのファイルです。

+

Mozillaをビルドせずに大部分のテストを実行するために、Mochitest makerを利用できます。

+

Mochitestを使わない事を試みる

+

はい、これは冗談ではなく本当にです。様々な理由のために、Mochitestは過剰な物となっています。一般的な用途では、より軽量なテストフレームワーク使うように常に試みる事をお勧めします。例えば、ある一つのXPCOMコンポーネントをテストしたいだけであれば、xpcshellを使うべきです。また、Mochitestにもできない事や、それをするようには設計されていないという事がいくつかあります。こちらの例は視覚的な出力についてのテストで、その場合はreftestフレームワークを使うのがお勧めです。他の異なる種類の自動テストフレームワークについての情報は、Mozillaの自動テストを参照してください。

+

テストのテンプレート

+

定型的な内容を毎回入力する手間を省くために、{{ Source("testing/mochitest/gen_template.pl", "gen_template.pl") }} Perlスクリプトがテストのテンプレートの生成に利用できます。このスクリプトは2つの省略可能な引数を取ります:

+
    +
  1. -b : バグの番号。
  2. +
  3. -type : 連符レートの種類。html、xhtml、xul のいずれかを選択する。デフォルトはhtml。
  4. +
+

利用例:

+
cd mozilla/testing/mochitest/
+perl gen_template.pl -b=123456 > path/to/test_bug123456.html
+perl gen_template.pl -b=123456 --type=xul > path/to/test_bug123456.xul
+
+

Mochitest ではすべてのテストのファイル名は「test_」で始まっている必要がある事に注意してください。テストをツリーのどの位置に置けばよいのかを決める手助けとしては、後述の内容を参照してください。

+

Mochitest の定型的なコードに加えて、このスクリプトは 'content' という id を持った要素と 'display' という id を持った要素も生成するでしょう。あなたが書くテストでは、これらを他のあなたが追加する要素と同様に操作して構いません。

+

テスト関数

+

個々のテストは、Mochitestに対してテストが成功したのか失敗したのかを通知するために実行されるいくつかのJavaScriptを含んでいる必要があります。 {{ Source("testing/mochitest/tests/SimpleTest/SimpleTest.js", "SimpleTest.js") }} は、テストにおいてMochitestにテストの成否を知らせるための様々な関数を含んでいます。これらには以下の物が含まれます:

+ +

これらの関数の使い方の例は、 {{ Source("testing/mochitest/README.txt", "README") }} を参照してください。

+

もし、現在のところは失敗するというテストを含めたい場合、単にその部分をコメントアウトしないでください! その代わりに、 相当する「todo」を使ってください。これによってTinderboxは、不意にテストが成功するようになった時に、(いつの時点でテストが成功するようになったのかを)知らせる事ができます。:

+ +

ヘルパー関数

+

現時点では、すべてのMochikitの機能が利用できます(これは{{ Bug(367393) }}によって変わるでしょう)。{{ Bug(367569) }}で、ヘルパー関数としてsendCharsendKeysendStringが追加されました。これらは{{ Source("testing/mochitest/tests/SimpleTest/EventUtils.js") }}において利用できます。

+

テストをツリーに追加する

+

新しいテストを書いたら、すぐにそれをMozillaのソースツリーに追加して、ビルドシステムにその事を通知する必要があります。これによって、Mozilla tinderboxはそれを自動的に実行するようになります。

+

場所の選択

+

新しいMochitestのテストはテストされるコードの近くのどこか、できれば同じモジュールに置かれるべきで、これにより、テストケースが何のための物なのかが明確になります。例えば、あるHTMLの機能のテストを作成した場合、おそらく、テストを{{ Source("content/html/content/test") }}または{{ Source("content/html/document/test") }}に置きたいと思うでしょう。もしも、テストしようとしているコードの近くにテスト用のディレクトリがなければ、{{ Bug(368531) }}のパッチで実際にそうしているように、新しいテスト用のディレクトリを作成する事ができます。

+

Makefileの変更

+

あなたが書いた新しいテストの事をビルドシステムに通知するために、あなたが書いたテストファイルの名前をそのテストディレクトリのMakefile.inの中の_TEST_FILESに追加する必要があります。

+

もしもあなたが書いたテストが複数のファイルに渡っているなら、その場合はメインのファイルの名前を「test_...」としてください。これは実行するテストのリストに登場する名前となります。他のファイルはそれ以外の名前になっているべきですが、Makefile.in_TEST_FILESに追加されなければならないという点は変わりません。

+

Chromeのテストを追加する場合、テストを _tests/testing/mochitest/tests ではなく _tests/testing/mochitest/chrome にインストールするようMakefileを変更する事を忘れないでください。

+

ビルドと新しいテストの実行

+

新しいテストをコミットする前に、Makefile.inの変更内容が正しく、また、あなたが書いたテストが期待通りに成功する事を確認してください。あなたが書いたテストを確認するには、まず、以下のコマンドでそのテストをMochitestのディレクトリ(ソースツリーのテストファイルの位置と同じ場所)に取り出してください:

+
make
+
+

次に、Mochitestを前述の通りに開きますが、この時、「Run Tests」リンクをクリックする代わりに、あなたが書いたテストを一覧から探してそれをクリックしてください。

+

SSLとhttpsを有効にしたテスト

+

Mochitestのテストは、正常な動作のために http://localhost:8888 で実行されなくてはなりません。しかし、テストの中にはオリジンが異なる場合のための機能のテストとして、他のプロトコル、ホスト、ポートを使う必要があるものもあるでしょう。Mochitestのテストハーネスは、元のサーバのすべてのコンテンツをproxy autoconfigとSSLトンネリングを用いて他の様々なサーバに同期(ミラー)することで、この問題を解決します。テストを実行したいすべてのスキーム、ホスト、ポートのリスト(それらはすべて http://localhost:8888 と完全に同じコンテンツを返す必要があります)は{{ Source("build/pgo/server-locations.txt") }}で指定します。ただし、そこに記述されたオリジンのすべてが完全に同じである必要はありません。テスト用として特定のSSL証明書を指定された物や、そのサーバ上のページで特権の昇格の要求を許可する物も設定できます。完全な詳細説明については、ファイルの内容を参照してください。

+

動作させる方法

+


+ Mochitestのハーネスは、要求されたURLをサーバにマッチさせるためにブラウザにproxy autoconfig を使わせる設定を含んでいます。network.proxy.autoconfig_url の設定は、要求されたURLがマップされているホストを認識するためのFindProxyForURLという JavaScript 関数をエンコードしたdata: URLがセットされます。SSLのサイトがミラーされる場合、その関数はリクエストを、RFC 2817で定められたCONNECTメソッドによる説明に応じて、トラフィックを実際のサーバへ透過的に転送するSSLトンネルにマップします。このようにして、http://127.0.0.1:8888に立てられた単一のサーバは異なる場所を示す何十ものサーバをエミュレートします。

+

MochitestのSSL関連の機能や、署名を変更する方法、新しいhttpsのサーバを追加する手順などのさらに詳細な説明については、MochitestのSSLの動作の変更を参照してください。

+

スタックトレースの取得

+

Mochitest がクラッシュした時のスタックトレースを取得する方法は以下の通りです:

+
    +
  1. http://hg.mozilla.org/build/tools/fi...e49a/breakpad/ からあなたのプラットフォーム用の minidump_stackwalk のバイナリを取得します。
  2. +
  3. 環境変数 MINIDUMP_STACKWALK にそのバイナリのパスを指定します。
  4. +
+

もし結果のスタックトレースが行番号を含んでいない場合には、必須のシンボルファイルを生成するために make buildsymbols を実行して下さい。詳しくは Firefox をデバッグ用のシンボル付きでビルドするを参照して下さい。

+

FAQ

+

onloadイベントの時に実行されるようなテストが動かない時はどうすればいいですか?

+

onloadイベントが発行される前に SimpleTest.waitForExplicitFinish() を呼んでください。その場合は、テストを完了したら SimpleTest.finish() を呼んでください。

+

テストの中で設定(Preference)を変える必要がある時はどうすればいいですか?

+
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var prefService = Components.classes["@mozilla.org/preferences-service;1"]
+                            .getService(Components.interfaces.nsIPrefService);
+var domBranch = prefService.getBranch("dom.");
+var oldVal = domBranch.getIntPref("max_script_run_time");
+domBranch.setIntPref("max_script_run_time", 0);
+
+// 必要な処理(テストの内容)
+
+domBranch.setIntPref("max_script_run_time", oldVal);
+
+

あるテストを実行している間だけ設定を変更する必要がある場合には、make target mochitest-plain を実行する時に環境変数 EXTRA_TEST_ARGS を設定して下さい。

+
EXTRA_TEST_ARGS='--setpref=javascript.options.jit.chrome=false'
+
+

文字列型の設定を変更する必要がある場合は、バックスラッシュでエスケープしたダブルクォートで文字列を括ります:

+
EXTRA_TEST_ARGS='--setpref=webgl.osmesa=\"libOSMesa.so.6\"'
+
+

テストはChrome URLの中でも実行できますか?

+

はい。 python runtests.py --chrome を使ってください。ただしXPCOMをテストするための最初の選択肢としてはxpcshellテストハーネスを使うべきであることを心に留めておいてください。Mochitestが必要になるのは、イベントやブラウザの機能、ネットワーク関係の機能がテストに必要な場合だけです。

+

どうすれば「Permission denied to get property XPCComponents.classes」エラーを回避できますか?

+

以下の行をあなたの書いたテストファイル(およびそれぞれのイベントハンドラ)に書き加えてください。すべてのXPCOMが利用できるようになるでしょう。

+
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+

この方法は明らかに不便です。これこそが、テスト実行用にテストをChromeのディレクトリにコピーするのに必要なハックを行おうと私たちが作業している理由です。

+

Mochitestで使われるファイルのHTTPヘッダやステータスを変えるにはどうすればよいですか?

+

テキストファイルを作成して、ヘッダを変えたいと思っているファイルの隣に置いてください。テキストファイルの名前はヘッダを変えようとしているファイルの名前の末尾に ^headers^ を付けた物にします。例えば foo.jpg というファイルがある場合は、テキストファイルの名前は foo.jpg^headers^ となります。(ヘッダ指定用のファイルはテストの中で他の目的では使わないでください。HTTPサーバの不可視ファイル機能は、「^」で名前が終わっているすべてのファイルを見えなくするからです。)そして、あなたが設定したいヘッダおよび(もしくは)ステータスをそのファイルの内容として記述してください。例:

+
HTTP 404 Not Found
+Content-Type: text/html
+Random-Header-of-Doom: 17
+
+

最初の行はそのファイルに関連付けられたHTTPステータスと(任意で)説明文を設定しています。この行は省略可能で、通常のレスポンスステータスと説明文で問題ない場合は記述する必要はありません。他の行は、レスポンスヘッダ中で追加または上書きしたい(後者の最も典型的な例はContent-Typeヘッダでしょう)、そのファイルについて説明する追加のヘッダです。様式はHTTPの仕様でのものと同じですが、HTTPの行末を示す必要は無く、一つのヘッダを複数書く事はできません(同じヘッダを複数回多場合は最後の物だけが有効となります)。 ファイルはUnixのテキストファイルの様式に沿って一つの空行で終わる場合がありますが、それは厳密に必要というわけではありません。

+

複数のドメインに渡って実行されるテストでのみ発生する事象をテストするにはどうすればよいですか?

+

Mochitestのハーネスはテストを行うために一つのWebサーバだけを起動しますが、proxy autoconfigの働きにより、すべてのテストファイルは異なるドメイン、異なるポートで実行できます。これらのサーバ(権限昇格のための機能に関する2つの例外を除く)で動作しているあらゆるテストは自動的に、UniversalXPConnectなどの特権の取得を要求する事ができるようになります。テストの実行が可能で、http://localhost:8888と全く同じコンテンツを提供するドメインとポートの完全なリストは、{{ Source("build/pgo/server-locations.txt") }}で指定されます。

+

HTTPリクエストのヘッダの値、メソッドの種類などを確認するテストはどのように書けばよいですか?

+

その種のテストを書くには、それ用のSJS(server-side JavaScript)を書くだけでよいです。SJSは sjs という拡張子を持つ単純なJavaScriptファイルで、サンドボックス内に読み込まれます。スクリプト内でグローバルな名前空間において handleRequest という名前で定義された関数は、リクエストとレスポンスのオブジェクトを伴って実行され、そのスクリプトはリクエストの情報に基づいてレスポンスを生成します。

+

以下は単純なSJSの例です:

+
function handleRequest(request, response)
+{
+  // avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  response.setHeader("Content-Type", "text/plain", false);
+  response.write("Hello world!");
+}
+
+

引数として渡されるリクエストとレスポンスのオブジェクトが持つ正確なプロパティは、{{ Source("netwerk/test/httpserver/nsIHttpServer.idl", "nsIHttpServer.idl") }}nsIHttpRequestMetadatansIHttpResponse インターフェースとして定義されています。ブラウザはあなたが書いたスクリプトによって生成されたレスポンスを自由にキャッシュする事に気をつけてください。もしSJSが同じURLへの複数のリクエストに対して異なるデータを返したい場合は、   Mochitestの同じセッションで手動で複数回実行された際にテストが意図せず失敗してしまう事を防ぐために、レスポンスに Cache-Control: no-cache ヘッダを加えるとよいでしょう。

+

reftestにおけるSJSの簡単な利用例としては、{{ Source("modules/libpr0n/test/reftest/generic/check-header.sjs", "check-header.sjs") }}があります。

+

異なるサーバサイドスクリプトの間で状態を引き継ぐにはどうすればよいですか?

+

Mochitest のサーバサイドスクリプトは、それぞれの読み込みごとに新たに生成されるサンドボックスの中で実行されます。そのため、ハンドラの中で定義されたいかなる変数も、それぞれの読み込みごとの実行コンテキストを超えて状態を保持し続ける事はありません。状態を保存する手助けとしては、グローバルオブジェクトにおいて定義されている getState(k) および setState(k, v) メソッドを利用します。これらのメソッドはキーと値(どちらも文字列を使用)によるストレージの仕組みをサーバに提供します。(オブジェクトやその他の構造化されたデータを保存するにはJSONを使用してください。)Mochitest における無数のサーバが、プロキシとトンネリングによってそう見せられているだけで実際には単一のサーバであるために、保存された状態はすべてのサーバで常に同じとなることに注意してください。

+

getState および setState メソッドは、サーバサイドスクリプトが読み込まれた時点のパスでスコープが決まります。/foo/bar/baz, /foo/bar/baz?quux, /foo/bar/baz#fnord のような絶対 URL はすべて同じ状態を共有します(この場合 /foo/bar の状態はそれらとは別に保持されます)。テスト同士の依存性とバグの発生を避けるためにも、可能な限り常に、状態はパスごとに使用するべきです。しかしながら、2つのスクリプトが関連して協調動作することが必要であるなどのレアケースで、そのスクリプトから分岐に応じた挙動を要求するための専用のクエリ文字列を利用できないような場合もあります。このような用途についてのみ、あなたはグローバルオブジェクトで定義されている getSharedState(k, v) および setSharedState(k, v) メソッドを使う事ができます。このサーバ全体で共有される状態へのアクセスについては何も制限はかけられておらず、どのスクリプトからも新しい状態を設定でき、どのスクリプトからもそれを削除できます。衝突を避けるために、あなたは名前空間(意図しない衝突を避けるため、これもテスト用の物を作って下さい)をキーに含める事が望ましいです。例えば、ある HTML5 ビデオのテストで状態を共有する必要がある場合なら、dom.media.video:sharedState のようなキーを使う事になります。

+

より強力な状態保存のための機能として、あらゆる nsISupports 形式のオブジェクトを保持することができる getObjectState(k) および setObjectState(k, v) メソッドもあります。これらのメソッドは nsIHttpServer インターフェースにこの形式で存在していますが、SJS レスポンス処理用のサーバで使われるサンドボックスオブジェクトの制限のため、前者のメソッドは SJS リクエストハンドラのグローバル環境においては、getObjectState(k, callback) という形式(callback は、第1引数で示されたキーに対応するオブジェクトを引数として getObjectState の内部で呼ばれるコールバック関数)で存在します。この、値のマッピングのために、値が XPCOM オブジェクトである必要がある必要があることに注意して下さい。QueryInterface メソッドを持たない任意の JavaScript オブジェクトは利用できません。JavaScript のオブジェクトを保持させたい場合には、QueryInterface の実装を持ち、XPConnect でラップされたオブジェクトから実際の JavaScript オブジェクトを取得するための wrappedJSObject プロパティも持つオブジェクトを使って下さい。

+

httpd.js によって提供される状態保存の仕組みの詳細については、{{ Source("netwerk/test/httpserver/nsIHttpServer.idl") }} および nsIHttpServer.get(Shared|Object)?State メソッドを参照して下さい。

+

非同期にレスポンスを返す SJS スクリプトはどのように書けばいいですか?

+

例えば一定の時間待つという風に、リクエストに対するレスポンスを非同期に返したいという場合があるでしょう。これは handleRequest() 関数に渡される response オブジェクトの processAsync() および finish() 関数によって実現できます。

+

processAsync() は必ず、handleRequest() からリターンする前に呼ばれなくてはなりません。この関数を実行すると、さらに追加のレスポンスを送信するために、request オブジェクトのメソッドを好きな時点で呼ぶ事ができるようになります。必要なレスポンスを送信し終えたら、finish() 関数を呼んでください。例えば、上で説明した setState()/getState() 関数を、request を保存して、後でその内容を参照し、さらに終了するために利用できます。しかしながら、ブラウザはリクエストを異なる順番で行う事があり、そのためあなたが書くコードは時々起こる失敗を避けるよう耐性を高くしなければならないということに気をつけてください。

+
var timer = null;
+
+function handleRequest(request, response)
+{
+  response.processAsync();
+  response.setHeader("Content-Type", "text/plain", false);
+  response.write("hello...");
+
+  timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+  timer.initWithCallback(function()
+  {
+    response.write("world!");
+    response.finish();
+  }, 5 * 1000 /* ミリ秒 */, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
+

より詳しい情報については、{{ Source("netwerk/test/httpserver/nsIHttpServer.idl") }} にある processAsync() 関数の説明を参照してください。

+

SJS スクリプトからサーバ上にあるファイルに XPCOM オブジェクトとしてアクセスするにはどうすればよいですか?(Gecko 1.9.3 およびそれ以降の場合)

+

ファイルにアクセスする必要がある場合(例えば、画像データはファイルとして保存しておく方が、SJS スクリプトの中に直接画像を埋め込むよりも扱いが簡単です)、Mochitest で実行されている SJS スクリプトで最初から定義済みの SERVER_ROOT オブジェクトステートを利用して下さい:

+
function handleRequest(req, res)
+{
+  var file;
+  getObjectState("SERVER_ROOT", function(serverRoot)
+  {
+    file = serverRoot.getFile("tests/content/media/test/320x240.ogv");
+  });
+
+  // この時点で file は指定されたファイルを参照する XPCOM オブジェクトになっています。
+  res.write("file: " + file);
+}
+
+

指定するパスは、httpd.js が取り扱うルートディレクトリからの相対パスとして扱われ、その位置に対応するnsIFile のオブジェクトが返されます。この時は、パスの書き間違いに注意してください。ファイルのオブジェクトはパス文字列を保持しているだけなので、指定したファイルは実際に存在している必要がありません。

diff --git a/files/ja/mozilla/projects/mochitest/specialpowers/index.html b/files/ja/mozilla/projects/mochitest/specialpowers/index.html new file mode 100644 index 0000000000..c3b6141d06 --- /dev/null +++ b/files/ja/mozilla/projects/mochitest/specialpowers/index.html @@ -0,0 +1,471 @@ +--- +title: SpecialPowers +slug: Mozilla/Projects/Mochitest/SpecialPowers +tags: + - Mochistest + - NeedsContent + - QA + - 'QA:Tools' + - Reference +translation_of: Mozilla/Projects/Mochitest/SpecialPowers +--- +

SpecialPowers は Mochitest のテストで利用可能な API 群の 1 つです。Mochitest は通常の Web ページとしてかけるようにする予定です。しかし、セキュリティ的な理由から権限の無い通常の Web ページではテストできないものもあります。そういった場合に SpecialPowers API を使う事で通常の Web ページでは触れることのできない操作をすることができます。

+ +
もし Mochitest で幅広い権限を必要とするテストをする場合は、変りに Chrome Mochitest を使う方が良いでしょう。
+ +

Method overview

+ +

Preference APIs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void pushPrefEnv(inPrefs, callback);
void popPrefEnv(callback);
void flushPrefEnv(callback);
bool getBoolPref(aPrefName);
int getIntPref(aPrefName);
string getCharPref(aPrefName);
any getComplexValue(aPrefName);
void setBoolPref(aPrefName, aValue);
void setIntPref(aPrefName, aValue);
void setCharPref(aPrefName, aValue);
void setComplexValue(aPrefName, aValue);
void clearUserPref(aPrefName);
+ +

Permission APIs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void pushPermissions(inPermissions, callback);
void popPermissions(callback);
void flushPermissions(callback);
void addPermission(type, allow, arg);
void removePermission(type, arg);
bool hasPermission(type, arg);
bool testPermission(type, value, arg);
void setFullscreenAllowed(document);
void removeFullscreenAllowed(document);
+ +

Event Listener / Observer APIs

+ +

TBD

+ +

Garbage Collection APIs

+ +

TBD

+ +

Privilege Wrapper APIs

+ + + + + + + +
Object wrap(Object);
+ +

XPCOM Components APIs

+ + + + + + + + + + + + + + + + +
Cc
Ci
Cr
Cu
+ +

Log APIs

+ +

TBD

+ +

Environment APIs

+ + + + + + + + + + + + + + + + + + + + + + + + + +
bool isMainProcess();
string getMozFullPath(file);
bool isWindowPrivate(aWindow);
bool isBackButtonEnabled(aWindow);
int assertionCount();
void removeExpectedCrashDumpFiles(aExpectingProcessCrash);
string[] findUnexpectedCrashDumpFiles();
+ +

Focus Management APIs

+ +

TBD

+ +

Mock APIs

+ +

TBD

+ +

Form History APIs

+ +

TBD

+ +

Snapshot APIs

+ +

TBD

+ +

Clipboard APIs

+ +

TBD

+ +

Console APIs

+ +

TBD

+ +

Layout APIs

+ +

TBD

+ +

Frame Message APIs

+ +

TBD

+ +

Apps APIs

+ +

TBD

+ +

Other APIs

+ + + + + + + + + + + + + + + + + + + + + + + + + +
XMLHttpRequest createSystemXHR();
void quit();
DOMWindowUtils getDOMWindowUtils(window);
void executeSoon(aFun, aWindow);
object getDOMRequestService();
void openDialog(aWindow, aArg);
string sanityCheck();
+ +

Attributes

+ + + + + + + + + + + + + + + + + + + + + +
AttributeTypeDescription
DOMWindowUtils  
Services  
+ +

Methods

+ +

Preference APIs

+ +

内部的に、このメソッドがどのように使われているかは {{ interface("nsIPrefBranch") }} のドキュメントを参照してください。

+ +

getBoolPref(aPrefName)

+ +

boolean 型として aPrefName のプリファレンス値を取得します。

+ +

getIntPref(aPrefName)

+ +

integer 型として aPrefName のプリファレンス値を取得します。

+ +

getCharPref(aPrefName)

+ +

string 型として aPrefName のプリファレンス値を取得します。

+ +

getComplexValue(aPrefName)

+ +

XPCOM オブジェクトとして aPrefName のプリファレンス値を取得します。

+ +

setBoolPref(aPrefName, aValue)

+ +

boolean 型の aValue を aPrefName をキーとしてプリファレンスへ設定します。

+ +

setIntPref(aPrefName, aValue)

+ +

integer 型の aValue を aPrefName をキーとしてプリファレンスへ設定します。

+ +

setCharPref(aPrefName, aValue)

+ +

string 型の aValue を aPrefName をキーとしてプリファレンスへ設定します。

+ +

setComplexValue(aPrefName, aValue)

+ +

XPCOM オブジェクトの aValue を aPrefName をキーとしてプリファレンスへ設定します。

+ +

clearUserPref(aPrefName)

+ +

aPrefName のプリファレンス値を初期値に戻します。

+ +

Permission APIs

+ +

TBD

+ +

Event Listener / Observer APIs

+ +

addChromeEventListener(type, listener, capture, allowUntrusted)

+ +

TabChildGlobal オブジェクトにイベントリスナーを登録します。

+ +

removeChromeEventListener(type, listener, capture)

+ +

TabChildGlobal オブジェクトからイベントリスナーを除去します。

+ +

Garbage Collection APIs

+ +

gc()

+ +

強制的にガベージコレクションを発生させます。

+ +

Privilege Wrapper APIs

+ +

Object wrap(Object)

+ +

chrome オブジェクトにアクセスするために chrome オブジェクトをラップします。(例えば) XPCOM コンポーネントを返すメソッドの戻り値にアクセスするためには必要です。

+ +

XPCOM Components APIs

+ +

Cc

+ +

Components.classes の値を取得できます。これは chrome コード内で取得できるものと同じです。

+ +

Ci

+ +

Components.interfaces の値を取得できます。これは chrome コード内で取得できるものと同じです。

+ +

Cr

+ +

Components.results の値を取得できます。これは chrome コード内で取得できるものと同じです。

+ +

Cu

+ +

Components.utils の値を取得できます。これは chrome コード内で取得できるものと同じです。

+ +

Log APIs

+ +

TBD

+ +

Environment APIs

+ +

TBD

+ +

Focus Management APIs

+ +

TBD

+ +

Mock APIs

+ +

MockFilePicker

+ +

これは読み込み・保存のコードをテストするために、標準 File Picker をスクリプトで制御可能にするものに置換します。これを使うと、以下のコードをテストすることができます。

+ +
var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.reset(); // You must call reset before each test
+
+ +

このパッチ ではMockFilePicker の使い方と XPCShell テストの使い方の良い例です。 testing/mochitest/MockFilePicker.jsm のコードが参考になるでしょう。

+ +

Form History APIs

+ +

TBD

+ +

Snapshot APIs

+ +

TBD

+ +

Clipboard APIs

+ +

TBD

+ +

Console APIs

+ +

TBD

+ +

Layout APIs

+ +

TBD

+ +

Frame Message APIs

+ +

loadChromeScript()

+ +

TBD

+ +

Apps APIs

+ +

TBD

+ +

Other APIs

+ +

createSystemXHR()

+ +

完全な "system privileges"  を持った XMLHttpRequest を生成して返します。言い換えれば以下の事が可能になります。

+ + + +

しかし、xhr オブジェクトをパースしたドキュメントや xhr.responseXML からアクセスしたドキュメントは null principal として生成されています。そのため、ドキュメントでできることに制限があります。

+ +

sanityCheck()

+ +

"foo" という文字列を返します。

+ +

Adding new APIs

+ +

もし現在定義されていない権限が必要な関数をテストしたい場合、SpecialPowers オブジェクトに新しい API を追加することができます。

+ +
SpecialPowers API は Electrolysis(e10s) プロジェクトでは前方互換として設計されています。そのためコンテンツは別プロセスとして動作します。(Firefox Mobile と同様)。変更したもの全てについてこれを考慮しなくてはいけません。考慮しない場合は許可されることは無いでしょう。
+ +

プロセス外 (out-of-process) のコンテンツをサポートするために、SpecialPowers の実装は以下の 2 つのファイルに分離されています。

+ + + +

両方のファイルは chrome 権限で実行されます。しかし XPCOM API は恐らくコンテンツプロセスでは利用できないでそう。もし特殊な API でそれを利用する場合は Electrolysis や Mobile チームに相談するべきです。プロセス間メッセージの仕組みについての情報を知りたい場合、 Message Manager のドキュメントを参照してください。

+ +

{{ interface("nsIScreenManager") }} インターフェイスの numberOfScreens  をアクセス可能にする修正を例にしてみましょう。このインターフェイスはコンテンツアプリではアクセス不可能ですので、サンプルコードでそれを可能にしてみましょう。まず初めに、コンテンツで利用できるように SpecialPowers に新しい API を定義した方が良いでしょう。このオブジェクトは {{ Source("testing/specialpowers/content/specialpowers.js", "the content script") }} に定義します。

+ +
SpecialPowers は標準の JavaScript オブジェクトです。そのため、関数・属性・セッター・ゲッターを自由に追加することができます。特殊な __exposedProps__ property のようにアンダースコア("_") から始まるプロパティを定義することでプロパティを隠すことができます。アンダースコアから始まる関数もプライベートになります。
+ +

最初にSpecialPowersnumberOfScreens のゲッターを追加しましょう。単純に chrome プロセスにブロッキングメッセージを送信し、応答として値を返すだけです。

+ +
var SpecialPowers = {
+  // existing APIs
+  //...
+
+  // Provide nsIScreenManager.numberOfScreens
+  get numberOfScreens() {
+    // You could pass additional parameters in the second parameter, consult the message manager documentation for more details.
+    // Ideally this would be a memoizing getter, that's somewhat out of scope for this document.
+    return sendSyncMessage("SPNumberOfScreens", {})[0];
+  }
+};
+
+ +

このとき、対応するメッセージのハンドラーを {{ Source("testing/specialpowers/components/SpecialPowersObserver.js", "chrome observer script") }} に定義する必要があります。SpecialPowersObserver.observe 関数の中で、以下の実在するメッセージを登録します。

+ +
// Register for any messages our API needs us to handle
+messageManager.addMessageListener("SPPrefService", this);
+messageManager.addMessageListener("SPNumberOfScreens", this);
+
+ +

そして、SpecialPowersObserver.receiveMessage 関数の中で、新しいメッセージの分岐を追加し結果を返します。

+ +
receiveMessage: function(aMessage) {
+  switch(aMessage.name) {
+    case "SPPrefService":
+    // existing code...
+
+    case "SPNumberOfScreens":
+      var screenManager = Components.classes["@mozilla.org/gfx/screenmanager;1"]
+                    .getService(Components.interfaces.nsIScreenManager);}
+      return screenManager.numberOfScreens;
+
+    default:
+
+ +

これで終わりです。
+ この修正を反映させるために、testing/mochitest ディレクトリを再ビルドする必要があるでしょう。これで Mochitest でSpecialPowers.numberOfScreens を利用することができるようになります。

+ +
新しい API を追加後に、このドキュメントに新 API の説明を書くことを忘れないで下さい。
-- cgit v1.2.3-54-g00ecf