diff --git a/src/FDBDatabase.ts b/src/FDBDatabase.ts index 8e3aca7d..c52beac1 100644 --- a/src/FDBDatabase.ts +++ b/src/FDBDatabase.ts @@ -8,6 +8,7 @@ import { TransactionInactiveError, } from "./lib/errors.js"; import FakeDOMStringList from "./lib/FakeDOMStringList.js"; +import FakeEvent from "./lib/FakeEvent.js"; import FakeEventTarget from "./lib/FakeEventTarget.js"; import ObjectStore from "./lib/ObjectStore.js"; import { queueTask } from "./lib/scheduling.js"; @@ -43,11 +44,12 @@ const closeConnection = (connection: FDBDatabase) => { const transactionsComplete = connection._rawDatabase.transactions.every( (transaction) => { return transaction._state === "finished"; - }, + } ); if (transactionsComplete) { connection._closed = true; + connection.dispatchEvent(new FakeEvent("close")); connection._rawDatabase.connections = connection._rawDatabase.connections.filter((otherConnection) => { return connection !== otherConnection; @@ -79,14 +81,14 @@ class FDBDatabase extends FakeEventTarget { this.name = rawDatabase.name; this.version = rawDatabase.version; this.objectStoreNames = new FakeDOMStringList( - ...Array.from(rawDatabase.rawObjectStores.keys()).sort(), + ...Array.from(rawDatabase.rawObjectStores.keys()).sort() ); } // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore public createObjectStore( name: string, - options: { autoIncrement?: boolean; keyPath?: KeyPath } | null = {}, + options: { autoIncrement?: boolean; keyPath?: KeyPath } | null = {} ) { if (name === undefined) { throw new TypeError(); @@ -130,14 +132,14 @@ class FDBDatabase extends FakeEventTarget { this._rawDatabase, name, keyPath, - autoIncrement, + autoIncrement ); this.objectStoreNames._push(name); this.objectStoreNames._sort(); transaction._scope.add(name); this._rawDatabase.rawObjectStores.set(name, rawObjectStore); transaction.objectStoreNames = new FakeDOMStringList( - ...this.objectStoreNames, + ...this.objectStoreNames ); return transaction.objectStore(name); } @@ -156,10 +158,10 @@ class FDBDatabase extends FakeEventTarget { this.objectStoreNames = new FakeDOMStringList( ...Array.from(this.objectStoreNames).filter((objectStoreName) => { return objectStoreName !== name; - }), + }) ); transaction.objectStoreNames = new FakeDOMStringList( - ...this.objectStoreNames, + ...this.objectStoreNames ); transaction._rollbackLog.push(() => { @@ -191,7 +193,7 @@ class FDBDatabase extends FakeEventTarget { transaction.mode === "versionchange" && transaction.db === this ); - }, + } ); if (hasActiveVersionchange) { throw new InvalidStateError(); @@ -210,7 +212,7 @@ class FDBDatabase extends FakeEventTarget { for (const storeName of storeNames) { if (!this.objectStoreNames.contains(storeName)) { throw new NotFoundError( - "No objectStore named " + storeName + " in this database", + "No objectStore named " + storeName + " in this database" ); } } diff --git a/src/lib/FakeEventTarget.ts b/src/lib/FakeEventTarget.ts index 625215e3..c4397aa0 100644 --- a/src/lib/FakeEventTarget.ts +++ b/src/lib/FakeEventTarget.ts @@ -3,6 +3,7 @@ import FakeEvent from "./FakeEvent.js"; import { EventCallback, EventType } from "./types.js"; type EventTypeProp = + | "onclose" | "onabort" | "onblocked" | "oncomplete" @@ -43,6 +44,7 @@ const invokeEventListeners = (event: FakeEvent, obj: FakeEventTarget) => { } const typeToProp: { [key in EventType]: EventTypeProp } = { + close: "onclose", abort: "onabort", blocked: "onblocked", complete: "oncomplete", @@ -74,6 +76,7 @@ abstract class FakeEventTarget { public readonly listeners: Listener[] = []; // These will be overridden in individual subclasses and made not readonly + public readonly onclose: EventCallback | null | undefined; public readonly onabort: EventCallback | null | undefined; public readonly onblocked: EventCallback | null | undefined; public readonly oncomplete: EventCallback | null | undefined; @@ -85,7 +88,7 @@ abstract class FakeEventTarget { public addEventListener( type: EventType, callback: EventCallback, - capture = false, + capture = false ) { this.listeners.push({ callback, @@ -97,7 +100,7 @@ abstract class FakeEventTarget { public removeEventListener( type: EventType, callback: EventCallback, - capture = false, + capture = false ) { const i = this.listeners.findIndex((listener) => { return ( diff --git a/src/lib/types.ts b/src/lib/types.ts index 519784ad..59a65b60 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -13,6 +13,7 @@ interface EventInCallback extends Event { export type EventCallback = (event: EventInCallback) => void; export type EventType = + | "close" | "abort" | "blocked" | "complete" diff --git a/src/test/fakeIndexedDB/fakeIndexedDB.ts b/src/test/fakeIndexedDB/fakeIndexedDB.ts index adae7a39..cabb5900 100644 --- a/src/test/fakeIndexedDB/fakeIndexedDB.ts +++ b/src/test/fakeIndexedDB/fakeIndexedDB.ts @@ -712,6 +712,15 @@ describe("fakeIndexedDB Tests", () => { done(); }); }); + + it("should trigger onclose event", (done) => { + const request = fakeIndexedDB.open("test" + Math.random()); + request.onsuccess = (e) => { + const db = e.target.result; + db.addEventListener("close", done); + db.close(); + }; + }); }); it("confirm openCursor works (issue #60)", (done) => {