Edited at

node環境でsinon.jsのfakeServerを使う

More than 3 years have passed since last update.


やりたいこと

node.js環境でsinonのfakeServerを使いたい。


なんで?

sinonのfakeServerを使うと、特定のurlへのアクセスに対して任意のステータスコード、ヘッダー、レスポンスボディを返すstubサーバを作る事ができ、APIを呼んだらこうなる、というテストを書く事ができる。

sinon.js#server

しかし、このfakeServerはnode環境だと使えない。sinon.jsの初期化処理を眺めるとわかるが、global環境にXMLHttpRequestが定義されているか否か、そのXMLHttpRequestオブジェクトにwithCredentials属性があるか否か、といったことをチェックしており、実行環境にXMLHttpRequestがあることが前提となっている。


対処法

てことは、globalにXMLHttpRequestのインタフェースを実装してあげれば良さそうである。自分で一通りインタフェースを実装すれば良いのかもしれないが、その前にGoogle先生に聞いてみると、node-xmlhttprequestなる、XMLHttpRequestをnode.js上で実装したモジュールが出てくる。一通りXMLHttpRequestのインタフェースが実装されているので、テスト環境においてこのモジュールをglobal.XMLHttpRequestに設定してあげると、sinon.jsの初期化時にXMLHttpRequestが検出され、fakeServerがちゃんと動作するようになる。


コード

以下サンプルコード。XMLHttpRequestをglobalに設定するファイル(browser.js)とsinonの読み込みは別ファイルにして、必ずbrowser.jsを先に読み込ませる。一つのファイル内でどうにかできないもんかと思いつつ、ES6のimportやglobalが最終的にどうコンパイルされるかまで見てないのでよくわからず。。。

個人的な事情で、mochachaiのテストコードです。

mocha --compilers js:babel/register test.js


browser.js

// ブラウザ環境っぽいものを作る

import jsdom from 'jsdom';
import jQuery from 'jquery';
import { XMLHttpRequest } from 'w3c-xmlhttprequest';

global.XMLHttpRequest = XMLHttpRequest;
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = document.parentWindow;
global.$ = jQuery(window);



test.js

// chai使ってます

import './browser';
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
chai.use(sinonChai);

describe('FakeServer in node.js', () => {
let server;
let spy;
beforeEach(() => {
server = sinon.fakeServer.create();
spy = sinon.spy();
});
afterEach(() => {
server.restore();
});
it('fake responseが返ること', () => {
server.respondWith('GET', '/sample.json', [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify({message: 'Hello World'})
]);
$.getJSON('/sample.json')
.then((data) => {
spy(data);
});
server.respond();
expect(spy).to.have.been.calledWith({message: 'Hello World'})
});
});



まとめ

node環境でもfakeServer使えそうです。

同じようなXMLHttpRequest in node.js実装として、xhr2というのもあったのだけど、こっちではうまく動きませんでした。withCredentialsが実装されてないのが原因っぽいですが、詳細は追ってません。