// META: title=IndexedDB Transaction Deactivation Timing // META: global=window,worker // META: script=resources/support.js // Spec: https://w3c.github.io/IndexedDB/#dom-idbdatabase-transaction 'use strict'; indexeddb_test( (t, db, tx) => { db.createObjectStore('store'); }, (t, db) => { const tx = db.transaction('store', 'readonly'); const release_tx = keep_alive(tx, 'store'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active after creation'); setTimeout( t.step_func(() => { assert_false( is_transaction_active(tx, 'store'), 'Transaction should be inactive in next task'); release_tx(); t.done(); }), 0); }, 'New transactions are deactivated before next task'); indexeddb_test( (t, db, tx) => { db.createObjectStore('store'); }, (t, db) => { const tx = db.transaction('store', 'readonly'); const release_tx = keep_alive(tx, 'store'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active after creation'); Promise.resolve().then(t.step_func(() => { assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active in microtask checkpoint'); release_tx(); t.done(); })); }, 'New transactions are not deactivated until after the microtask checkpoint'); indexeddb_test( (t, db, tx) => { db.createObjectStore('store'); }, (t, db) => { let tx; let release_tx; Promise.resolve().then(t.step_func(() => { tx = db.transaction('store', 'readonly'); release_tx = keep_alive(tx, 'store'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active after creation'); })); setTimeout( t.step_func(() => { assert_false( is_transaction_active(tx, 'store'), 'Transaction should be inactive in next task'); release_tx(); t.done(); }), 0); }, 'New transactions from microtask are deactivated before next task'); indexeddb_test( (t, db, tx) => { db.createObjectStore('store'); }, (t, db) => { let tx; let release_tx; Promise.resolve().then(t.step_func(() => { tx = db.transaction('store', 'readonly'); release_tx = keep_alive(tx, 'store'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active after creation'); })); Promise.resolve().then(t.step_func(() => { assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active in microtask checkpoint'); release_tx(); t.done(); })); }, 'New transactions from microtask are still active through the ' + 'microtask checkpoint'); indexeddb_test( (t, db, tx) => { db.createObjectStore('store'); }, (t, db) => { // This transaction serves as the source of an event seen by multiple // listeners. A DOM event with multiple listeners could be used instead, // but not via dispatchEvent() because (drumroll...) that happens // synchronously so microtasks don't run between steps. const tx = db.transaction('store', 'readonly'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active after creation'); const request = tx.objectStore('store').get(0); let new_tx; let first_listener_ran = false; let microtasks_ran = false; request.addEventListener('success', t.step_func(() => { first_listener_ran = true; assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active in callback'); // We check to see if t transaction is active across unrelated event // dispatch steps. new_tx = db.transaction('store', 'readonly'); assert_true( is_transaction_active(new_tx, 'store'), 'New transaction should be active after creation'); Promise.resolve().then(t.step_func(() => { microtasks_ran = true; assert_true( is_transaction_active(new_tx, 'store'), 'New transaction is still active in microtask checkpoint'); })); })); request.addEventListener('success', t.step_func(() => { assert_true(first_listener_ran, 'first listener ran first'); assert_true(microtasks_ran, 'microtasks ran before second listener'); assert_true( is_transaction_active(tx, 'store'), 'Transaction should be active in callback'); assert_false( is_transaction_active(new_tx, 'store'), 'New transaction should be inactive in unrelated callback'); t.done(); })); }, 'Deactivation of new transactions happens at end of invocation');