Skip to content

Commit 4c0e32f

Browse files
committed
Implemented awaiting an uncaught exception
1 parent 7a9d735 commit 4c0e32f

File tree

6 files changed

+62
-14
lines changed

6 files changed

+62
-14
lines changed

.vscode/launch.json

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"--import=tsx",
7575
"--expose_gc",
7676
"--enable-source-maps",
77-
"--no-warnings",
77+
"--force-node-api-uncaught-exceptions-policy",
7878
"${workspaceRoot}/node_modules/mocha/lib/cli/cli.js",
7979
"--require",
8080
"src/node/inject-dev-environment.ts",
@@ -85,6 +85,28 @@
8585
"${input:integrationTestFilter}"
8686
]
8787
},
88+
{
89+
"type": "lldb",
90+
"request": "launch",
91+
"name": "LLDB: Integration tests (throwing from listeners)",
92+
"program": "node",
93+
"cwd": "${workspaceRoot}/integration-tests/tests",
94+
"args": [
95+
"--inspect",
96+
"--import=tsx",
97+
"--expose_gc",
98+
"--enable-source-maps",
99+
"--force-node-api-uncaught-exceptions-policy",
100+
"${workspaceRoot}/node_modules/mocha/lib/cli/cli.js",
101+
"--require",
102+
"src/node/inject-dev-environment.ts",
103+
"src/node/index.ts",
104+
"--timeout",
105+
"10000",
106+
"--grep",
107+
"can throw from a listener"
108+
]
109+
},
88110
{
89111
"type": "node",
90112
"presentation": {
@@ -99,7 +121,7 @@
99121
"--import=tsx",
100122
"--expose_gc",
101123
"--enable-source-maps",
102-
"--no-warnings"
124+
"--force-node-api-uncaught-exceptions-policy"
103125
],
104126
"args": [
105127
"--require",

integration-tests/environments/node/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@
66
"scripts": {
77
"test": "wireit",
88
"test:commonjs": "wireit",
9-
"test:ci": "mocha-remote --reporter @realm/mocha-reporter -- tsx index.mjs",
9+
"test:ci": "mocha-remote --reporter @realm/mocha-reporter -- tsx --force-node-api-uncaught-exceptions-policy index.mjs",
1010
"lint": "eslint --ext js,mjs ."
1111
},
1212
"wireit": {
1313
"test": {
14-
"command": "mocha-remote --reporter @realm/mocha-reporter -- tsx index.mjs",
14+
"command": "mocha-remote --reporter @realm/mocha-reporter -- tsx --force-node-api-uncaught-exceptions-policy index.mjs",
1515
"dependencies": [
1616
"../../../packages/realm:build:ts",
1717
"../../../packages/realm:build:node",
1818
"../../../packages/mocha-reporter:bundle"
1919
]
2020
},
2121
"test:commonjs": {
22-
"command": "mocha-remote --reporter @realm/mocha-reporter -- tsx index.cjs",
22+
"command": "mocha-remote --reporter @realm/mocha-reporter -- tsx --force-node-api-uncaught-exceptions-policy index.cjs",
2323
"dependencies": [
2424
"../../../packages/realm:build:ts",
2525
"../../../packages/realm:build:node",

integration-tests/tests/.mocharc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"import=tsx",
44
"expose_gc",
55
"enable-source-maps",
6-
"no-warnings"
6+
"force-node-api-uncaught-exceptions-policy"
77
],
88
"reporter": "@realm/mocha-reporter",
99
"require": [

integration-tests/tests/src/node/setup-globals.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ Object.assign(globalThis, {
4444
},
4545
},
4646
gc: vm.runInNewContext("gc"),
47+
async nextUncaughtException(timeoutMs = 5000) {
48+
// Remove any other listeners, storing them later so they can be restored
49+
const listenersBefore = process.listeners("uncaughtException");
50+
process.removeAllListeners("uncaughtException");
51+
try {
52+
return await new Promise<Error>((resolve, reject) => {
53+
const timeoutTimer = setTimeout(() => {
54+
process.off("uncaughtException", handleException);
55+
const error = new Error(`Timed out waiting for uncaught exception (waited ${timeoutMs} ms)`);
56+
reject(error);
57+
}, timeoutMs);
58+
function handleException(error: Error) {
59+
clearTimeout(timeoutTimer);
60+
resolve(error);
61+
}
62+
process.once("uncaughtException", handleException);
63+
});
64+
} finally {
65+
for (const listener of listenersBefore) {
66+
process.addListener("uncaughtException", listener);
67+
}
68+
}
69+
},
4770
});
4871

4972
// Indicate that the tests are running in Node

integration-tests/tests/src/tests/observable.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,12 +467,16 @@ describe("Observable", () => {
467467
});
468468

469469
it.skipIf(
470-
!environment.testThrowingListeners,
470+
typeof nextUncaughtException !== "function",
471471
"can throw from a listener",
472472
async function (this: RealmObjectContext<Person>) {
473+
assert(typeof nextUncaughtException === "function", "Expected ability to await an uncaught exception");
474+
const uncaughtException = nextUncaughtException();
473475
this.object.addListener(() => {
474476
throw new Error("boom!");
475477
});
478+
const error = await uncaughtException;
479+
expect(error.message).equals("boom!");
476480
},
477481
);
478482

@@ -880,12 +884,16 @@ describe("Observable", () => {
880884
});
881885

882886
it.skipIf(
883-
!environment.testThrowingListeners,
887+
typeof nextUncaughtException !== "function",
884888
"can throw from a listener",
885889
async function (this: RealmObjectContext<Person>) {
890+
assert(typeof nextUncaughtException === "function", "Expected ability to await an uncaught exception");
891+
const uncaughtException = nextUncaughtException();
886892
this.realm.objects("Person").addListener(() => {
887893
throw new Error("boom!");
888894
});
895+
const error = await uncaughtException;
896+
expect(error.message).equals("boom!");
889897
},
890898
);
891899

integration-tests/tests/src/typings.d.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,6 @@ type KnownEnvironment = {
107107
* React native specific variable injected by the runner, to signal if the tests are ran by the legacy chrome debugger (i.e. in a browser).
108108
* @deprecated Since we no longer support the legacy chrome debugger. */
109109
chromeDebugging?: true;
110-
111-
/**
112-
* Test throwing from listeners.
113-
* These tests are skipped by default, because we don't want these to fail and we don't have a good way to instrument Mocha to expect these uncaught exceptions.
114-
*/
115-
testThrowingListeners?: true;
116110
};
117111

118112
type Environment = KnownEnvironment & Record<string, unknown>;
@@ -122,6 +116,7 @@ declare const fs: fs;
122116
declare const path: path;
123117
declare const environment: Environment;
124118
declare const gc: undefined | (() => void);
119+
declare const nextUncaughtException: undefined | (() => Promise<Error>);
125120

126121
// Extend the mocha test function with the skipIf that we patch in from index.ts
127122
declare namespace Mocha {

0 commit comments

Comments
 (0)