PhntomJSでTest
PhantomJSって何?
PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
PhantomJSって何?
- ブラウザ無しにWebページのエミュレーションができる
- さらにAPI経由で、Webページ上でJavaScriptが実行可能
- つまり、Webの操作が何でもできる!
PhantomJSって何?
- PhantomJSは、QtWebKitをベースに作られています。
- DOMやCSSの操作だけでなく、CanvasやSVGまで扱えます。
- 簡単にWebページのScreenShotが取れます。
PhantomJS基本編
まずは動かしてみる
PhantomJSのインストール
$ brew install phantomjs
PhantomJSを使ってみる1
- sample1.js
- $ phantomjs sample1.js
スクリーンショットが`github.png`に保存される
var page = require('webpage').create();
page.open('https://github.com/', function() {
page.render('github.png');
phantom.exit();
});
PhantomJSを使ってみる2
- sample2.js
- $ phantomjs sample2.js
githubのステータスがコンソールに出力される
var page = require('webpage').create();
page.open('https://status.github.com/', function(status) {
if (status !== 'success') {
console.error('fail to open page');
} else {
var msg = page.evaluate(function() {
var msg = document.getElementById('message');
return [msg.className, msg.innerText];
});
console.log('[' + msg[0] + '] ' + msg[1]);
}
phantom.exit();
});
[good] All systems operational
PhantomJS応用編
UnitTestで活用
FacebookのOAuth認証
- FacebookのAccessTokenを取得してテストしたい
- 普通はBrowserを開いてFacebookのページを表示する必要があるため、自動化が難しい
- でも、事前に取得したAccessTokenを使う場合には期限切れの問題がある
- それ、PhantomJSでできるよ!
OAuth認証の流れ
ここが問題
Authorization Code Grantの場合
Facebook認証の手順
OAuth認証の自動化のために
- OAuth Serverに対してユーザ操作が必要
- そこに PhantomJSを使ってあげる
JavaScriptで出来る事は何でも可能!- 具体的には認証ダイアログに対して
ID/Passwordを自動入力&Submit - さらにOAuthのApproveも自動でOKを押す
- 具体的には認証ダイアログに対して
ようやく本題
phantomjs-nodeを使ってFacebookのAccessToken取得
TypeScript on Node
コードの簡単な解説
- moduleのimportと、定数の宣言。
- このために phantomjs-nodeの型定義を自分で作成
https://github.com/borisyankov/DefinitelyTyped/pull/3255
///<reference path="./typings/tsd.d.ts" />
import url = require('url');
import querystring = require('querystring');
import phantom = require('phantom');
var clientId = "1426039047681363";
var redirectUri = "http://localhost:3000/auth/facebook/callback";
コードの簡単な解説
function openOAuthDialog(ph: phantom.PhantomJS, callback: (err: any, token: string) => void): void {
var params = {
redirect_uri: redirectUri,
response_type: 'code',
client_id: clientId
};
openPage(ph, params, (page: phantom.WebPage, targetUrl: string): boolean => {
var location = url.parse(targetUrl);
var redirectLocation = url.parse(redirectUri);
debuglog('location: ' + location.host + ', ' + location.pathname);
(次のページで解説するので省略)
}, callback);
}
- Authorization Code取得のRequestをしている
response_type=code
コードの簡単な解説
- ログイン画面とApprove画面の自動処理の実装部分
ここが今回の一番のキモ。ただ中身は簡単。
if (location.host === 'www.facebook.com') {
switch (location.pathname) {
case '/login.php':
page.evaluate((login_email, login_password) => {
var email = <HTMLInputElement>document.getElementById('email');
if (email) {
email.value = login_email;
(<HTMLInputElement>document.getElementById('pass')).value = login_password;
(<HTMLFormElement>document.getElementById('login_form')).submit();
}
}, () => {}, login_email, login_password);
return false;
case '/v2.0/dialog/oauth':
page.evaluate(() => {
(<HTMLFormElement>document.getElementById('platformDialogForm')).submit();
});
return false;
default:
return false;
}
} else if (location.host === redirectLocation.host) {
var qs = querystring.parse(location.query);
openAccessToken(ph, qs.code, callback);
return true;
}
コードの簡単な解説
- RedirectURLに Authorization Codeが渡されるので、
受け取っている部分。 - その Codeを元にAccessToken取得のRequestを行う
} else if (location.host === redirectLocation.host) {
var qs = querystring.parse(location.query);
openAccessToken(ph, qs.code, callback);
return true;
}
コードの簡単な解説
- AccessTokenを受け取って callbackを呼び出す
function openAccessToken(ph: phantom.PhantomJS, code: string, callback: (err: any, token: string) => void): void {
debuglog('code=' + code);
var params = {
client_id: clientId,
redirect_uri: redirectUri,
response_type: 'token',
code: code
};
openPage(ph, params, (page: phantom.WebPage, targetUrl: string): boolean => {
var location = url.parse(targetUrl);
var redirectLocation = url.parse(redirectUri);
debuglog('location: ' + location.host + ', ' + location.pathname);
if (location.host === redirectLocation.host) {
var qs = querystring.parse(location.hash);
callback(null, qs['#access_token']);
ph.exit();
return true;
} else {
return false;
}
}, callback);
}
- Authorization Code取得のRequest
response_type=token
PhantomJSでテスト
By Hiroki Horiuchi
PhantomJSでテスト
- 1,342