| <!doctype html> |
| <meta charset="utf8"> |
| <title>IndexedDB: versionchange transaction lifecycle</title> |
| <!-- These tests cannot yet be upstreamed to WPT because they rely on microtask |
| sequencing, which was not fully specified yet. --> |
| <link rel="help" |
| href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"> |
| <link rel="help" |
| href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore"> |
| <link rel="help" |
| href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore"> |
| <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <script src="resources/support-promises.js"></script> |
| <script> |
| 'use strict'; |
| |
| promise_test(t => { |
| return createDatabase(t, database => { |
| createBooksStore(t, database); |
| }).then(database => { |
| database.close(); |
| }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
| let abortFired = false; |
| const abortPromise = new Promise((resolve, reject) => { |
| transaction.addEventListener('abort', () => { |
| abortFired = true; |
| resolve(); |
| }, false); |
| transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]); |
| transaction._willBeAborted(); |
| }); |
| |
| return Promise.resolve().then(() => { |
| assert_false( |
| abortFired, |
| 'The abort event should fire after promises are resolved'); |
| assert_equals( |
| request.transaction, transaction, |
| "The open request's transaction should be reset after onabort"); |
| try { |
| database.createObjectStore('books2'); |
| } catch(e) { |
| assert_false( |
| e, |
| 'createObjectStore should not throw an exception, because the ' + |
| 'transaction is still active'); |
| } |
| try { |
| database.deleteObjectStore('books'); |
| } catch(e) { |
| assert_false( |
| e, |
| 'deleteObjectStore should not throw an exception, because the ' + |
| 'transaction is still active'); |
| } |
| }).then(() => abortPromise); |
| })); |
| }, 'in a promise microtask after a failing request is issued, before the ' + |
| 'transaction abort event is fired'); |
| |
| promise_test(t => { |
| return createDatabase(t, database => { |
| createBooksStore(t, database); |
| }).then(database => { |
| database.close(); |
| }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
| return new Promise((resolve, reject) => { |
| transaction.addEventListener('abort', () => resolve(), false); |
| transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]); |
| transaction._willBeAborted(); |
| }).then(() => { |
| assert_equals( |
| request.transaction, transaction, |
| "The open request's transaction should be reset after onabort " + |
| 'microtasks'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.createObjectStore('books2'); }, |
| 'createObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.deleteObjectStore('books'); }, |
| 'deleteObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| }); |
| })); |
| }, 'in a promise microtask after the abort event is fired for a transaction ' + |
| 'aborted due to an unhandled request failure'); |
| |
| promise_test(t => { |
| return createDatabase(t, database => { |
| createBooksStore(t, database); |
| }).then(database => { |
| database.close(); |
| }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
| return new Promise((resolve, reject) => { |
| transaction.addEventListener('abort', () => resolve(), false); |
| transaction.abort(); |
| }).then(() => { |
| assert_equals( |
| request.transaction, transaction, |
| "The open request's transaction should be reset after onabort " + |
| 'microtasks'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.createObjectStore('books2'); }, |
| 'createObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.deleteObjectStore('books'); }, |
| 'deleteObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| }); |
| })); |
| }, 'in a promise microtask after the abort event is fired for a transaction ' + |
| 'aborted due to an abort() call'); |
| |
| promise_test(t => { |
| return createDatabase(t, database => { |
| createBooksStore(t, database); |
| }).then(database => { |
| database.close(); |
| }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
| let completeFired = false; |
| const completePromise = new Promise((resolve, reject) => { |
| transaction.addEventListener('complete', () => { |
| completeFired = true; |
| resolve(); |
| }, false); |
| }); |
| |
| return Promise.resolve().then(() => { |
| assert_false( |
| completeFired, |
| 'The complete event should fire after promises are resolved'); |
| assert_equals( |
| request.transaction, transaction, |
| "The open request's transaction should be reset after oncomplete"); |
| try { |
| database.createObjectStore('books2'); |
| } catch(e) { |
| assert_false( |
| e, |
| 'createObjectStore should not throw an exception, because the ' + |
| 'transaction is still active'); |
| } |
| try { |
| database.deleteObjectStore('books'); |
| } catch(e) { |
| assert_false( |
| e, |
| 'deleteObjectStore should not throw an exception, because the ' + |
| 'transaction is still active'); |
| } |
| }).then(() => completePromise); |
| })).then(database => { database.close(); }); |
| }, 'in a promise microtask after the transaction requests are performed'); |
| |
| promise_test(t => { |
| return createDatabase(t, database => { |
| createBooksStore(t, database); |
| }).then(database => { |
| database.close(); |
| }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
| return new Promise((resolve, reject) => { |
| transaction.addEventListener('complete', () => resolve(), false); |
| }).then(() => { |
| assert_equals( |
| request.transaction, transaction, |
| "The open request's transaction should be reset after oncomplete " + |
| 'microtasks'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.createObjectStore('books2'); }, |
| 'createObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| assert_throws( |
| 'InvalidStateError', |
| () => { database.deleteObjectStore('books'); }, |
| 'deleteObjectStore exception should reflect that the transaction ' + |
| 'is no longer running'); |
| }); |
| })).then(database => { database.close(); }); |
| }, 'in a promise microtask after the complete event is fired for a committed ' + |
| 'transaction'); |
| |
| </script> |