idb: fix 'prevunique' iteration and other bugs
This commit is contained in:
parent
3eced74a88
commit
f0d820d8c6
@ -234,7 +234,7 @@ test("Spec: Example 1 Part 3", async (t) => {
|
|||||||
await promiseFromRequest(request7);
|
await promiseFromRequest(request7);
|
||||||
cursor = request7.result;
|
cursor = request7.result;
|
||||||
t.is(cursor.value.author, "Fred");
|
t.is(cursor.value.author, "Fred");
|
||||||
t.is(cursor.value.isbn, 234567);
|
t.is(cursor.value.isbn, 123456);
|
||||||
cursor.continue();
|
cursor.continue();
|
||||||
|
|
||||||
await promiseFromRequest(request7);
|
await promiseFromRequest(request7);
|
||||||
|
@ -1137,127 +1137,140 @@ export class MemoryBackend implements Backend {
|
|||||||
let indexEntry: IndexRecord | undefined;
|
let indexEntry: IndexRecord | undefined;
|
||||||
indexEntry = indexData.get(indexPos);
|
indexEntry = indexData.get(indexPos);
|
||||||
if (!indexEntry) {
|
if (!indexEntry) {
|
||||||
const res = indexData.nextHigherPair(indexPos);
|
const res = forward
|
||||||
|
? indexData.nextHigherPair(indexPos)
|
||||||
|
: indexData.nextLowerPair(indexPos);
|
||||||
if (res) {
|
if (res) {
|
||||||
indexEntry = res[1];
|
indexEntry = res[1];
|
||||||
indexPos = indexEntry.indexKey;
|
indexPos = indexEntry.indexKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let primkeySubPos = 0;
|
if (unique) {
|
||||||
|
while (1) {
|
||||||
// Sort out the case where the index key is the same, so we have
|
if (req.limit != 0 && numResults == req.limit) {
|
||||||
// to get the prev/next primary key
|
|
||||||
if (
|
|
||||||
indexEntry !== undefined &&
|
|
||||||
req.lastIndexPosition !== undefined &&
|
|
||||||
compareKeys(indexEntry.indexKey, req.lastIndexPosition) === 0
|
|
||||||
) {
|
|
||||||
let pos = forward ? 0 : indexEntry.primaryKeys.length - 1;
|
|
||||||
this.enableTracing &&
|
|
||||||
console.log("number of primary keys", indexEntry.primaryKeys.length);
|
|
||||||
this.enableTracing && console.log("start pos is", pos);
|
|
||||||
// Advance past the lastObjectStorePosition
|
|
||||||
do {
|
|
||||||
const cmpResult = compareKeys(
|
|
||||||
req.lastObjectStorePosition,
|
|
||||||
indexEntry.primaryKeys[pos],
|
|
||||||
);
|
|
||||||
this.enableTracing && console.log("cmp result is", cmpResult);
|
|
||||||
if ((forward && cmpResult < 0) || (!forward && cmpResult > 0)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += forward ? 1 : -1;
|
if (indexPos === undefined) {
|
||||||
this.enableTracing && console.log("now pos is", pos);
|
break;
|
||||||
} while (pos >= 0 && pos < indexEntry.primaryKeys.length);
|
}
|
||||||
|
if (!range.includes(indexPos)) {
|
||||||
// Make sure we're at least at advancedPrimaryPos
|
break;
|
||||||
while (
|
}
|
||||||
primaryPos !== undefined &&
|
if (indexEntry === undefined) {
|
||||||
pos >= 0 &&
|
|
||||||
pos < indexEntry.primaryKeys.length
|
|
||||||
) {
|
|
||||||
const cmpResult = compareKeys(
|
|
||||||
primaryPos,
|
|
||||||
indexEntry.primaryKeys[pos],
|
|
||||||
);
|
|
||||||
if ((forward && cmpResult <= 0) || (!forward && cmpResult >= 0)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += forward ? 1 : -1;
|
|
||||||
}
|
|
||||||
primkeySubPos = pos;
|
|
||||||
} else if (indexEntry !== undefined) {
|
|
||||||
primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.enableTracing) {
|
if (
|
||||||
console.log("subPos=", primkeySubPos);
|
req.lastIndexPosition === null ||
|
||||||
console.log("indexPos=", indexPos);
|
req.lastIndexPosition === undefined ||
|
||||||
}
|
compareKeys(indexEntry.indexKey, req.lastIndexPosition) !== 0
|
||||||
|
) {
|
||||||
|
indexKeys.push(indexEntry.indexKey);
|
||||||
|
primaryKeys.push(indexEntry.primaryKeys[0]);
|
||||||
|
numResults++;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (req.limit != 0 && numResults == req.limit) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (indexPos === undefined) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!range.includes(indexPos)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (indexEntry === undefined) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
primkeySubPos < 0 ||
|
|
||||||
primkeySubPos >= indexEntry.primaryKeys.length
|
|
||||||
) {
|
|
||||||
const res: any = forward
|
const res: any = forward
|
||||||
? indexData.nextHigherPair(indexPos)
|
? indexData.nextHigherPair(indexPos)
|
||||||
: indexData.nextLowerPair(indexPos);
|
: indexData.nextLowerPair(indexPos);
|
||||||
if (res) {
|
if (res) {
|
||||||
indexPos = res[1].indexKey;
|
indexPos = res[1].indexKey;
|
||||||
indexEntry = res[1];
|
indexEntry = res[1] as IndexRecord;
|
||||||
primkeySubPos = forward ? 0 : indexEntry!.primaryKeys.length - 1;
|
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let primkeySubPos = 0;
|
||||||
|
|
||||||
// Skip repeated index keys if unique results are requested.
|
// Sort out the case where the index key is the same, so we have
|
||||||
let skip = false;
|
// to get the prev/next primary key
|
||||||
if (unique) {
|
if (
|
||||||
if (
|
indexEntry !== undefined &&
|
||||||
indexKeys.length > 0 &&
|
req.lastIndexPosition !== undefined &&
|
||||||
compareKeys(
|
compareKeys(indexEntry.indexKey, req.lastIndexPosition) === 0
|
||||||
indexEntry.indexKey,
|
) {
|
||||||
indexKeys[indexKeys.length - 1],
|
let pos = forward ? 0 : indexEntry.primaryKeys.length - 1;
|
||||||
) === 0
|
this.enableTracing &&
|
||||||
|
console.log(
|
||||||
|
"number of primary keys",
|
||||||
|
indexEntry.primaryKeys.length,
|
||||||
|
);
|
||||||
|
this.enableTracing && console.log("start pos is", pos);
|
||||||
|
// Advance past the lastObjectStorePosition
|
||||||
|
do {
|
||||||
|
const cmpResult = compareKeys(
|
||||||
|
req.lastObjectStorePosition,
|
||||||
|
indexEntry.primaryKeys[pos],
|
||||||
|
);
|
||||||
|
this.enableTracing && console.log("cmp result is", cmpResult);
|
||||||
|
if ((forward && cmpResult < 0) || (!forward && cmpResult > 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += forward ? 1 : -1;
|
||||||
|
this.enableTracing && console.log("now pos is", pos);
|
||||||
|
} while (pos >= 0 && pos < indexEntry.primaryKeys.length);
|
||||||
|
|
||||||
|
// Make sure we're at least at advancedPrimaryPos
|
||||||
|
while (
|
||||||
|
primaryPos !== undefined &&
|
||||||
|
pos >= 0 &&
|
||||||
|
pos < indexEntry.primaryKeys.length
|
||||||
) {
|
) {
|
||||||
skip = true;
|
const cmpResult = compareKeys(
|
||||||
}
|
primaryPos,
|
||||||
if (
|
indexEntry.primaryKeys[pos],
|
||||||
req.lastIndexPosition !== undefined &&
|
);
|
||||||
compareKeys(indexPos, req.lastIndexPosition) === 0
|
if ((forward && cmpResult <= 0) || (!forward && cmpResult >= 0)) {
|
||||||
) {
|
break;
|
||||||
skip = true;
|
}
|
||||||
|
pos += forward ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
primkeySubPos = pos;
|
||||||
|
} else if (indexEntry !== undefined) {
|
||||||
|
primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
|
||||||
}
|
}
|
||||||
if (!skip) {
|
|
||||||
if (this.enableTracing) {
|
if (this.enableTracing) {
|
||||||
console.log(`not skipping!, subPos=${primkeySubPos}`);
|
console.log("subPos=", primkeySubPos);
|
||||||
|
console.log("indexPos=", indexPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (req.limit != 0 && numResults == req.limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (indexPos === undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!range.includes(indexPos)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (indexEntry === undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
primkeySubPos < 0 ||
|
||||||
|
primkeySubPos >= indexEntry.primaryKeys.length
|
||||||
|
) {
|
||||||
|
const res: any = forward
|
||||||
|
? indexData.nextHigherPair(indexPos)
|
||||||
|
: indexData.nextLowerPair(indexPos);
|
||||||
|
if (res) {
|
||||||
|
indexPos = res[1].indexKey;
|
||||||
|
indexEntry = res[1];
|
||||||
|
primkeySubPos = forward ? 0 : indexEntry!.primaryKeys.length - 1;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
indexKeys.push(indexEntry.indexKey);
|
indexKeys.push(indexEntry.indexKey);
|
||||||
primaryKeys.push(indexEntry.primaryKeys[primkeySubPos]);
|
primaryKeys.push(indexEntry.primaryKeys[primkeySubPos]);
|
||||||
numResults++;
|
numResults++;
|
||||||
} else {
|
primkeySubPos += forward ? 1 : -1;
|
||||||
if (this.enableTracing) {
|
|
||||||
console.log("skipping!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
primkeySubPos += forward ? 1 : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can collect the values based on the primary keys,
|
// Now we can collect the values based on the primary keys,
|
||||||
|
@ -102,7 +102,7 @@ export interface RecordGetRequest {
|
|||||||
*/
|
*/
|
||||||
advancePrimaryKey?: IDBValidKey;
|
advancePrimaryKey?: IDBValidKey;
|
||||||
/**
|
/**
|
||||||
* Maximum number of resuts to return.
|
* Maximum number of results to return.
|
||||||
* If -1, return all available results
|
* If -1, return all available results
|
||||||
*/
|
*/
|
||||||
limit: number;
|
limit: number;
|
||||||
|
@ -702,7 +702,8 @@ export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {
|
|||||||
this._transactions.push(tx);
|
this._transactions.push(tx);
|
||||||
|
|
||||||
queueTask(() => {
|
queueTask(() => {
|
||||||
console.log("TRACE: calling auto-commit", this._getReadableName());
|
BridgeIDBFactory.enableTracing &&
|
||||||
|
console.log("TRACE: calling auto-commit", this._getReadableName());
|
||||||
tx._start();
|
tx._start();
|
||||||
});
|
});
|
||||||
if (BridgeIDBFactory.enableTracing) {
|
if (BridgeIDBFactory.enableTracing) {
|
||||||
@ -941,7 +942,8 @@ export class BridgeIDBFactory {
|
|||||||
|
|
||||||
// We re-use the same transaction (as per spec) here.
|
// We re-use the same transaction (as per spec) here.
|
||||||
transaction._active = true;
|
transaction._active = true;
|
||||||
if (transaction._aborted) {
|
|
||||||
|
if (db._closed || db._closePending) {
|
||||||
request.result = undefined;
|
request.result = undefined;
|
||||||
request.error = new AbortError();
|
request.error = new AbortError();
|
||||||
request.readyState = "done";
|
request.readyState = "done";
|
||||||
@ -951,6 +953,23 @@ export class BridgeIDBFactory {
|
|||||||
});
|
});
|
||||||
event2.eventPath = [];
|
event2.eventPath = [];
|
||||||
request.dispatchEvent(event2);
|
request.dispatchEvent(event2);
|
||||||
|
} else if (transaction._aborted) {
|
||||||
|
try {
|
||||||
|
await db._backend.close(db._backendConnection);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("failed to close database");
|
||||||
|
}
|
||||||
|
|
||||||
|
request.result = undefined;
|
||||||
|
request.error = new AbortError();
|
||||||
|
request.readyState = "done";
|
||||||
|
const event2 = new FakeEvent("error", {
|
||||||
|
bubbles: false,
|
||||||
|
cancelable: false,
|
||||||
|
});
|
||||||
|
event2.eventPath = [];
|
||||||
|
request.dispatchEvent(event2);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (BridgeIDBFactory.enableTracing) {
|
if (BridgeIDBFactory.enableTracing) {
|
||||||
console.log("dispatching 'success' event for opening db");
|
console.log("dispatching 'success' event for opening db");
|
||||||
@ -2361,6 +2380,9 @@ export class BridgeIDBTransaction
|
|||||||
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
|
||||||
this._active = true;
|
this._active = true;
|
||||||
|
queueTask(() => {
|
||||||
|
this._active = false;
|
||||||
|
});
|
||||||
event = new FakeEvent("error", {
|
event = new FakeEvent("error", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
This directory contains test cases from the W3C Web Platform Tests suite for IndexedDB.
|
This directory contains test cases from the W3C Web Platform Tests suite for IndexedDB.
|
||||||
|
|
||||||
The original code for these tests can be found here: https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
|
The original code for these tests can be found here: https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
|
||||||
|
|
||||||
|
The following tests are intentionally not included:
|
||||||
|
* error-attributes.html (assumes we have a DOM)
|
||||||
|
* file_support.sub.html (assumes we have a DOM)
|
||||||
|
* fire-error-event-exception.html (ava can't test unhandled rejections)
|
||||||
|
* fire-success-event-exception.html (ava can't test unhandled rejections)
|
||||||
|
* fire-upgradeneeded-event-exception.html (ava can't test unhandled rejections)
|
@ -0,0 +1,44 @@
|
|||||||
|
import test from "ava";
|
||||||
|
import { BridgeIDBCursor } from "..";
|
||||||
|
import { BridgeIDBCursorWithValue } from "../bridge-idb";
|
||||||
|
import { createdb } from "./wptsupport";
|
||||||
|
|
||||||
|
// When db.close is called in upgradeneeded, the db is cleaned up on refresh
|
||||||
|
test.cb("WPT test close-in-upgradeneeded.htm", (t) => {
|
||||||
|
var db: any;
|
||||||
|
var open_rq = createdb(t);
|
||||||
|
var sawTransactionComplete = false;
|
||||||
|
|
||||||
|
open_rq.onupgradeneeded = function (e: any) {
|
||||||
|
db = e.target.result;
|
||||||
|
t.deepEqual(db.version, 1);
|
||||||
|
|
||||||
|
db.createObjectStore("os");
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
e.target.transaction.oncomplete = function () {
|
||||||
|
sawTransactionComplete = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
open_rq.onerror = function (e: any) {
|
||||||
|
t.true(sawTransactionComplete, "saw transaction.complete");
|
||||||
|
|
||||||
|
t.deepEqual(e.target.error.name, "AbortError");
|
||||||
|
t.deepEqual(e.result, undefined);
|
||||||
|
|
||||||
|
t.true(!!db);
|
||||||
|
t.deepEqual(db.version, 1);
|
||||||
|
t.deepEqual(db.objectStoreNames.length, 1);
|
||||||
|
t.throws(
|
||||||
|
() => {
|
||||||
|
db.transaction("os");
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InvalidStateError",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
|
});
|
114
packages/idb-bridge/src/idb-wpt-ported/cursor-overloads.test.ts
Normal file
114
packages/idb-bridge/src/idb-wpt-ported/cursor-overloads.test.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import test from "ava";
|
||||||
|
import { BridgeIDBCursor } from "..";
|
||||||
|
import { BridgeIDBCursorWithValue } from "../bridge-idb";
|
||||||
|
import { createdb } from "./wptsupport";
|
||||||
|
|
||||||
|
// Validate the overloads of IDBObjectStore.openCursor(), IDBIndex.openCursor() and IDBIndex.openKeyCursor()
|
||||||
|
test.cb("WPT test cursor-overloads.htm", (t) => {
|
||||||
|
var db: any, trans: any, store: any, index: any;
|
||||||
|
|
||||||
|
var request = createdb(t);
|
||||||
|
request.onupgradeneeded = function (e) {
|
||||||
|
db = request.result;
|
||||||
|
store = db.createObjectStore("store");
|
||||||
|
index = store.createIndex("index", "value");
|
||||||
|
store.put({ value: 0 }, 0);
|
||||||
|
trans = request.transaction;
|
||||||
|
trans.oncomplete = verifyOverloads;
|
||||||
|
};
|
||||||
|
|
||||||
|
function verifyOverloads() {
|
||||||
|
trans = db.transaction("store");
|
||||||
|
store = trans.objectStore("store");
|
||||||
|
index = store.index("index");
|
||||||
|
|
||||||
|
checkCursorDirection("store.openCursor()", "next");
|
||||||
|
checkCursorDirection("store.openCursor(0)", "next");
|
||||||
|
checkCursorDirection("store.openCursor(0, 'next')", "next");
|
||||||
|
checkCursorDirection("store.openCursor(0, 'nextunique')", "nextunique");
|
||||||
|
checkCursorDirection("store.openCursor(0, 'prev')", "prev");
|
||||||
|
checkCursorDirection("store.openCursor(0, 'prevunique')", "prevunique");
|
||||||
|
|
||||||
|
checkCursorDirection("store.openCursor(IDBKeyRange.only(0))", "next");
|
||||||
|
checkCursorDirection(
|
||||||
|
"store.openCursor(IDBKeyRange.only(0), 'next')",
|
||||||
|
"next",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"store.openCursor(IDBKeyRange.only(0), 'nextunique')",
|
||||||
|
"nextunique",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"store.openCursor(IDBKeyRange.only(0), 'prev')",
|
||||||
|
"prev",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"store.openCursor(IDBKeyRange.only(0), 'prevunique')",
|
||||||
|
"prevunique",
|
||||||
|
);
|
||||||
|
|
||||||
|
checkCursorDirection("index.openCursor()", "next");
|
||||||
|
checkCursorDirection("index.openCursor(0)", "next");
|
||||||
|
checkCursorDirection("index.openCursor(0, 'next')", "next");
|
||||||
|
checkCursorDirection("index.openCursor(0, 'nextunique')", "nextunique");
|
||||||
|
checkCursorDirection("index.openCursor(0, 'prev')", "prev");
|
||||||
|
checkCursorDirection("index.openCursor(0, 'prevunique')", "prevunique");
|
||||||
|
|
||||||
|
checkCursorDirection("index.openCursor(IDBKeyRange.only(0))", "next");
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openCursor(IDBKeyRange.only(0), 'next')",
|
||||||
|
"next",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openCursor(IDBKeyRange.only(0), 'nextunique')",
|
||||||
|
"nextunique",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openCursor(IDBKeyRange.only(0), 'prev')",
|
||||||
|
"prev",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openCursor(IDBKeyRange.only(0), 'prevunique')",
|
||||||
|
"prevunique",
|
||||||
|
);
|
||||||
|
|
||||||
|
checkCursorDirection("index.openKeyCursor()", "next");
|
||||||
|
checkCursorDirection("index.openKeyCursor(0)", "next");
|
||||||
|
checkCursorDirection("index.openKeyCursor(0, 'next')", "next");
|
||||||
|
checkCursorDirection("index.openKeyCursor(0, 'nextunique')", "nextunique");
|
||||||
|
checkCursorDirection("index.openKeyCursor(0, 'prev')", "prev");
|
||||||
|
checkCursorDirection("index.openKeyCursor(0, 'prevunique')", "prevunique");
|
||||||
|
|
||||||
|
checkCursorDirection("index.openKeyCursor(IDBKeyRange.only(0))", "next");
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openKeyCursor(IDBKeyRange.only(0), 'next')",
|
||||||
|
"next",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openKeyCursor(IDBKeyRange.only(0), 'nextunique')",
|
||||||
|
"nextunique",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openKeyCursor(IDBKeyRange.only(0), 'prev')",
|
||||||
|
"prev",
|
||||||
|
);
|
||||||
|
checkCursorDirection(
|
||||||
|
"index.openKeyCursor(IDBKeyRange.only(0), 'prevunique')",
|
||||||
|
"prevunique",
|
||||||
|
);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCursorDirection(statement: string, direction: string) {
|
||||||
|
request = eval(statement);
|
||||||
|
request.onsuccess = function (event: any) {
|
||||||
|
t.notDeepEqual(event.target.result, null, "Check the result is not null");
|
||||||
|
t.deepEqual(
|
||||||
|
event.target.result.direction,
|
||||||
|
direction,
|
||||||
|
"Check the result direction",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
@ -7,7 +7,7 @@ import {
|
|||||||
keep_alive,
|
keep_alive,
|
||||||
} from "./wptsupport";
|
} from "./wptsupport";
|
||||||
|
|
||||||
test("WPT test abort-in-initial-upgradeneeded.htm", async (t) => {
|
test("WPT test abort-in-initial-upgradeneeded.htm (subtest 1)", async (t) => {
|
||||||
// Transactions are active during success handlers
|
// Transactions are active during success handlers
|
||||||
await indexeddb_test(
|
await indexeddb_test(
|
||||||
t,
|
t,
|
||||||
@ -24,10 +24,9 @@ test("WPT test abort-in-initial-upgradeneeded.htm", async (t) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const request = tx.objectStore("store").get(4242);
|
const request = tx.objectStore("store").get(4242);
|
||||||
(request as BridgeIDBRequest)._debugName = "req-main";
|
(request as BridgeIDBRequest)._debugName = "req-main";
|
||||||
request.onerror = () => t.fail("request should succeed");
|
request.onerror = () => t.fail("request should succeed");
|
||||||
request.onsuccess = () => {
|
request.onsuccess = () => {
|
||||||
|
|
||||||
t.true(
|
t.true(
|
||||||
is_transaction_active(t, tx, "store"),
|
is_transaction_active(t, tx, "store"),
|
||||||
"Transaction should be active during success handler",
|
"Transaction should be active during success handler",
|
||||||
@ -55,3 +54,147 @@ test("WPT test abort-in-initial-upgradeneeded.htm", async (t) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("WPT test abort-in-initial-upgradeneeded.htm (subtest 2)", async (t) => {
|
||||||
|
// Transactions are active during success listeners
|
||||||
|
await indexeddb_test(
|
||||||
|
t,
|
||||||
|
(done, db, tx) => {
|
||||||
|
db.createObjectStore("store");
|
||||||
|
},
|
||||||
|
(done, db) => {
|
||||||
|
const tx = db.transaction("store");
|
||||||
|
const release_tx = keep_alive(t, tx, "store");
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active after creation",
|
||||||
|
);
|
||||||
|
|
||||||
|
const request = tx.objectStore("store").get(0);
|
||||||
|
request.onerror = () => t.fail("request should succeed");
|
||||||
|
request.addEventListener("success", () => {
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active during success listener",
|
||||||
|
);
|
||||||
|
|
||||||
|
let saw_listener_promise = false;
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
saw_listener_promise = true;
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active in listener's microtasks",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
t.true(saw_listener_promise);
|
||||||
|
t.false(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be inactive in next task",
|
||||||
|
);
|
||||||
|
release_tx();
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("WPT test abort-in-initial-upgradeneeded.htm (subtest 3)", async (t) => {
|
||||||
|
// Transactions are active during error handlers
|
||||||
|
await indexeddb_test(
|
||||||
|
t,
|
||||||
|
(done, db, tx) => {
|
||||||
|
db.createObjectStore("store");
|
||||||
|
},
|
||||||
|
(done, db) => {
|
||||||
|
const tx = db.transaction("store", "readwrite");
|
||||||
|
const release_tx = keep_alive(t, tx, "store");
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active after creation",
|
||||||
|
);
|
||||||
|
|
||||||
|
tx.objectStore("store").put(0, 0);
|
||||||
|
const request = tx.objectStore("store").add(0, 0);
|
||||||
|
request.onsuccess = () => t.fail("request should fail");
|
||||||
|
request.onerror = (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active during error handler",
|
||||||
|
);
|
||||||
|
|
||||||
|
let saw_handler_promise = false;
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
saw_handler_promise = true;
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active in handler's microtasks",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
t.true(saw_handler_promise);
|
||||||
|
t.false(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be inactive in next task",
|
||||||
|
);
|
||||||
|
release_tx();
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("WPT test abort-in-initial-upgradeneeded.htm (subtest 4)", async (t) => {
|
||||||
|
// Transactions are active during error listeners
|
||||||
|
await indexeddb_test(
|
||||||
|
t,
|
||||||
|
(done, db, tx) => {
|
||||||
|
db.createObjectStore("store");
|
||||||
|
},
|
||||||
|
(done, db) => {
|
||||||
|
const tx = db.transaction("store", "readwrite");
|
||||||
|
const release_tx = keep_alive(t, tx, "store");
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active after creation",
|
||||||
|
);
|
||||||
|
|
||||||
|
tx.objectStore("store").put(0, 0);
|
||||||
|
const request = tx.objectStore("store").add(0, 0);
|
||||||
|
request.onsuccess = () => t.fail("request should fail");
|
||||||
|
request.addEventListener("error", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active during error listener",
|
||||||
|
);
|
||||||
|
|
||||||
|
let saw_listener_promise = false;
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
saw_listener_promise = true;
|
||||||
|
t.true(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be active in listener's microtasks",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
t.true(saw_listener_promise);
|
||||||
|
t.false(
|
||||||
|
is_transaction_active(t, tx, "store"),
|
||||||
|
"Transaction should be inactive in next task",
|
||||||
|
);
|
||||||
|
release_tx();
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -1,46 +1,385 @@
|
|||||||
import test from "ava";
|
import test from "ava";
|
||||||
import { BridgeIDBCursor } from "..";
|
import { BridgeIDBCursor } from "..";
|
||||||
|
import { BridgeIDBCursorWithValue } from "../bridge-idb";
|
||||||
import { createdb } from "./wptsupport";
|
import { createdb } from "./wptsupport";
|
||||||
|
|
||||||
test("WPT test idbcursor_continue_index.htm", async (t) => {
|
test.cb("WPT test idbcursor_continue_index.htm", (t) => {
|
||||||
await new Promise<void>((resolve, reject) => {
|
var db: any;
|
||||||
var db: any;
|
let count = 0;
|
||||||
let count = 0;
|
const records = [
|
||||||
const records = [ { pKey: "primaryKey_0", iKey: "indexKey_0" },
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
{ pKey: "primaryKey_1-2", iKey: "indexKey_1" } ];
|
{ pKey: "primaryKey_1-2", iKey: "indexKey_1" },
|
||||||
|
];
|
||||||
|
|
||||||
var open_rq = createdb(t);
|
var open_rq = createdb(t);
|
||||||
open_rq.onupgradeneeded = function(e: any) {
|
open_rq.onupgradeneeded = function (e: any) {
|
||||||
db = e.target.result;
|
db = e.target.result;
|
||||||
var objStore = db.createObjectStore("test", { keyPath:"pKey" });
|
var objStore = db.createObjectStore("test", { keyPath: "pKey" });
|
||||||
|
|
||||||
objStore.createIndex("index", "iKey");
|
objStore.createIndex("index", "iKey");
|
||||||
|
|
||||||
for (var i = 0; i < records.length; i++)
|
for (var i = 0; i < records.length; i++) objStore.add(records[i]);
|
||||||
objStore.add(records[i]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
open_rq.onsuccess = function(e) {
|
open_rq.onsuccess = function (e) {
|
||||||
var cursor_rq = db.transaction("test")
|
var cursor_rq = db
|
||||||
.objectStore("test")
|
.transaction("test")
|
||||||
.index("index")
|
.objectStore("test")
|
||||||
.openCursor();
|
.index("index")
|
||||||
|
.openCursor();
|
||||||
|
|
||||||
cursor_rq.onsuccess = function(e: any) {
|
cursor_rq.onsuccess = function (e: any) {
|
||||||
var cursor = e.target.result;
|
var cursor = e.target.result;
|
||||||
if (!cursor) {
|
if (!cursor) {
|
||||||
t.deepEqual(count, records.length, "cursor run count");
|
t.deepEqual(count, records.length, "cursor run count");
|
||||||
resolve();
|
t.end();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var record = cursor.value;
|
var record = cursor.value;
|
||||||
t.deepEqual(record.pKey, records[count].pKey, "primary key");
|
t.deepEqual(record.pKey, records[count].pKey, "primary key");
|
||||||
t.deepEqual(record.iKey, records[count].iKey, "index key");
|
t.deepEqual(record.iKey, records[count].iKey, "index key");
|
||||||
|
|
||||||
cursor.continue();
|
cursor.continue();
|
||||||
count++;
|
count++;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - attempt to pass a key parameter that is not a valid key
|
||||||
|
test.cb("WPT idbcursor-continue-index2.htm", (t) => {
|
||||||
|
var db: any;
|
||||||
|
let 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.throws(
|
||||||
|
() => {
|
||||||
|
cursor.continue({ foo: "bar" });
|
||||||
|
},
|
||||||
|
{ name: "DataError" },
|
||||||
|
);
|
||||||
|
|
||||||
|
t.true(cursor instanceof BridgeIDBCursorWithValue, "cursor");
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - attempt to iterate to the previous
|
||||||
|
// record when the direction is set for the next record
|
||||||
|
test.cb("WPT idbcursor-continue-index3.htm", (t) => {
|
||||||
|
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 count = 0;
|
||||||
|
var cursor_rq = db
|
||||||
|
.transaction("test")
|
||||||
|
.objectStore("test")
|
||||||
|
.index("index")
|
||||||
|
.openCursor(undefined, "next"); // XXX: Fx has issue with "undefined"
|
||||||
|
|
||||||
|
cursor_rq.onsuccess = function (e: any) {
|
||||||
|
var cursor = e.target.result;
|
||||||
|
if (!cursor) {
|
||||||
|
t.deepEqual(count, 2, "ran number of times");
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First time checks key equal, second time checks key less than
|
||||||
|
t.throws(
|
||||||
|
() => {
|
||||||
|
cursor.continue(records[0].iKey);
|
||||||
|
},
|
||||||
|
{ name: "DataError" },
|
||||||
|
);
|
||||||
|
|
||||||
|
cursor.continue();
|
||||||
|
|
||||||
|
count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - attempt to iterate to the next
|
||||||
|
// record when the direction is set for the previous record
|
||||||
|
test.cb("WPT idbcursor-continue-index4.htm", (t) => {
|
||||||
|
var db: any;
|
||||||
|
const records = [
|
||||||
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_2", iKey: "indexKey_2" },
|
||||||
|
];
|
||||||
|
|
||||||
|
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 count = 0,
|
||||||
|
cursor_rq = db
|
||||||
|
.transaction("test")
|
||||||
|
.objectStore("test")
|
||||||
|
.index("index")
|
||||||
|
.openCursor(undefined, "prev"); // XXX Fx issues w undefined
|
||||||
|
|
||||||
|
cursor_rq.onsuccess = function (e: any) {
|
||||||
|
var cursor = e.target.result,
|
||||||
|
record = cursor.value;
|
||||||
|
|
||||||
|
switch (count) {
|
||||||
|
case 0:
|
||||||
|
t.deepEqual(record.pKey, records[2].pKey, "first pKey");
|
||||||
|
t.deepEqual(record.iKey, records[2].iKey, "first iKey");
|
||||||
|
cursor.continue();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
t.deepEqual(record.pKey, records[1].pKey, "second pKey");
|
||||||
|
t.deepEqual(record.iKey, records[1].iKey, "second iKey");
|
||||||
|
t.throws(
|
||||||
|
() => {
|
||||||
|
cursor.continue("indexKey_2");
|
||||||
|
},
|
||||||
|
{ name: "DataError" },
|
||||||
|
);
|
||||||
|
t.end();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
t.fail("Unexpected count value: " + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - iterate using 'prevunique'
|
||||||
|
test.cb("WPT idbcursor-continue-index5.htm", (t) => {
|
||||||
|
var db: any;
|
||||||
|
const records = [
|
||||||
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_1-2", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_2", iKey: "indexKey_2" },
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
{ pKey: "primaryKey_2", iKey: "indexKey_2" },
|
||||||
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
|
];
|
||||||
|
|
||||||
|
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 count = 0,
|
||||||
|
cursor_rq = db
|
||||||
|
.transaction("test")
|
||||||
|
.objectStore("test")
|
||||||
|
.index("index")
|
||||||
|
.openCursor(undefined, "prevunique");
|
||||||
|
|
||||||
|
cursor_rq.onsuccess = function (e: any) {
|
||||||
|
if (!e.target.result) {
|
||||||
|
t.deepEqual(count, expected.length, "count");
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cursor = e.target.result;
|
||||||
|
const record = cursor.value;
|
||||||
|
t.deepEqual(record.pKey, expected[count].pKey, "pKey #" + count);
|
||||||
|
t.deepEqual(record.iKey, expected[count].iKey, "iKey #" + count);
|
||||||
|
|
||||||
|
t.deepEqual(cursor.key, expected[count].iKey, "cursor.key #" + count);
|
||||||
|
t.deepEqual(
|
||||||
|
cursor.primaryKey,
|
||||||
|
expected[count].pKey,
|
||||||
|
"cursor.primaryKey #" + count,
|
||||||
|
);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
cursor.continue(expected[count] ? expected[count].iKey : undefined);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - iterate using nextunique
|
||||||
|
test.cb("WPT idbcursor-continue-index6.htm", (t) => {
|
||||||
|
var db: any;
|
||||||
|
const records = [
|
||||||
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_1-2", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_2", iKey: "indexKey_2" },
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
{ pKey: "primaryKey_0", iKey: "indexKey_0" },
|
||||||
|
{ pKey: "primaryKey_1", iKey: "indexKey_1" },
|
||||||
|
{ pKey: "primaryKey_2", iKey: "indexKey_2" },
|
||||||
|
];
|
||||||
|
|
||||||
|
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 count = 0,
|
||||||
|
cursor_rq = db
|
||||||
|
.transaction("test")
|
||||||
|
.objectStore("test")
|
||||||
|
.index("index")
|
||||||
|
.openCursor(undefined, "nextunique");
|
||||||
|
|
||||||
|
cursor_rq.onsuccess = function (e: any) {
|
||||||
|
if (!e.target.result) {
|
||||||
|
t.deepEqual(count, expected.length, "count");
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cursor = e.target.result,
|
||||||
|
record = cursor.value;
|
||||||
|
|
||||||
|
t.deepEqual(record.pKey, expected[count].pKey, "pKey #" + count);
|
||||||
|
t.deepEqual(record.iKey, expected[count].iKey, "iKey #" + count);
|
||||||
|
|
||||||
|
t.deepEqual(cursor.key, expected[count].iKey, "cursor.key #" + count);
|
||||||
|
t.deepEqual(
|
||||||
|
cursor.primaryKey,
|
||||||
|
expected[count].pKey,
|
||||||
|
"cursor.primaryKey #" + count,
|
||||||
|
);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
cursor.continue(expected[count] ? expected[count].iKey : undefined);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - throw TransactionInactiveError
|
||||||
|
test.cb("WPT idbcursor-continue-index7.htm", (t) => {
|
||||||
|
var db,
|
||||||
|
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.continue();
|
||||||
|
},
|
||||||
|
{ name: "TransactionInactiveError" },
|
||||||
|
"Calling continue() should throws an exception TransactionInactiveError when the transaction is not active.",
|
||||||
|
);
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// IDBCursor.continue() - index - throw InvalidStateError caused by object store been deleted
|
||||||
|
test.cb("WPT idbcursor-continue-index8.htm", (t) => {
|
||||||
|
var db: any,
|
||||||
|
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);
|
||||||
|
|
||||||
|
db.deleteObjectStore("store");
|
||||||
|
|
||||||
|
t.throws(
|
||||||
|
() => {
|
||||||
|
cursor.continue();
|
||||||
|
},
|
||||||
|
{ name: "InvalidStateError" },
|
||||||
|
"If the cursor's source or effective object store has been deleted, the implementation MUST throw a DOMException of type InvalidStateError",
|
||||||
|
);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -12,9 +12,9 @@ import {
|
|||||||
import { MemoryBackend } from "../MemoryBackend";
|
import { MemoryBackend } from "../MemoryBackend";
|
||||||
import { compareKeys } from "../util/cmp";
|
import { compareKeys } from "../util/cmp";
|
||||||
|
|
||||||
BridgeIDBFactory.enableTracing = true;
|
BridgeIDBFactory.enableTracing = false;
|
||||||
const backend = new MemoryBackend();
|
const backend = new MemoryBackend();
|
||||||
backend.enableTracing = true;
|
backend.enableTracing = false;
|
||||||
export const idbFactory = new BridgeIDBFactory(backend);
|
export const idbFactory = new BridgeIDBFactory(backend);
|
||||||
|
|
||||||
const self = {
|
const self = {
|
||||||
|
Loading…
Reference in New Issue
Block a user