summaryrefslogtreecommitdiff
path: root/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts
diff options
context:
space:
mode:
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.ts504
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,
+ );
+}