diff --git a/Documentation/Contributors/TestingGuide/README.md b/Documentation/Contributors/TestingGuide/README.md index 915c8bf38d38..ffde3a98870a 100644 --- a/Documentation/Contributors/TestingGuide/README.md +++ b/Documentation/Contributors/TestingGuide/README.md @@ -441,14 +441,26 @@ In addition to testing success cases, we also test all failure cases. The custom ```javascript it("fromDegrees throws with no latitude", function () { expect(function () { - Cartesian3.fromDegrees(0.0); - }).toThrowDeveloperError(); + Cartesian3.fromDegrees(0.0, undefined); + }).toThrowDeveloperError( + "Expected latitude to be typeof number, actual typeof was undefined", + ); }); ``` Above, `Cartesian3.fromDegrees` is expected to throw a `DeveloperError` because it expects longitude and latitude arguments, and only longitude is provided. -Tips: +#### Tips + +- When testing for exceptions it is recommended to test for the expected error message to verify that the test is triggering the correct error. This can be achieved either with the full error message, like above, or with a regular expression that will match the error message like this: + +```javascript +it("fromDegrees throws with no latitude", function () { + expect(function () { + Cartesian3.fromDegrees(0.0, undefined); + }).toThrowDeveloperError(/Expected latitude to be/); +}); +``` - When testing for exceptions, put only code that is expected to trigger the exception inside the function passed to `expect()`, in case setup code unintentionally throws an exception. - To verify the right exception is thrown, it is often useful to comment out the `expect` call when first running the test, for example: @@ -456,7 +468,7 @@ Tips: ```javascript it("fromDegrees throws with no latitude", function () { // expect(function() { - Cartesian3.fromDegrees(0.0); + Cartesian3.fromDegrees(0.0, undefined); // }).toThrowDeveloperError(); }); ``` diff --git a/Specs/addDefaultMatchers.js b/Specs/addDefaultMatchers.js index 9ad56f65c30a..67079ed61042 100644 --- a/Specs/addDefaultMatchers.js +++ b/Specs/addDefaultMatchers.js @@ -46,7 +46,14 @@ function makeAsyncThrowFunction(debug, Type, name) { .catch((e) => { let result = e instanceof Type || e.name === name; if (defined(message)) { - result = result && util.equals(e.message, message); + if (typeof message === "string") { + result = result && e.message === message; + } else { + // if the expected message is a regular expression check it against the error message + // this matches how the builtin .toRejectWithError(Error, /message/) works + // https://github.com/jasmine/jasmine/blob/main/src/core/matchers/toThrowError.js + result = result && message.test(e.message); + } } return { pass: result, @@ -92,7 +99,7 @@ function makeThrowFunction(debug, Type, name) { if (debug) { return function (util) { return { - compare: function (actual, expected) { + compare: function (actual, message) { // based on the built-in Jasmine toThrow matcher let result = false; let exception; @@ -110,20 +117,29 @@ function makeThrowFunction(debug, Type, name) { if (exception) { result = exception instanceof Type || exception.name === name; } + if (defined(message)) { + if (typeof message === "string") { + result = result && exception.message === message; + } else { + // if the expected message is a regular expression check it against the error message + // this matches how the builtin .toRejectWithError(Error, /message/) works + // https://github.com/jasmine/jasmine/blob/main/src/core/matchers/toThrowError.js + result = result && message.test(exception.message); + } + } - let message; + let testMessage; if (result) { - message = [ - `Expected function not to throw ${name} , but it threw`, - exception.message || exception, - ].join(" "); + testMessage = `Expected function not to throw ${name} , but it threw ${exception.message || exception}`; } else { - message = `Expected function to throw ${name}.`; + testMessage = defined(message) + ? `Expected to throw with ${name}: ${message}, but it was thrown with ${exception}` + : `Expected function to throw with ${name}.`; } return { pass: result, - message: message, + message: testMessage, }; }, }; diff --git a/packages/engine/Specs/Core/Cartesian3Spec.js b/packages/engine/Specs/Core/Cartesian3Spec.js index d2cae1feef9d..a0441473c06d 100644 --- a/packages/engine/Specs/Core/Cartesian3Spec.js +++ b/packages/engine/Specs/Core/Cartesian3Spec.js @@ -1241,14 +1241,16 @@ describe("Core/Cartesian3", function () { it("fromDegrees throws with no longitude", function () { expect(function () { - Cartesian3.fromDegrees(); - }).toThrowDeveloperError(); + Cartesian3.fromDegrees(undefined, undefined); + }).toThrowDeveloperError(/Expected longitude to be/); }); it("fromDegrees throws with no latitude", function () { expect(function () { - Cartesian3.fromDegrees(1); - }).toThrowDeveloperError(); + Cartesian3.fromDegrees(1, undefined); + }).toThrowDeveloperError( + "Expected latitude to be typeof number, actual typeof was undefined", + ); }); it("fromDegrees works works with default ellipsoid", function () { diff --git a/packages/engine/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js b/packages/engine/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js index 416514c4a68e..8816594b228e 100644 --- a/packages/engine/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/GoogleEarthEnterpriseImageryProviderSpec.js @@ -155,7 +155,7 @@ describe("Scene/GoogleEarthEnterpriseImageryProvider", function () { it("fromMetadata throws without metadata", function () { expect(() => GoogleEarthEnterpriseImageryProvider.fromMetadata(), - ).toThrowDeveloperError(""); + ).toThrowDeveloperError(/metadata is required/); }); it("fromMetadata throws if there isn't imagery", async function () { diff --git a/packages/engine/Specs/Scene/ImageryLayerSpec.js b/packages/engine/Specs/Scene/ImageryLayerSpec.js index 5ec56fae243d..506d3f9ad039 100644 --- a/packages/engine/Specs/Scene/ImageryLayerSpec.js +++ b/packages/engine/Specs/Scene/ImageryLayerSpec.js @@ -78,7 +78,7 @@ describe( it("fromProviderAsync throws without provider promise", function () { expect(() => ImageryLayer.fromProviderAsync()).toThrowDeveloperError( - "expected", + /Expected imageryProviderPromise to be typeof object/, ); }); diff --git a/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js b/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js index 2bd1728922d8..eb04cd0f84c3 100644 --- a/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js @@ -31,7 +31,7 @@ describe("Scene/MapboxStyleImageryProvider", function () { it("requires the styleId to be specified", function () { expect(function () { return new MapboxStyleImageryProvider({ accessToken: "test-token" }); - }).toThrowDeveloperError("styleId is required"); + }).toThrowDeveloperError("options.styleId is required."); }); it("returns valid value for hasAlphaChannel", function () {