Electron のデフォルトでは Spectron が正しく動作しない
@Electron 7.0.0 @Spectron 9.0.0
electron-quick-start に mocha と spectron をインストールして、簡単なテストを走らせてみました。 すると、以下のようなエラーが。
1) Application launch shows an initial window: TypeError: waitUntilWindowLoaded Cannot read property 'isLoading' of undefined at waitUntil(<function>, ) - application.js:263:17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | const Application = require( 'spectron' ).Application const assert = require( 'assert' ) const electronPath = require( 'electron' ) const path = require( 'path' ) describe( 'Application launch' , function () { this .timeout(10000) beforeEach( function () { this .app = new Application({ path: electronPath, args: [path.join(__dirname, '..' )] }) return this .app.start() }) afterEach( function () { if ( this .app && this .app.isRunning()) { return this .app.stop() } }) it( 'shows an initial window' , function () { // 以下の waitUntilWindowLoaded() 内で落ちてる return this .app.client.waitUntilWindowLoaded().getWindowCount().then( function (count) { assert.equal(count, 1) }) }) }) |
waitUntilWindowLoaded()
内で問題が起こっているようですが、このコードは Spectron
の公式ページに書かれているものです。
waitUntilWindowLoaded()
の使用方法に問題があるとは思えません1。
Electron の設定が原因
この問題、実は Spectron の README.md にしれっと書いてありました。
The Electron helpers provided by Spectron require accessing the core Electron APIs in the renderer processes of your application. So, either your Electron application has nodeIntegration set to true or you'll need to expose a require window global to Spectron so it can access the core Electron APIs.
nodeIntegration
が false
だと Spectron は正しく動かないとのこと。
そして、この nodeIntegration
、Electron 5 以降ではデフォルト false
なのです。(理由は後述)
このことは、公式の Issue#174 にもあがっていて、他にも app.electron
や app.webContents
が undefined
になってしまう問題があるようです。
実際、app.webContents.executeJavaScript('1 + 2')
を呼んでみたところ、エラーになりました。
1) Application launch shows an initial window: TypeError: Cannot read property 'executeJavaScript' of undefined at Context.<anonymous> (test/spec.js:24:35) at <anonymous> at process._tickDomainCallback (internal/process/next_tick.js:228:7)
対策
nodeIntegration
を true
にすれば動作します。
しかし、常に true
にしてしまうとセキュリティリスクがあるので、以下のようにテストの時だけ true
になるようにするのが良いかと思います。
1 2 3 4 5 6 | mainWindow = new BrowserWindow({ webPreferences: { preload: path.join(__dirname, 'preload.js' ), nodeIntegration: (process.env.NODE_ENV === 'test' ) } }) |
私の環境では NODE_ENV
環境変数は自動で test
に設定されました。
ただ、これは環境依存だと思うので package.json
に以下のように書いておくと安心です。
1 2 3 | "scripts" : { "test" : "NODE_ENV=test mocha" }, |
私の環境では公式に載っている preload.js
内で window.electronRequire
を設定する方法は動きませんでした。何でだろう…
なぜ、デフォルト false になったのか
nodeIntegration
が true
だと Renderer プロセスの中から Node.js の API にアクセス出来るようになります。
つまり、Renderer からローカルのファイルやその他のローカルリソースに直接アクセスできてしまうのです。
もし、この状態で悪意のある外部コンテンツを実行すると、とても危険です。
そのため、nodeIntegration
はデフォルト false
になったのだと思われます。
セキュリティを高めたのは良いけれど、テスト時と実行時の動作環境があまりに異なってしまうのはどうなんだろう…
0 件のコメント:
コメントを投稿