I'm writing integration tests for some data storage stuff that I'm using IndexedDb for. This involves setting up each test by creating a database, performing some operation (running the test), and then tearing down each test by calling database.close()
and then deleting the database by calling window.indexedDB.deleteDatabase(DB_NAME)
.
The documentation for IDBDatabase.close() states that "The close() method of the IDBDatabase interface returns immediately and closes the connection in a separate thread. Close doesn't accept a callback to be fired once the database has actually been closed, so there's no way to determine with certainty that the connection has been closed.
My initial test was timing out when attempting to delete the database with window.indexedDB.deleteDatabase(DB_NAME)
. All the test was doing was opening the database, no operations beside that were performed. I was able to fix this by adding a small timeout after calling database.close()
.
After adding another test that adds data to the database, the call to delete the database is hanging again, even with the timeout. The data does get successfully added and the transaction callback completes, so I'm not sure what why the call to database.close()
would be hanging. Any insight would be greatly appreciated.
EDIT
I created a project that illustrates this problem. The code can be found here: https://github.com/bgourlie/idb-hang-repro
A few things to note -- The repro is written in dart, since that's where I'm seeing this problem. The behavior is reproduced both in Chrome and Dartium (a special version of Chromium with the dart VM embedded). For those who have not used Dart but would still like to mess with this issue, follow these steps:
{extracted_dir}/dart/dart-sdk/bin
to your PATH.git clone https://github.com/bgourlie/idb-hang-repro.git
cd idb-hang-repro
pub get
pub serve
This will start the pub development server, most likely, at http://localhost:8080
. I have reproduced the issue within the test runner, which would be accessed at http://localhost:8080/tests.html
. It will take a short time for the test to timeout and any output to be displayed. There are also important print messages that will be shown on the developer console.
As I have been doing tons of Indexed db experiment for my idb_shim project, I can share that I was able to write unit test on a fresh database as long as I ensured that
According to that I was able to fix your test project (thanks for sharing it), with the following changes:
return tx.completed.then((_) {
print('transaction complete.');
},...
As a side note, I typically prefer to delete the dabase in the setUp fonction so that it works fine if a previous test failed with the database not cleaned up. so the solution for your existing code is then:
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.');
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With