Share(Action) エクステンションのJavaScriptをテストする
Share(Action) エクステンションに対応したiOSアプリを作る際,Safariに対し特定のJavaScriptファイルの実行(と結果の受け取り)をさせることができます.
参考: App Extension Programming Guide: Handling Common Scenarios の”Accessing a Webpage”
このJavaScriptのテストをしたかったので,実現方法を考えてみました.
環境
- macOS: 10.15 (Catalina)
- Node.js: v10.18
- Safari: 14.1
方法
本当はiOS上でテストできればよいのですが,テストフレームワークからiOSのSafariを制御したりするのが難しそうだった(わからなかった)ので,せめて似た環境になるように,Seleniumを使ってmacOS上のSafariでテストしました. テストの実行は次のようなことをしています.
- serveでWebサーバを立てる
- SafariをSeleniumで動かし,立てたWebサーバにアクセスする
- テストするJavaScriptをSafariに読み込ませる
- テストメソッドでアサーションを実行する
この記事ではrunだけテストしていますが,同様にfinalizeを呼ぶことでfinalizeのテストもできると思います.
実装
テスト対象のJavaScriptはAppleのガイドを参考に,次のようなものを作りました. ベースURLとページタイトルを取得するものです. これがiOSアプリのプロダクトコードの一部であり,エクステンション実行時に実際に呼ばれることになります.
var MyExtensionJavaScriptClass = function() {};
MyExtensionJavaScriptClass.prototype = {
run: function(arguments) {
arguments.completionFunction({
"baseURI": document.baseURI,
"title": document.title
});
},
finalize: function(arguments) {
}
};
テスト用Webサーバの起動はこんな感じです.Safariの立ち上がりが遅いことがあったので,タイムアウトを長めにしています.
また,テスト終了時にすぐにサーバ停止するように,keepAliveTimeout
は短めに設定しています.
before(async function() {
this.timeout(10000)
// Webサーバの起動
server = http.createServer((request, response) => {
return handler(request, response, {
public: path.join(__dirname, '..', 'public'),
directoryListing: false,
})
})
server.keepAliveTimeout = 500
server.listen(3000)
// Safariのドライバ
driver = await new Builder().forBrowser('safari').build()
// テスト対象のJavasScript
processingJs = await util.promisify(fs.readFile)(processingJsPath, 'utf-8')
})
テスト終了時はこのようにWebサーバを停止します.
after(async function() {
// Webサーバの停止
await driver.quit()
server.close()
})
テスト対象のJavaScriptはこんな感じでSafariに実行させています.
async function runProcessingJs() {
return await driver.executeScript(async (processingJs) => {
eval(processingJs)
return new Promise((resolve) => {
ExtensionPreprocessingJS.run({
completionFunction: (runResult) => {
resolve(runResult)
}})
})
}, processingJs)
}
テストメソッドはこんな感じです.ここでもSafariの動作が遅いことがあったので,タイムアウトを長めに設定しています.
describe('processing', function() {
this.timeout(5000)
// 日本語ページのベースURLとタイトルを取得する
it('ja', async function() {
await driver.get('http://localhost:3000/ja')
const result = await runProcessingJs()
console.log('結果', result)
assert(result.title === '日本語のページ<アングルブラケット>')
assert(result.baseURI === 'http://localhost:3000/ja')
})
})
すべてのファイルはottijp/test-extension-javascriptにコミットしてあるので参照してください.
テスト実行
テストを実行するとこのような出力になります.
$ npm test
> test-extension-javascript@1.0.0 test /Users/otti/src/github.com/ottijp/test-extension-javascript
> mocha
processing
✓ ja (242ms)
1 passing (2s)