diff options
Diffstat (limited to 'packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts')
-rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts new file mode 100644 index 000000000..0f872fa51 --- /dev/null +++ b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts @@ -0,0 +1,504 @@ +import test, { ExecutionContext } from "ava"; +import { BridgeIDBRequest } from ".."; +import { EventTarget, IDBDatabase } from "../idbtypes"; +import { + checkStoreContents, + checkStoreGenerator, + checkStoreIndexes, + createBooksStore, + createDatabase, + createdb, + createNotBooksStore, + migrateDatabase, +} from "./wptsupport"; + +// IndexedDB: object store renaming support +// IndexedDB object store rename in new transaction +test("WPT idbobjectstore-rename-store.html (subtest 1)", async (t) => { + await new Promise<void>((resolve, reject) => { + let bookStore: any = null; + let bookStore2: any = null; + let renamedBookStore: any = null; + let renamedBookStore2: any = null; + + return createDatabase(t, (database, transaction) => { + bookStore = createBooksStore(t, database); + }) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["books"], + 'Test setup should have created a "books" object store', + ); + const transaction = database.transaction("books", "readonly"); + bookStore2 = transaction.objectStore("books"); + return checkStoreContents( + t, + bookStore2, + "The store should have the expected contents before any renaming", + ).then(() => database.close()); + }) + .then(() => + migrateDatabase(t, 2, (database, transaction) => { + renamedBookStore = transaction.objectStore("books"); + renamedBookStore.name = "renamed_books"; + + t.deepEqual( + renamedBookStore.name, + "renamed_books", + "IDBObjectStore name should change immediately after a rename", + ); + t.deepEqual( + database.objectStoreNames as any, + ["renamed_books"], + "IDBDatabase.objectStoreNames should immediately reflect the " + + "rename", + ); + t.deepEqual( + transaction.objectStoreNames as any, + ["renamed_books"], + "IDBTransaction.objectStoreNames should immediately reflect the " + + "rename", + ); + t.deepEqual( + transaction.objectStore("renamed_books"), + renamedBookStore, + "IDBTransaction.objectStore should return the renamed object " + + "store when queried using the new name immediately after the " + + "rename", + ); + t.throws( + () => transaction.objectStore("books"), + { name: "NotFoundError" }, + "IDBTransaction.objectStore should throw when queried using the " + + "renamed object store's old name immediately after the rename", + ); + }), + ) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["renamed_books"], + "IDBDatabase.objectStoreNames should still reflect the rename " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction("renamed_books", "readonly"); + renamedBookStore2 = transaction.objectStore("renamed_books"); + return checkStoreContents( + t, + renamedBookStore2, + "Renaming an object store should not change its records", + ).then(() => database.close()); + }) + .then(() => { + t.deepEqual( + bookStore.name, + "books", + "IDBObjectStore obtained before the rename transaction should " + + "not reflect the rename", + ); + t.deepEqual( + bookStore2.name, + "books", + "IDBObjectStore obtained before the rename transaction should " + + "not reflect the rename", + ); + t.deepEqual( + renamedBookStore.name, + "renamed_books", + "IDBObjectStore used in the rename transaction should keep " + + "reflecting the new name after the transaction is committed", + ); + t.deepEqual( + renamedBookStore2.name, + "renamed_books", + "IDBObjectStore obtained after the rename transaction should " + + "reflect the new name", + ); + }); + }); + t.pass(); +}); + +// IndexedDB: object store renaming support +// IndexedDB object store rename in the transaction where it is created +test("WPT idbobjectstore-rename-store.html (subtest 2)", async (t) => { + await new Promise<void>((resolve, reject) => { + let renamedBookStore: any = null, + renamedBookStore2: any = null; + return createDatabase(t, (database, transaction) => { + renamedBookStore = createBooksStore(t, database); + renamedBookStore.name = "renamed_books"; + + t.deepEqual( + renamedBookStore.name, + "renamed_books", + "IDBObjectStore name should change immediately after a rename", + ); + t.deepEqual( + database.objectStoreNames as any, + ["renamed_books"], + "IDBDatabase.objectStoreNames should immediately reflect the " + + "rename", + ); + t.deepEqual( + transaction.objectStoreNames as any, + ["renamed_books"], + "IDBTransaction.objectStoreNames should immediately reflect the " + + "rename", + ); + t.deepEqual( + transaction.objectStore("renamed_books"), + renamedBookStore, + "IDBTransaction.objectStore should return the renamed object " + + "store when queried using the new name immediately after the " + + "rename", + ); + t.throws( + () => transaction.objectStore("books"), + { name: "NotFoundError" }, + "IDBTransaction.objectStore should throw when queried using the " + + "renamed object store's old name immediately after the rename", + ); + }) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["renamed_books"], + "IDBDatabase.objectStoreNames should still reflect the rename " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction("renamed_books", "readonly"); + renamedBookStore2 = transaction.objectStore("renamed_books"); + return checkStoreContents( + t, + renamedBookStore2, + "Renaming an object store should not change its records", + ).then(() => database.close()); + }) + .then(() => { + t.deepEqual( + renamedBookStore.name, + "renamed_books", + "IDBObjectStore used in the rename transaction should keep " + + "reflecting the new name after the transaction is committed", + ); + t.deepEqual( + renamedBookStore2.name, + "renamed_books", + "IDBObjectStore obtained after the rename transaction should " + + "reflect the new name", + ); + }); + }); + t.pass(); +}); + +// Renames the 'books' store to 'renamed_books'. +// +// Returns a promise that resolves to an IndexedDB database. The caller must +// close the database. +const renameBooksStore = (testCase: ExecutionContext) => { + return migrateDatabase(testCase, 2, (database, transaction) => { + const store = transaction.objectStore("books"); + store.name = "renamed_books"; + }); +}; + +// IndexedDB: object store renaming support +// IndexedDB object store rename covers index +test("WPT idbobjectstore-rename-store.html (subtest 3)", async (t) => { + await createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + }) + .then(async (database) => { + const transaction = database.transaction("books", "readonly"); + const store = transaction.objectStore("books"); + await checkStoreIndexes( + t, + store, + "The object store index should have the expected contens before " + + "any renaming", + ); + return database.close(); + }) + .then(() => renameBooksStore(t)) + .then(async (database) => { + const transaction = database.transaction("renamed_books", "readonly"); + const store = transaction.objectStore("renamed_books"); + await checkStoreIndexes( + t, + store, + "Renaming an object store should not change its indexes", + ); + return database.close(); + }); + t.pass(); +}); + +// IndexedDB: object store renaming support +// IndexedDB object store rename covers key generator +test("WPT idbobjectstore-rename-store.html (subtest 4)", async (t) => { + await createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + }) + .then((database) => { + const transaction = database.transaction("books", "readwrite"); + const store = transaction.objectStore("books"); + return checkStoreGenerator( + t, + store, + 345679, + "The object store key generator should have the expected state " + + "before any renaming", + ).then(() => database.close()); + }) + .then(() => renameBooksStore(t)) + .then((database) => { + const transaction = database.transaction("renamed_books", "readwrite"); + const store = transaction.objectStore("renamed_books"); + return checkStoreGenerator( + t, + store, + 345680, + "Renaming an object store should not change the state of its key " + + "generator", + ).then(() => database.close()); + }); + t.pass(); +}); + +// IndexedDB: object store renaming support +// IndexedDB object store rename to the name of a deleted store succeeds +test("WPT idbobjectstore-rename-store.html (subtest 5)", async (t) => { + await createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + createNotBooksStore(t, database); + }) + .then((database) => { + database.close(); + }) + .then(() => + migrateDatabase(t, 2, (database, transaction) => { + const store = transaction.objectStore("books"); + database.deleteObjectStore("not_books"); + store.name = "not_books"; + t.deepEqual( + database.objectStoreNames as any, + ["not_books"], + "IDBDatabase.objectStoreNames should immediately reflect the " + + "rename", + ); + }), + ) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["not_books"], + "IDBDatabase.objectStoreNames should still reflect the rename " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction("not_books", "readonly"); + const store = transaction.objectStore("not_books"); + return checkStoreContents( + t, + store, + "Renaming an object store should not change its records", + ).then(() => database.close()); + }); + t.pass(); +}); + +// IndexedDB: object store renaming support +test("WPT idbobjectstore-rename-store.html (IndexedDB object store swapping via renames succeeds)", async (t) => { + await createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + createNotBooksStore(t, database); + }) + .then((database) => { + database.close(); + }) + .then(() => + migrateDatabase(t, 2, (database, transaction) => { + const bookStore = transaction.objectStore("books"); + const notBookStore = transaction.objectStore("not_books"); + + transaction.objectStore("books").name = "tmp"; + transaction.objectStore("not_books").name = "books"; + transaction.objectStore("tmp").name = "not_books"; + + t.deepEqual( + database.objectStoreNames as any, + ["books", "not_books"], + "IDBDatabase.objectStoreNames should immediately reflect the swap", + ); + + t.deepEqual( + transaction.objectStore("books"), + notBookStore, + 'IDBTransaction.objectStore should return the original "books" ' + + 'store when queried with "not_books" after the swap', + ); + t.deepEqual( + transaction.objectStore("not_books"), + bookStore, + "IDBTransaction.objectStore should return the original " + + '"not_books" store when queried with "books" after the swap', + ); + }), + ) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["books", "not_books"], + "IDBDatabase.objectStoreNames should still reflect the swap " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction("not_books", "readonly"); + const store = transaction.objectStore("not_books"); + t.deepEqual( + store.indexNames as any, + ["by_author", "by_title"], + '"not_books" index names should still reflect the swap after the ' + + "versionchange transaction commits", + ); + return checkStoreContents( + t, + store, + "Swapping two object stores should not change their records", + ).then(() => database.close()); + }); + t.pass(); +}); + +// IndexedDB: object store renaming support +test("WPT idbobjectstore-rename-store.html (IndexedDB object store rename stringifies non-string names)", async (t) => { + await createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + }) + .then((database) => { + database.close(); + }) + .then(() => + migrateDatabase(t, 2, (database, transaction) => { + const store = transaction.objectStore("books"); + // @ts-expect-error + store.name = 42; + t.deepEqual( + store.name, + "42", + "IDBObjectStore name should change immediately after a " + + "rename to a number", + ); + t.deepEqual( + database.objectStoreNames as any, + ["42"], + "IDBDatabase.objectStoreNames should immediately reflect the " + + "stringifying rename", + ); + + // @ts-expect-error + store.name = true; + t.deepEqual( + store.name, + "true", + "IDBObjectStore name should change immediately after a " + + "rename to a boolean", + ); + + // @ts-expect-error + store.name = {}; + t.deepEqual( + store.name, + "[object Object]", + "IDBObjectStore name should change immediately after a " + + "rename to an object", + ); + + // @ts-expect-error + store.name = () => null; + t.deepEqual( + store.name, + "() => null", + "IDBObjectStore name should change immediately after a " + + "rename to a function", + ); + + // @ts-expect-error + store.name = undefined; + t.deepEqual( + store.name, + "undefined", + "IDBObjectStore name should change immediately after a " + + "rename to undefined", + ); + }), + ) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + ["undefined"], + "IDBDatabase.objectStoreNames should reflect the last rename " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction("undefined", "readonly"); + const store = transaction.objectStore("undefined"); + return checkStoreContents( + t, + store, + "Renaming an object store should not change its records", + ).then(() => database.close()); + }); + t.pass(); +}); + +function rename_test_macro(t: ExecutionContext, escapedName: string) { + const name = JSON.parse('"' + escapedName + '"'); + createDatabase(t, (database, transaction) => { + createBooksStore(t, database); + }) + .then((database) => { + database.close(); + }) + .then(() => + migrateDatabase(t, 2, (database, transaction) => { + const store = transaction.objectStore("books"); + + store.name = name; + t.deepEqual( + store.name, + name, + "IDBObjectStore name should change immediately after the " + "rename", + ); + t.deepEqual( + database.objectStoreNames as any, + [name], + "IDBDatabase.objectStoreNames should immediately reflect the " + + "rename", + ); + }), + ) + .then((database) => { + t.deepEqual( + database.objectStoreNames as any, + [name], + "IDBDatabase.objectStoreNames should reflect the rename " + + "after the versionchange transaction commits", + ); + const transaction = database.transaction(name, "readonly"); + const store = transaction.objectStore(name); + return checkStoreContents( + t, + store, + "Renaming an object store should not change its records", + ).then(() => database.close()); + }); +} + +for (let escapedName of ["", "\\u0000", "\\uDC00\\uD800"]) { + test( + 'IndexedDB object store can be renamed to "' + escapedName + '"', + rename_test_macro, + escapedName, + ); +} |