Skip to content

Commit 8d244c5

Browse files
authored
Merge pull request #162 from nolanlawson/minimal-event-changes
Minimal changes to improve `Event` compatibility
2 parents 26e91e6 + e6039b8 commit 8d244c5

File tree

3 files changed

+104
-7
lines changed

3 files changed

+104
-7
lines changed

src/lib/FakeEventTarget.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { InvalidStateError } from "./errors.js";
22
import type FakeEvent from "./FakeEvent.js";
3-
import type { EventCallback, EventType } from "./types.js";
3+
import type {
4+
EventCallback,
5+
EventCallbackOrEventCallbackObject,
6+
EventType,
7+
} from "./types.js";
48

59
type EventTypeProp =
610
| "onabort"
@@ -13,7 +17,7 @@ type EventTypeProp =
1317
| "onversionchange";
1418

1519
interface Listener {
16-
callback: EventCallback;
20+
callback: EventCallbackOrEventCallbackObject;
1721
capture: boolean;
1822
type: EventType;
1923
}
@@ -32,8 +36,12 @@ const invokeEventListeners = (event: FakeEvent, obj: FakeEventTarget) => {
3236
event.currentTarget = obj;
3337

3438
const errors: Error[] = [];
35-
const invoke = (callback: EventCallback) => {
39+
const invoke = (callbackOrObject: EventCallbackOrEventCallbackObject) => {
3640
try {
41+
const callback =
42+
typeof callbackOrObject === "function"
43+
? callbackOrObject
44+
: callbackOrObject.handleEvent;
3745
// @ts-expect-error EventCallback's types are not quite right here
3846
callback.call(event.currentTarget, event);
3947
} catch (err) {
@@ -101,9 +109,12 @@ abstract class FakeEventTarget {
101109

102110
public addEventListener(
103111
type: EventType,
104-
callback: EventCallback,
105-
capture = false,
112+
callback: EventCallbackOrEventCallbackObject,
113+
options?: boolean | AddEventListenerOptions | undefined,
106114
) {
115+
const capture = !!(typeof options === "object" && options
116+
? options.capture
117+
: options);
107118
this.listeners.push({
108119
callback,
109120
capture,
@@ -113,9 +124,12 @@ abstract class FakeEventTarget {
113124

114125
public removeEventListener(
115126
type: EventType,
116-
callback: EventCallback,
117-
capture = false,
127+
callback: EventCallbackOrEventCallbackObject,
128+
options?: boolean | AddEventListenerOptions | undefined,
118129
) {
130+
const capture = !!(typeof options === "object" && options
131+
? options.capture
132+
: options);
119133
const i = this.listeners.findIndex((listener) => {
120134
return (
121135
listener.type === type &&

src/lib/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ interface EventInCallback extends Event {
1212

1313
export type EventCallback = (event: EventInCallback) => void;
1414

15+
export type EventCallbackOrEventCallbackObject =
16+
| EventCallback
17+
| { handleEvent: EventCallback };
18+
1519
export type EventType =
1620
| "abort"
1721
| "blocked"

src/test/fakeIndexedDB/fakeIndexedDB.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,85 @@ describe("fakeIndexedDB Tests", () => {
747747
done();
748748
});
749749
});
750+
751+
it("allows handleEvent object in addEventListener", () => {
752+
return new Promise<void>((resolve, reject) => {
753+
const request = fakeIndexedDB.open("test" + Math.random());
754+
request.addEventListener("upgradeneeded", {
755+
handleEvent(e) {
756+
const db = (e.target as any).result as FDBDatabase;
757+
db.createObjectStore("store");
758+
},
759+
});
760+
request.addEventListener("success", {
761+
handleEvent(e) {
762+
const db = (e.target as any).result as FDBDatabase;
763+
764+
const tx = db.transaction("store", "readwrite");
765+
tx.objectStore("store").put({}, 1);
766+
tx.onerror = (e) => reject(e.target.error);
767+
768+
tx.addEventListener("complete", {
769+
handleEvent() {
770+
resolve();
771+
},
772+
});
773+
},
774+
});
775+
});
776+
});
777+
778+
describe("capture", () => {
779+
[
780+
// capture=true
781+
true,
782+
{ capture: true },
783+
// capture=false
784+
false,
785+
{ capture: false },
786+
undefined,
787+
null,
788+
].forEach((arg3) => {
789+
const capture =
790+
typeof arg3 === "object" && arg3 ? arg3.capture : !!arg3;
791+
it(`can set capture=${capture} using third argument: ${JSON.stringify(arg3)}`, async () => {
792+
const logs: string[] = [];
793+
const log = (text: string) => () => {
794+
logs.push(text);
795+
};
796+
await new Promise<void>((resolve) => {
797+
const request = fakeIndexedDB.open(
798+
"test" + Math.random(),
799+
);
800+
request.onupgradeneeded = (e) => {
801+
const db = e.target.result as FDBDatabase;
802+
db.createObjectStore("store");
803+
db.addEventListener(
804+
"abort",
805+
log("db"),
806+
arg3 as any,
807+
);
808+
};
809+
request.onsuccess = (e) => {
810+
const db = e.target.result as FDBDatabase;
811+
const tx = db.transaction("store", "readwrite");
812+
tx.addEventListener(
813+
"abort",
814+
log("tx"),
815+
arg3 as any,
816+
);
817+
tx.addEventListener("abort", () => resolve());
818+
tx.abort();
819+
};
820+
});
821+
const expected = ["tx", "db"]; // bubble order - bottom-up
822+
if (capture) {
823+
expected.reverse(); // capture order - top-down
824+
}
825+
assert.deepStrictEqual(logs, expected);
826+
});
827+
});
828+
});
750829
});
751830

752831
it("confirm openCursor works (issue #60)", (done) => {

0 commit comments

Comments
 (0)