summaryrefslogtreecommitdiff
path: root/packages/idb-bridge/src/idb-wpt-ported
diff options
context:
space:
mode:
Diffstat (limited to 'packages/idb-bridge/src/idb-wpt-ported')
-rw-r--r--packages/idb-bridge/src/idb-wpt-ported/idbcursor-advance-index.test.ts255
-rw-r--r--packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-add-put-exception-order.test.ts104
-rw-r--r--packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts58
3 files changed, 417 insertions, 0 deletions
diff --git a/packages/idb-bridge/src/idb-wpt-ported/idbcursor-advance-index.test.ts b/packages/idb-bridge/src/idb-wpt-ported/idbcursor-advance-index.test.ts
index a7be31f28..2d449a9ab 100644
--- a/packages/idb-bridge/src/idb-wpt-ported/idbcursor-advance-index.test.ts
+++ b/packages/idb-bridge/src/idb-wpt-ported/idbcursor-advance-index.test.ts
@@ -1,5 +1,7 @@
import test from "ava";
import { BridgeIDBCursor } from "..";
+import { BridgeIDBRequest } from "../bridge-idb";
+import { InvalidStateError } from "../util/errors";
import { createdb } from "./wptsupport";
test("WPT test idbcursor_advance_index.htm", async (t) => {
@@ -34,6 +36,7 @@ test("WPT test idbcursor_advance_index.htm", async (t) => {
cursor_rq.onsuccess = function (e: any) {
var cursor = e.target.result;
t.log(cursor);
+ t.true(e.target instanceof BridgeIDBRequest);
t.true(cursor instanceof BridgeIDBCursor);
switch (count) {
@@ -51,7 +54,259 @@ test("WPT test idbcursor_advance_index.htm", async (t) => {
t.fail("unexpected count");
break;
}
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - attempt to pass a count parameter that is not a number
+test("WPT test idbcursor_advance_index2.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (e: any) {
+ db = e.target.result;
+ var objStore = db.createObjectStore("test", { keyPath: "pKey" });
+
+ objStore.createIndex("index", "iKey");
+
+ for (var i = 0; i < records.length; i++) objStore.add(records[i]);
+ };
+
+ open_rq.onsuccess = function (e) {
+ var cursor_rq = db
+ .transaction("test")
+ .objectStore("test")
+ .index("index")
+ .openCursor();
+
+ cursor_rq.onsuccess = function (e: any) {
+ var cursor = e.target.result;
+
+ t.true(cursor != null, "cursor exist");
+ t.throws(
+ () => {
+ // Original test uses "document".
+ cursor.advance({ foo: 42 });
+ },
+ { instanceOf: TypeError },
+ );
+ resolve();
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - index - attempt to advance backwards
+test("WPT test idbcursor_advance_index3.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (e: any) {
+ db = e.target.result;
+ var objStore = db.createObjectStore("test", { keyPath: "pKey" });
+
+ objStore.createIndex("index", "iKey");
+
+ for (var i = 0; i < records.length; i++) objStore.add(records[i]);
+ };
+
+ open_rq.onsuccess = function (e) {
+ var cursor_rq = db
+ .transaction("test")
+ .objectStore("test")
+ .index("index")
+ .openCursor();
+
+ cursor_rq.onsuccess = function (e: any) {
+ var cursor = e.target.result;
+
+ t.true(cursor != null, "cursor exist");
+ t.throws(
+ () => {
+ cursor.advance(-1);
+ },
+ { instanceOf: TypeError },
+ );
+ resolve();
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - index - iterate to the next record
+test("WPT test idbcursor_advance_index5.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+ let count = 0;
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ { pKey: "primaryKey_1-2", iKey: "indexKey_1" },
+ ],
+ expected = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1-2", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (e: any) {
+ db = e.target.result;
+ var objStore = db.createObjectStore("test", { keyPath: "pKey" });
+
+ objStore.createIndex("index", "iKey");
+
+ for (var i = 0; i < records.length; i++) objStore.add(records[i]);
+ };
+
+ open_rq.onsuccess = function (e: any) {
+ var cursor_rq = db
+ .transaction("test")
+ .objectStore("test")
+ .index("index")
+ .openCursor();
+
+ cursor_rq.onsuccess = function (e: any) {
+ var cursor = e.target.result;
+ if (!cursor) {
+ t.deepEqual(count, expected.length, "cursor run count");
+ resolve();
+ }
+
+ var record = cursor.value;
+ t.deepEqual(record.pKey, expected[count].pKey, "primary key");
+ t.deepEqual(record.iKey, expected[count].iKey, "index key");
+
+ cursor.advance(2);
+ count++;
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - index - throw TransactionInactiveError
+test("WPT test idbcursor_advance_index7.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (event: any) {
+ db = event.target.result;
+ var objStore = db.createObjectStore("store", { keyPath: "pKey" });
+ objStore.createIndex("index", "iKey");
+ for (var i = 0; i < records.length; i++) {
+ objStore.add(records[i]);
+ }
+ var rq = objStore.index("index").openCursor();
+ rq.onsuccess = function (event: any) {
+ var cursor = event.target.result;
+ t.true(cursor instanceof BridgeIDBCursor);
+
+ event.target.transaction.abort();
+ t.throws(
+ () => {
+ cursor.advance(1);
+ },
+ { name: "TransactionInactiveError" },
+ "Calling advance() should throws an exception TransactionInactiveError when the transaction is not active.",
+ );
+ resolve();
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - index - throw InvalidStateError
+test("WPT test idbcursor_advance_index8.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (event: any) {
+ db = event.target.result;
+ var objStore = db.createObjectStore("store", { keyPath: "pKey" });
+ objStore.createIndex("index", "iKey");
+ for (var i = 0; i < records.length; i++) {
+ objStore.add(records[i]);
}
+ var rq = objStore.index("index").openCursor();
+ let called = false;
+ rq.onsuccess = function (event: any) {
+ if (called) {
+ return;
+ }
+ called = true;
+ var cursor = event.target.result;
+ t.true(cursor instanceof BridgeIDBCursor);
+
+ cursor.advance(1);
+ t.throws(
+ () => {
+ cursor.advance(1);
+ },
+ { name: "InvalidStateError" },
+ "Calling advance() should throw DOMException when the cursor is currently being iterated.",
+ );
+ t.pass();
+ resolve();
+ };
+ };
+ });
+});
+
+// IDBCursor.advance() - index - throw InvalidStateError caused by object store been deleted
+test("WPT test idbcursor_advance_index9.htm", async (t) => {
+ await new Promise<void>((resolve, reject) => {
+ var db: any;
+ const records = [
+ { pKey: "primaryKey_0", iKey: "indexKey_0" },
+ { pKey: "primaryKey_1", iKey: "indexKey_1" },
+ ];
+
+ var open_rq = createdb(t);
+ open_rq.onupgradeneeded = function (event: any) {
+ db = event.target.result;
+ var objStore = db.createObjectStore("store", { keyPath: "pKey" });
+ objStore.createIndex("index", "iKey");
+ for (var i = 0; i < records.length; i++) {
+ objStore.add(records[i]);
+ }
+ var rq = objStore.index("index").openCursor();
+ rq.onsuccess = function (event: any) {
+ var cursor = event.target.result;
+ t.true(cursor instanceof BridgeIDBCursor, "cursor exist");
+
+ db.deleteObjectStore("store");
+ t.throws(
+ () => {
+ cursor.advance(1);
+ },
+ { name: "InvalidStateError" },
+ "If the cursor's source or effective object store has been deleted, the implementation MUST throw a DOMException of type InvalidStateError",
+ );
+
+ resolve();
+ };
};
});
});
diff --git a/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-add-put-exception-order.test.ts b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-add-put-exception-order.test.ts
new file mode 100644
index 000000000..77c4a9391
--- /dev/null
+++ b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-add-put-exception-order.test.ts
@@ -0,0 +1,104 @@
+import test, { ExecutionContext } from "ava";
+import { BridgeIDBCursor } from "..";
+import { BridgeIDBRequest } from "../bridge-idb";
+import { InvalidStateError } from "../util/errors";
+import { createdb, indexeddb_test } from "./wptsupport";
+
+async function t1(t: ExecutionContext, method: string): Promise<void> {
+ await indexeddb_test(
+ t,
+ (done, db) => {
+ const store = db.createObjectStore("s");
+ const store2 = db.createObjectStore("s2");
+
+ db.deleteObjectStore("s2");
+
+ setTimeout(() => {
+ t.throws(
+ () => {
+ (store2 as any)[method]("key", "value");
+ },
+ { name: "InvalidStateError" },
+ '"has been deleted" check (InvalidStateError) should precede ' +
+ '"not active" check (TransactionInactiveError)',
+ );
+ done();
+ }, 0);
+ },
+ (done, db) => {},
+ "t1",
+ );
+}
+
+/**
+ * IDBObjectStore.${method} exception order: 'TransactionInactiveError vs. ReadOnlyError'
+ */
+async function t2(t: ExecutionContext, method: string): Promise<void> {
+ await indexeddb_test(
+ t,
+ (done, db) => {
+ const store = db.createObjectStore("s");
+ },
+ (done, db) => {
+ (db as any)._debugName = method;
+ const tx = db.transaction("s", "readonly");
+ const store = tx.objectStore("s");
+
+ setTimeout(() => {
+ t.throws(
+ () => {
+ console.log(`calling ${method}`);
+ (store as any)[method]("key", "value");
+ },
+ {
+ name: "TransactionInactiveError",
+ },
+ '"not active" check (TransactionInactiveError) should precede ' +
+ '"read only" check (ReadOnlyError)',
+ );
+
+ done();
+ }, 0);
+
+ console.log(`queued task for ${method}`);
+ },
+ "t2",
+ );
+}
+
+/**
+ * IDBObjectStore.${method} exception order: 'ReadOnlyError vs. DataError'
+ */
+async function t3(t: ExecutionContext, method: string): Promise<void> {
+ await indexeddb_test(
+ t,
+ (done, db) => {
+ const store = db.createObjectStore("s");
+ },
+ (done, db) => {
+ const tx = db.transaction("s", "readonly");
+ const store = tx.objectStore("s");
+
+ t.throws(
+ () => {
+ (store as any)[method]({}, "value");
+ },
+ { name: "ReadOnlyError" },
+ '"read only" check (ReadOnlyError) should precede ' +
+ "key/data check (DataError)",
+ );
+
+ done();
+ },
+ "t3",
+ );
+}
+
+test("WPT idbobjectstore-add-put-exception-order.html (add, t1)", t1, "add");
+test("WPT idbobjectstore-add-put-exception-order.html (put, t1)", t1, "put");
+
+test("WPT idbobjectstore-add-put-exception-order.html (add, t2)", t2, "add");
+test("WPT idbobjectstore-add-put-exception-order.html (put, t2)", t2, "put");
+
+test("WPT idbobjectstore-add-put-exception-order.html (add, t3)", t3, "add");
+test("WPT idbobjectstore-add-put-exception-order.html (put, t3)", t3, "put");
diff --git a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
index 4a7205f8d..6777dc122 100644
--- a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
+++ b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
@@ -422,3 +422,61 @@ export function format_value(val: any, seen?: any): string {
}
}
}
+
+// Usage:
+// indexeddb_test(
+// (test_object, db_connection, upgrade_tx, open_request) => {
+// // Database creation logic.
+// },
+// (test_object, db_connection, open_request) => {
+// // Test logic.
+// test_object.done();
+// },
+// 'Test case description');
+export function indexeddb_test(
+ t: ExecutionContext,
+ upgrade_func: (
+ done: () => void,
+ db: IDBDatabase,
+ tx: IDBTransaction,
+ open: IDBOpenDBRequest,
+ ) => void,
+ open_func: (
+ done: () => void,
+ db: IDBDatabase,
+ open: IDBOpenDBRequest,
+ ) => void,
+ dbsuffix?: string,
+ options?: any,
+): Promise<void> {
+ return new Promise((resolve, reject) => {
+ options = Object.assign({ upgrade_will_abort: false }, options);
+ const dbname =
+ "testdb-" + new Date().getTime() + Math.random() + (dbsuffix ?? "");
+ var del = self.indexedDB.deleteDatabase(dbname);
+ del.onerror = () => t.fail("deleteDatabase should succeed");
+ var open = self.indexedDB.open(dbname, 1);
+ open.onupgradeneeded = function () {
+ var db = open.result;
+ t.teardown(function () {
+ // If open didn't succeed already, ignore the error.
+ open.onerror = function (e) {
+ e.preventDefault();
+ };
+ db.close();
+ self.indexedDB.deleteDatabase(db.name);
+ });
+ var tx = open.transaction!;
+ upgrade_func(resolve, db, tx, open);
+ };
+ if (options.upgrade_will_abort) {
+ open.onsuccess = () => t.fail("open should not succeed");
+ } else {
+ open.onerror = () => t.fail("open should succeed");
+ open.onsuccess = function () {
+ var db = open.result;
+ if (open_func) open_func(resolve, db, open);
+ };
+ }
+ });
+}