我正在编写一些我正在使用IndexedDb的数据存储内容的集成测试。这涉及通过创建数据库,执行某些操作(运行测试),然后通过调用database.close()
然后通过调用window.indexedDB.deleteDatabase(DB_NAME)
删除数据库来拆除每个测试来设置每个测试。
documentation for IDBDatabase.close()表示“IDBDatabase接口的close()方法立即返回并在单独的线程中关闭连接。 Close不接受一次触发的回调数据库实际上已经关闭,因此无法确定连接是否已关闭。
尝试使用window.indexedDB.deleteDatabase(DB_NAME)
删除数据库时,我的初始测试超时。所有测试都在打开数据库,除此之外没有任何操作。我可以通过在调用database.close()
后添加一个小超时来解决这个问题。
添加另一个向数据库添加数据的测试后,即使超时,也会再次挂起删除数据库的调用。数据 成功添加并且事务回调完成,因此我不确定调用database.close()
的原因是什么。任何见解将不胜感激。
修改
我创建了一个项目来说明这个问题。代码可以在这里找到:https://github.com/bgourlie/idb-hang-repro
有几点要注意 - 复制品是用飞镖写的,因为那是我看到这个问题的地方。该行为在Chrome和Dartium(嵌入了dart VM的Chromium的特殊版本)中得到了再现。对于那些没有使用Dart但仍想解决此问题的人,请按照以下步骤操作:
{extracted_dir}/dart/dart-sdk/bin
添加到路径中。git clone https://github.com/bgourlie/idb-hang-repro.git
cd idb-hang-repro
pub get
pub serve
这将启动pub开发服务器,最有可能是http://localhost:8080
。我在测试运行器中重现了这个问题,可以在http://localhost:8080/tests.html
访问。测试超时并显示任何输出需要很短的时间。还有一些重要的打印消息将显示在开发者控制台上。
答案 0 :(得分:4)
由于我已经为我的idb_shim项目做了大量的索引数据库实验,我可以分享我能够在新数据库上编写单元测试,只要我确保
根据我能够修复你的测试项目(感谢分享它),并进行了以下更改:
return tx.completed.then((_) {
print('transaction complete.');
},...
作为旁注,我通常更喜欢删除setUp功能中的数据库,以便在先前的测试失败并且未清理数据库时它可以正常工作。因此,现有代码的解决方案是:
setUp(() {
return dom.window.indexedDB.deleteDatabase(DB_NAME, onBlocked: (e) {
print('delete db blocked, but completing future anyway');
}).then((_) {
print('db successfully deleted!');
return dom.window.indexedDB.open(DB_NAME, version: 1, onUpgradeNeeded: (VersionChangeEvent e) {
print('db upgrade called (${e.oldVersion} -> ${e.newVersion})');
final db = (e.target as Request).result;
db.createObjectStore('foo', autoIncrement: true);
}, onBlocked: (e) => print('open blocked.')).then((_db_) {
print('db opened.');
db = _db_;
});
});
});
tearDown(() {
// note the 'close' here
db.close();
});
group('indexed DB delete hang repro', () {
test('second test which will add data', () {
print('adding data in second test...');
final tx = db.transaction('foo', 'readwrite');
final objectStore = tx.objectStore('foo');
objectStore.add({
'bar': 1,
'baz': 2
}).then((addedKey) {
print('object added to store with key=$addedKey');
}, onError: (e) => print('error adding object!'));
// note the 'return' here
return tx.completed.then((_) {
print('transaction complete.');
}, onError: (e) => print('transaction errored!'));
});
test('call setup and teardown', () {
print('just setup and teardown being called in first test.');
});
});
答案 1 :(得分:3)
正如您所注意到的,无法知道database.close()
何时结束,window.indexedDB.deleteDatabase
在尝试删除数据库时仍然有点奇怪。但这些并非难以逾越的问题。看看what actually happens when you try to delete a database。我对此的解读表明,如果您尝试删除仍处于打开状态的数据库,它将在每个打开的数据库连接上触发versionchange
事件。然后,如果数据库仍处于打开状态,它将为您的blocked
触发success
事件而不是deleteDatabase
,但它仍会继续并以任何方式删除数据库。
因此,我这样做:
var request = indexedDB.deleteDatabase("whatever");
request.onsuccess = function () {
success();
};
request.onfailure = function (event) {
fail(event);
};
request.onblocked = function () {
success();
};
更好的解决方案可能是以某种方式监听前面提到的versionchange
事件并在那里关闭数据库,但我无法弄清楚如何做到这一点。只有当你删除它时,如果你关心数据库是否打开,那就更重要了,你可能不会这样做。