From 2eed93311bfdca860da0e55382bbc73f4bf1d4b5 Mon Sep 17 00:00:00 2001 From: Simon Ihmig Date: Wed, 28 Feb 2024 15:00:02 +0100 Subject: [PATCH 1/4] Better errors from visitable This adds the actual error message from Ember's router to the (too generic) message from `visitable`. This is especially important when your test needs to know what kind of error was triggered. For example some tests might want to handle `TransitionAborted` errors differently, see https://github.com/emberjs/ember-test-helpers/issues/332#issuecomment-414641697. --- addon/src/properties/visitable.js | 4 ++-- test-app/tests/unit/-private/properties/visitable-test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/src/properties/visitable.js b/addon/src/properties/visitable.js index ff17adf3..b4cdd510 100644 --- a/addon/src/properties/visitable.js +++ b/addon/src/properties/visitable.js @@ -138,8 +138,8 @@ export function visitable(path) { return getAdapter() .visit(fullPath) - .catch(() => { - throw new Error(`Failed to visit URL '${fullPath}'`); + .catch((e) => { + throw new Error(`Failed to visit URL '${fullPath}': ${e.message}`); }); }); } diff --git a/test-app/tests/unit/-private/properties/visitable-test.ts b/test-app/tests/unit/-private/properties/visitable-test.ts index 10b858e2..5d2c17f4 100644 --- a/test-app/tests/unit/-private/properties/visitable-test.ts +++ b/test-app/tests/unit/-private/properties/visitable-test.ts @@ -108,7 +108,7 @@ module('visitable', function (hooks) { } catch (e) { assert.strictEqual( e?.toString(), - `Error: Failed to visit URL '/non-existing-url/value' + `Error: Failed to visit URL '/non-existing-url/value': /non-existing-url/value PageObject: 'page.foo("[object Object]")' Selector: '.scope'` From 57543610f5f0c38e9519a962fca6995b215753ae Mon Sep 17 00:00:00 2001 From: Simon Ihmig Date: Thu, 7 Mar 2024 09:30:50 +0100 Subject: [PATCH 2/4] Pass original error message from visit as Error#cause --- addon/src/-private/better-errors.js | 2 +- addon/src/properties/visitable.js | 4 +++- test-app/tests/unit/-private/properties/visitable-test.ts | 7 ++++++- test-app/tsconfig.json | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/addon/src/-private/better-errors.js b/addon/src/-private/better-errors.js index 9973d7d0..52d36e98 100644 --- a/addon/src/-private/better-errors.js +++ b/addon/src/-private/better-errors.js @@ -24,7 +24,7 @@ export function throwBetterError(node, key, error, { selector } = {}) { const wrapperError = new PageObjectError(message, { cause: { - message, + message: error.cause ? error.cause.toString() : message, key, node, selector, diff --git a/addon/src/properties/visitable.js b/addon/src/properties/visitable.js index b4cdd510..64c85c98 100644 --- a/addon/src/properties/visitable.js +++ b/addon/src/properties/visitable.js @@ -139,7 +139,9 @@ export function visitable(path) { return getAdapter() .visit(fullPath) .catch((e) => { - throw new Error(`Failed to visit URL '${fullPath}': ${e.message}`); + throw new Error(`Failed to visit URL '${fullPath}': ${e.toString()}`, { + cause: e, + }); }); }); } diff --git a/test-app/tests/unit/-private/properties/visitable-test.ts b/test-app/tests/unit/-private/properties/visitable-test.ts index 5d2c17f4..571ad6a7 100644 --- a/test-app/tests/unit/-private/properties/visitable-test.ts +++ b/test-app/tests/unit/-private/properties/visitable-test.ts @@ -108,11 +108,16 @@ module('visitable', function (hooks) { } catch (e) { assert.strictEqual( e?.toString(), - `Error: Failed to visit URL '/non-existing-url/value': /non-existing-url/value + `Error: Failed to visit URL '/non-existing-url/value': UnrecognizedURLError: /non-existing-url/value PageObject: 'page.foo("[object Object]")' Selector: '.scope'` ); + + assert.strictEqual( + (e as any).cause.message, + 'UnrecognizedURLError: /non-existing-url/value' + ); } }); }); diff --git a/test-app/tsconfig.json b/test-app/tsconfig.json index c819eb84..57fa7b49 100644 --- a/test-app/tsconfig.json +++ b/test-app/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@tsconfig/ember/tsconfig.json", "compilerOptions": { + "target": "es2022", // The combination of `baseUrl` with `paths` allows Ember's classic package // layout, which is not resolvable with the Node resolution algorithm, to // work with TypeScript. From e485026a6bb1506eeeb13addf24c7d6310f93b08 Mon Sep 17 00:00:00 2001 From: Ruslan Hrabovyi Date: Mon, 11 Mar 2024 23:36:03 +0100 Subject: [PATCH 3/4] preserve original error instance ...under the `cause.error` --- addon/src/-private/better-errors.js | 3 ++- .../tests/unit/-private/properties/visitable-test.ts | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addon/src/-private/better-errors.js b/addon/src/-private/better-errors.js index 52d36e98..4ba079dd 100644 --- a/addon/src/-private/better-errors.js +++ b/addon/src/-private/better-errors.js @@ -24,7 +24,8 @@ export function throwBetterError(node, key, error, { selector } = {}) { const wrapperError = new PageObjectError(message, { cause: { - message: error.cause ? error.cause.toString() : message, + message, + error: error.cause, key, node, selector, diff --git a/test-app/tests/unit/-private/properties/visitable-test.ts b/test-app/tests/unit/-private/properties/visitable-test.ts index 571ad6a7..74c6b84c 100644 --- a/test-app/tests/unit/-private/properties/visitable-test.ts +++ b/test-app/tests/unit/-private/properties/visitable-test.ts @@ -114,10 +114,15 @@ PageObject: 'page.foo("[object Object]")' Selector: '.scope'` ); - assert.strictEqual( - (e as any).cause.message, - 'UnrecognizedURLError: /non-existing-url/value' + const originalError = (e as any).cause.error; + assert.true( + originalError instanceof Error, + '`cause.error` is an instance of `Error`' ); + + assert.strictEqual(originalError.name, 'UnrecognizedURLError'); + + assert.strictEqual(originalError.message, '/non-existing-url/value'); } }); }); From 9e0ca4924647cc19781d84d398fef3b2a927fb97 Mon Sep 17 00:00:00 2001 From: Ruslan Hrabovyi Date: Mon, 11 Mar 2024 23:36:50 +0100 Subject: [PATCH 4/4] doc: add a brief note about the `cause.error` in the `visitable` error instance --- addon/src/properties/visitable.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/src/properties/visitable.js b/addon/src/properties/visitable.js index 64c85c98..e38f9000 100644 --- a/addon/src/properties/visitable.js +++ b/addon/src/properties/visitable.js @@ -127,7 +127,9 @@ function appendQueryParams(path, queryParams) { * @param {string} path - Full path of the route to visit * @return {Descriptor} * - * @throws Will throw an error if dynamic segments are not filled + * @throws Will throw an error if dynamic segments are not filled. + * Note: An error instance may contain a `cause.error` property + * with the original error thrown by an underlying test helper. */ export function visitable(path) { return action(function (dynamicSegmentsAndQueryParams = {}) {