自分用に作ったIndexedDBライブラリをテストしようとしたときの話。
以下のような手順で、テストを書いていた。
- データベースの作成
- データの登録
- データの検索
- 以下略
問題は「2.データの登録」で発生した。
エラーの内容は、「データベースがまだ作成されていません」的なものだった。
それを解消するために、いろいろ調べたのでまとめていく。
エラーの原因
※ コードはTypeScriptで書いてるけど、基本JavaScriptと同じなので読み替えてほしい。
テストはJasmineを使って書いている。
class IDBLibrary {
private _idb: IDBDatabase;
private _idbInfo: IDBInfo;
/**
* コンストラクタ
* @param dbInfo IDBの情報
*/
constructor(dbInfo: IDBInfo) {
this._idbInfo = dbInfo;
var req = indexedDB.open(this._idbInfo.dbName, this._idbInfo.version);
req.onupgradeneeded = () => {
this._idb = req.result;
var store = this._idb.createObjectStore(this._idbInfo.storeName, this._idbInfo.key);
console.log("success:onupgradeneeded");
}
req.onsuccess = () => {
this._idb = req.result;
console.log("success:onsuccess");
}
}
/**
* 登録
* @param value 登録する情報(JSON)
*/
register(value: any): boolean {
console.log('register');
var tran = this._idb.transaction(this._idbInfo.storeName, 'readwrite');
var store = tran.objectStore(this._idbInfo.storeName);
var req = store.put(value);
req.onsuccess = () => {
console.log("success:register");
return true;
}
}
/* 以下略 */
}
describe('IDBライブラリのテスト', () => {
var idb: IDBLibrary;
beforeEach(() => {
var idbInfo: IDBInfo = {
dbName: 'IDBLibraryTest',
storeName: 'IDBLibrary',
version: 1,
key: { keyPath: 'url', autoIncrement: false }
};
idb = new IDBLibrary(idbInfo);
});
afterEach(() => {
idb.destroy();
});
it('データ登録する', () => {
var videoInfo: IVideoInfo = {
url: "123/abc",
title: "データ登録する",
time: "1h 00m",
tags: ['tag1', 'tag2', 'tag3']
};
var result = idb.register(videoInfo);
expect(result).toBe(true);
});
});
これを実行すると、まず26行目でエラーが発生してしまう。
内容は、「transactionが見つかりません」というエラー。
それが解消されても、次は15行目でエラーになってしまう。
ログは以下のようになっている。
> register
> success:onupgradeneeded
> success:onsuccess
> success:onupgradeneeded
> success:onsuccess
コールバックの処理が終わる前に、次の処理を実行してエラーになっていた。
コールバック処理が終わるまで待つ方法
いくつか試してみて、setTimeoutを使うことで落ち着いた。
sleepとかwaitとかsetIntervalとか試してみたけどダメだった。
describe('IDBライブラリのテスト', () => {
var idb: IDBLibrary;
beforeEach(() => {
var idbInfo: IDBInfo = {
dbName: 'IDBLibraryTest',
storeName: 'IDBLibrary',
version: 1,
key: { keyPath: 'url', autoIncrement: false }
};
idb = new IDBLibrary(idbInfo);
});
afterEach(() => {
window.setTimeout(
function() { idb.destroy() },
2000
);
});
it('データ登録する', () => {
var videoInfo: IVideoInfo = {
url: "123/abc",
title: "データ登録する",
time: "1h 00m",
tags: ['tag1', 'tag2', 'tag3']
};
var result;
window.setTimeout(
function() { result = idb.register(videoInfo) },
1000
);
expect(result).toBe(true);
});
});
window.setTimeout(function() { /* 遅延させたい処理 */ }, 遅延時間ms)
と書くことで、特定の処理を遅延させることができる。
私の環境では、sleepやwaitのメソッドを実装したり、setIntervalを使ったりすると、すべての処理(コールバック含め)が遅延してしまい、結果エラーのまま変わらなかった。
なんかもっと良い方法があれば、コメントなりTwitterなりで教えてください!
Jasmineで非同期のテストを行う方法がわかったので、後日「Jasmine2.x以降で非同期テストをする方法」として記事をアップする予定。(時期は未定)
参考サイト
- javascript で wait処理 - 新みのる日記
- JavaScriptのタイマー処理 setTimeoutとその活用 - 犬も歩けば棒も歩く
- TypeScript - コールバック……駆逐してやる…この世から…一匹…残らず!! - Qiita
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿