@openmrs/esm-error-handling 10.0.1-pre.5542 → 10.0.1-pre.5545
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -4
- package/package.json +3 -3
- package/src/index.ts +28 -4
- package/src/openmrs-esm-error-handling.test.ts +46 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Successfully compiled: 1 file with swc (
|
|
1
|
+
Successfully compiled: 1 file with swc (178.11ms)
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,QAKvC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,KAExB,aAAa,OAAO,UAK7B"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/** @module @category Error Handling */ import { dispatchToastShown } from "@openmrs/esm-globals";
|
|
2
|
-
window.onerror
|
|
3
|
-
|
|
2
|
+
// Uses the standard `window.onerror` signature: the first argument is the error
|
|
3
|
+
// message (a string) or an Event, and the fifth is the actual Error object (when
|
|
4
|
+
// the browser provides it). We prefer the Error so the toast shows its message.
|
|
5
|
+
window.onerror = function(message, _source, _lineno, _colno, error) {
|
|
6
|
+
console.error('Unexpected error: ', error ?? message);
|
|
4
7
|
dispatchToastShown({
|
|
5
|
-
description: error ?? 'Oops! An unexpected error occurred.',
|
|
8
|
+
description: getErrorMessage(error ?? message, 'Oops! An unexpected error occurred.'),
|
|
6
9
|
kind: 'error',
|
|
7
10
|
title: 'Error'
|
|
8
11
|
});
|
|
@@ -11,11 +14,28 @@ window.onerror = function(error) {
|
|
|
11
14
|
window.onunhandledrejection = function(event) {
|
|
12
15
|
console.error('Unhandled rejection: ', event.reason);
|
|
13
16
|
dispatchToastShown({
|
|
14
|
-
|
|
17
|
+
// `event.reason` is whatever the promise rejected with, frequently an Error
|
|
18
|
+
// object. `showToast` expects `description` to be a renderable, non-empty
|
|
19
|
+
// value, so resolve it to a string message rather than passing the raw
|
|
20
|
+
// rejection (which renders as "[object Object]" and fails the non-empty check).
|
|
21
|
+
description: getErrorMessage(event.reason, 'Oops! An unhandled promise rejection occurred.'),
|
|
15
22
|
kind: 'error',
|
|
16
23
|
title: 'Error'
|
|
17
24
|
});
|
|
18
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Resolves an arbitrary thrown/rejected value to a user-facing, non-empty
|
|
28
|
+
* message string suitable for use as a toast description, falling back to the
|
|
29
|
+
* provided message when no usable message can be derived.
|
|
30
|
+
*/ function getErrorMessage(reason, fallback) {
|
|
31
|
+
if (reason instanceof Error) {
|
|
32
|
+
return reason.message || fallback;
|
|
33
|
+
}
|
|
34
|
+
if (typeof reason === 'string' && reason.trim().length > 0) {
|
|
35
|
+
return reason;
|
|
36
|
+
}
|
|
37
|
+
return fallback;
|
|
38
|
+
}
|
|
19
39
|
/**
|
|
20
40
|
* Reports an error to the global error handler. The error will be displayed
|
|
21
41
|
* to the user as a toast notification. This function ensures the error is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-error-handling",
|
|
3
|
-
"version": "10.0.1-pre.
|
|
3
|
+
"version": "10.0.1-pre.5545",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "An ES module to help with error handling",
|
|
6
6
|
"type": "module",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@openmrs/esm-globals": "^10.0.1-pre.
|
|
49
|
+
"@openmrs/esm-globals": "^10.0.1-pre.5545"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@openmrs/esm-globals": "10.0.1-pre.
|
|
52
|
+
"@openmrs/esm-globals": "10.0.1-pre.5545",
|
|
53
53
|
"@swc/cli": "0.8.1",
|
|
54
54
|
"@swc/core": "1.15.21",
|
|
55
55
|
"@vitest/coverage-v8": "^4.1.2",
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/** @module @category Error Handling */
|
|
2
2
|
import { dispatchToastShown } from '@openmrs/esm-globals';
|
|
3
3
|
|
|
4
|
-
window.onerror
|
|
5
|
-
|
|
4
|
+
// Uses the standard `window.onerror` signature: the first argument is the error
|
|
5
|
+
// message (a string) or an Event, and the fifth is the actual Error object (when
|
|
6
|
+
// the browser provides it). We prefer the Error so the toast shows its message.
|
|
7
|
+
window.onerror = function (message, _source, _lineno, _colno, error) {
|
|
8
|
+
console.error('Unexpected error: ', error ?? message);
|
|
6
9
|
dispatchToastShown({
|
|
7
|
-
description: error ?? 'Oops! An unexpected error occurred.',
|
|
10
|
+
description: getErrorMessage(error ?? message, 'Oops! An unexpected error occurred.'),
|
|
8
11
|
kind: 'error',
|
|
9
12
|
title: 'Error',
|
|
10
13
|
});
|
|
@@ -14,12 +17,33 @@ window.onerror = function (error) {
|
|
|
14
17
|
window.onunhandledrejection = function (event: PromiseRejectionEvent) {
|
|
15
18
|
console.error('Unhandled rejection: ', event.reason);
|
|
16
19
|
dispatchToastShown({
|
|
17
|
-
|
|
20
|
+
// `event.reason` is whatever the promise rejected with, frequently an Error
|
|
21
|
+
// object. `showToast` expects `description` to be a renderable, non-empty
|
|
22
|
+
// value, so resolve it to a string message rather than passing the raw
|
|
23
|
+
// rejection (which renders as "[object Object]" and fails the non-empty check).
|
|
24
|
+
description: getErrorMessage(event.reason, 'Oops! An unhandled promise rejection occurred.'),
|
|
18
25
|
kind: 'error',
|
|
19
26
|
title: 'Error',
|
|
20
27
|
});
|
|
21
28
|
};
|
|
22
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Resolves an arbitrary thrown/rejected value to a user-facing, non-empty
|
|
32
|
+
* message string suitable for use as a toast description, falling back to the
|
|
33
|
+
* provided message when no usable message can be derived.
|
|
34
|
+
*/
|
|
35
|
+
function getErrorMessage(reason: unknown, fallback: string): string {
|
|
36
|
+
if (reason instanceof Error) {
|
|
37
|
+
return reason.message || fallback;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof reason === 'string' && reason.trim().length > 0) {
|
|
41
|
+
return reason;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return fallback;
|
|
45
|
+
}
|
|
46
|
+
|
|
23
47
|
/**
|
|
24
48
|
* Reports an error to the global error handler. The error will be displayed
|
|
25
49
|
* to the user as a toast notification. This function ensures the error is
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { dispatchToastShown } from '@openmrs/esm-globals';
|
|
2
3
|
import { reportError } from './index';
|
|
3
4
|
|
|
5
|
+
vi.mock('@openmrs/esm-globals', () => ({
|
|
6
|
+
dispatchToastShown: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
4
9
|
vi.useFakeTimers();
|
|
5
10
|
|
|
11
|
+
const mockDispatchToastShown = vi.mocked(dispatchToastShown);
|
|
12
|
+
|
|
6
13
|
describe('error handler', () => {
|
|
7
14
|
it('transforms non-Error inputs into valid Error objects', () => {
|
|
8
15
|
expect(() => {
|
|
@@ -26,3 +33,41 @@ describe('error handler', () => {
|
|
|
26
33
|
}).toThrow("'undefined' was thrown as an error");
|
|
27
34
|
});
|
|
28
35
|
});
|
|
36
|
+
|
|
37
|
+
describe('window.onunhandledrejection', () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
mockDispatchToastShown.mockClear();
|
|
40
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// The handler only reads `event.reason`, so a minimal stand-in avoids
|
|
44
|
+
// constructing a real (and itself-unhandled) PromiseRejectionEvent.
|
|
45
|
+
const fireRejection = (reason: unknown) => window.onunhandledrejection?.({ reason } as PromiseRejectionEvent);
|
|
46
|
+
|
|
47
|
+
it('shows a toast with the Error message as a string description', () => {
|
|
48
|
+
fireRejection(new Error('Something broke'));
|
|
49
|
+
|
|
50
|
+
expect(mockDispatchToastShown).toHaveBeenCalledWith(
|
|
51
|
+
expect.objectContaining({ description: 'Something broke', kind: 'error', title: 'Error' }),
|
|
52
|
+
);
|
|
53
|
+
expect(typeof mockDispatchToastShown.mock.calls[0][0].description).toBe('string');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('shows a string reason directly', () => {
|
|
57
|
+
fireRejection('plain string reason');
|
|
58
|
+
|
|
59
|
+
expect(mockDispatchToastShown).toHaveBeenCalledWith(
|
|
60
|
+
expect.objectContaining({ description: 'plain string reason' }),
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('falls back to a friendly message for empty/non-string reasons', () => {
|
|
65
|
+
for (const reason of [undefined, null, new Error(''), { some: 'object' }]) {
|
|
66
|
+
mockDispatchToastShown.mockClear();
|
|
67
|
+
fireRejection(reason);
|
|
68
|
+
expect(mockDispatchToastShown.mock.calls[0][0].description).toBe(
|
|
69
|
+
'Oops! An unhandled promise rejection occurred.',
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|