refactor(testing): align additional error messages (#5810)

This commit is contained in:
Ian Bull 2024-08-26 01:22:16 -04:00 committed by GitHub
parent 9a8b3a5d4e
commit 73987a1772
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 110 additions and 52 deletions

View File

@ -84,7 +84,9 @@ export class TestSuiteInternal<T> implements TestSuite<T> {
const { suite } = describe; const { suite } = describe;
if (suite && !TestSuiteInternal.suites.has(suite.symbol)) { if (suite && !TestSuiteInternal.suites.has(suite.symbol)) {
throw new Error("suite does not represent a registered test suite"); throw new Error(
"Cannot construct Test Suite: suite does not represent a registered test suite",
);
} }
const testSuite = suite const testSuite = suite
? TestSuiteInternal.suites.get(suite.symbol) ? TestSuiteInternal.suites.get(suite.symbol)
@ -101,7 +103,7 @@ export class TestSuiteInternal<T> implements TestSuite<T> {
const value = fn() as any; const value = fn() as any;
if (value instanceof Promise) { if (value instanceof Promise) {
throw new Error( throw new Error(
'Returning a Promise from "describe" is not supported. Tests must be defined synchronously.', 'Returning a Promise from "describe" is not supported: tests must be defined synchronously',
); );
} }
} finally { } finally {

View File

@ -562,7 +562,7 @@ export interface it {
export function it<T>(...args: ItArgs<T>) { export function it<T>(...args: ItArgs<T>) {
if (TestSuiteInternal.runningCount > 0) { if (TestSuiteInternal.runningCount > 0) {
throw new Error( throw new Error(
"cannot register new test cases after already registered test cases start running", "Cannot register new test cases after already registered test cases start running",
); );
} }
const options = itDefinition(...args); const options = itDefinition(...args);
@ -717,7 +717,7 @@ function addHook<T>(
if (!TestSuiteInternal.current) { if (!TestSuiteInternal.current) {
if (TestSuiteInternal.started) { if (TestSuiteInternal.started) {
throw new Error( throw new Error(
"cannot add global hooks after a global test is registered", "Cannot add global hooks after a global test is registered",
); );
} }
TestSuiteInternal.current = new TestSuiteInternal({ TestSuiteInternal.current = new TestSuiteInternal({
@ -1070,7 +1070,7 @@ export function describe<T>(
): TestSuite<T> { ): TestSuite<T> {
if (TestSuiteInternal.runningCount > 0) { if (TestSuiteInternal.runningCount > 0) {
throw new Error( throw new Error(
"cannot register new test suites after already registered test cases start running", "Cannot register new test suites after already registered test cases start running",
); );
} }
const options = describeDefinition(...args); const options = describeDefinition(...args);

View File

@ -2055,7 +2055,7 @@ Deno.test("describe()", async (t) => {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
() => describe("async describe", (async () => {}) as any), () => describe("async describe", (async () => {}) as any),
Error, Error,
'Returning a Promise from "describe" is not supported. Tests must be defined synchronously.', 'Returning a Promise from "describe" is not supported: tests must be defined synchronously',
); );
}, },
); );

View File

@ -435,7 +435,9 @@ function functionSpy<
restore: { restore: {
enumerable: true, enumerable: true,
value: () => { value: () => {
throw new MockError("Function cannot be restored"); throw new MockError(
"Cannot restore: function cannot be restored",
);
}, },
}, },
}); });
@ -643,15 +645,21 @@ function methodSpy<
Return, Return,
>(self: Self, property: keyof Self): MethodSpy<Self, Args, Return> { >(self: Self, property: keyof Self): MethodSpy<Self, Args, Return> {
if (typeof self[property] !== "function") { if (typeof self[property] !== "function") {
throw new MockError("Property is not an instance method"); throw new MockError(
"Cannot spy: property is not an instance method",
);
} }
if (isSpy(self[property])) { if (isSpy(self[property])) {
throw new MockError("Already spying on instance method"); throw new MockError(
"Cannot spy: already spying on instance method",
);
} }
const propertyDescriptor = Object.getOwnPropertyDescriptor(self, property); const propertyDescriptor = Object.getOwnPropertyDescriptor(self, property);
if (propertyDescriptor && !propertyDescriptor.configurable) { if (propertyDescriptor && !propertyDescriptor.configurable) {
throw new MockError("Cannot spy on non-configurable instance method"); throw new MockError(
"Cannot spy: non-configurable instance method",
);
} }
const original = self[property] as unknown as ( const original = self[property] as unknown as (
@ -690,7 +698,9 @@ function methodSpy<
enumerable: true, enumerable: true,
value: () => { value: () => {
if (restored) { if (restored) {
throw new MockError("Instance method already restored"); throw new MockError(
"Cannot restore: instance method already restored",
);
} }
if (propertyDescriptor) { if (propertyDescriptor) {
Object.defineProperty(self, property, propertyDescriptor); Object.defineProperty(self, property, propertyDescriptor);
@ -767,7 +777,9 @@ function constructorSpy<
static readonly calls = calls; static readonly calls = calls;
static readonly restored = false; static readonly restored = false;
static restore() { static restore() {
throw new MockError("Constructor cannot be restored"); throw new MockError(
"Cannot restore: constructor cannot be restored",
);
} }
} as ConstructorSpy<Self, Args>; } as ConstructorSpy<Self, Args>;
return spy; return spy;
@ -1082,15 +1094,19 @@ export function stub<
func?: (this: Self, ...args: Args) => Return, func?: (this: Self, ...args: Args) => Return,
): Stub<Self, Args, Return> { ): Stub<Self, Args, Return> {
if (self[property] !== undefined && typeof self[property] !== "function") { if (self[property] !== undefined && typeof self[property] !== "function") {
throw new MockError("Property is not an instance method"); throw new MockError(
"Cannot stub: property is not an instance method",
);
} }
if (isSpy(self[property])) { if (isSpy(self[property])) {
throw new MockError("Already spying on instance method"); throw new MockError(
"Cannot stub: already spying on instance method",
);
} }
const propertyDescriptor = Object.getOwnPropertyDescriptor(self, property); const propertyDescriptor = Object.getOwnPropertyDescriptor(self, property);
if (propertyDescriptor && !propertyDescriptor.configurable) { if (propertyDescriptor && !propertyDescriptor.configurable) {
throw new MockError("Cannot stub non-configurable instance method"); throw new MockError("Cannot stub: non-configurable instance method");
} }
const fake = func ?? (() => {}) as (this: Self, ...args: Args) => Return; const fake = func ?? (() => {}) as (this: Self, ...args: Args) => Return;
@ -1135,7 +1151,9 @@ export function stub<
enumerable: true, enumerable: true,
value: () => { value: () => {
if (restored) { if (restored) {
throw new MockError("Instance method already restored"); throw new MockError(
"Cannot restore: instance method already restored",
);
} }
if (propertyDescriptor) { if (propertyDescriptor) {
Object.defineProperty(self, property, propertyDescriptor); Object.defineProperty(self, property, propertyDescriptor);

View File

@ -79,7 +79,7 @@ Deno.test("spy()", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Function cannot be restore", "Cannot restore: function cannot be restored",
); );
assertEquals(func.restored, false); assertEquals(func.restored, false);
}); });
@ -125,7 +125,7 @@ Deno.test("spy() works on function", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Function cannot be restored", "Cannot restore: function cannot be restored",
); );
assertEquals(func.restored, false); assertEquals(func.restored, false);
@ -239,7 +239,7 @@ Deno.test("spy() works on instance method", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(func.restored, true); assertEquals(func.restored, true);
}); });
@ -277,7 +277,7 @@ Deno.test("spy() works on instance method symbol", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(func.restored, true); assertEquals(func.restored, true);
}); });
@ -342,7 +342,7 @@ Deno.test("spy() works on instance method property descriptor", () => {
assertThrows( assertThrows(
() => action.restore(), () => action.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(action.restored, true); assertEquals(action.restored, true);
}); });
@ -444,7 +444,7 @@ Deno.test("spy() supports explicit resource management", () => {
if (funcRef) funcRef.restore(); if (funcRef) funcRef.restore();
}, },
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(funcRef.restored, true); assertEquals(funcRef.restored, true);
} }
@ -478,7 +478,7 @@ Deno.test("spy() works on constructor", () => {
assertThrows( assertThrows(
() => PointSpy.restore(), () => PointSpy.restore(),
MockError, MockError,
"Constructor cannot be restored", "Cannot restore: constructor cannot be restored",
); );
}); });
@ -546,7 +546,7 @@ Deno.test("spy() throws when try spying already spied method", () => {
assertThrows( assertThrows(
() => spy(obj, "fn"), () => spy(obj, "fn"),
MockError, MockError,
"Already spying on instance method", "Cannot spy: already spying on instance method",
); );
}); });
@ -556,7 +556,7 @@ Deno.test("spy() throws when the property is not a method", () => {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
() => spy(obj as any, "fn"), () => spy(obj as any, "fn"),
MockError, MockError,
"Property is not an instance method", "Cannot spy: property is not an instance method",
); );
}); });
@ -566,7 +566,7 @@ Deno.test("spy() throws when the property is not configurable", () => {
assertThrows( assertThrows(
() => spy(obj, "fn"), () => spy(obj, "fn"),
MockError, MockError,
"Cannot spy on non-configurable instance method", "Cannot spy: non-configurable instance method",
); );
}); });
@ -602,7 +602,7 @@ Deno.test("stub()", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(func.restored, true); assertEquals(func.restored, true);
}); });
@ -640,7 +640,7 @@ Deno.test("stub() works on function", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(func.restored, true); assertEquals(func.restored, true);
}); });
@ -684,7 +684,7 @@ Deno.test("stub() supports explicit resource management", () => {
if (funcRef) funcRef.restore(); if (funcRef) funcRef.restore();
}, },
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(funcRef.restored, true); assertEquals(funcRef.restored, true);
} }
@ -727,7 +727,7 @@ Deno.test("stub() handles non existent function", () => {
assertThrows( assertThrows(
() => func.restore(), () => func.restore(),
MockError, MockError,
"Instance method already restored", "Cannot restore: instance method already restored",
); );
assertEquals(func.restored, true); assertEquals(func.restored, true);
}); });
@ -797,7 +797,7 @@ Deno.test("stub() throws when the property is not a method", () => {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
() => stub(obj as any, "fn"), () => stub(obj as any, "fn"),
MockError, MockError,
"Property is not an instance method", "Cannot stub: property is not an instance method",
); );
}); });
@ -807,7 +807,7 @@ Deno.test("stub() throws when try stubbing already stubbed method", () => {
assertThrows( assertThrows(
() => stub(obj, "fn"), () => stub(obj, "fn"),
MockError, MockError,
"Already spying on instance method", "Cannot stub: already spying on instance method",
); );
}); });
@ -817,7 +817,7 @@ Deno.test("stub() throws then the property is not configurable", () => {
assertThrows( assertThrows(
() => stub(obj, "fn"), () => stub(obj, "fn"),
MockError, MockError,
"Cannot stub non-configurable instance method", "Cannot stub: non-configurable instance method",
); );
}); });

View File

@ -134,12 +134,12 @@ function fakeSetTimeout(
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
...args: any[] ...args: any[]
): number { ): number {
if (!time) throw new TimeError("Time is not faked"); if (!time) throw new TimeError("Cannot set timeout: time is not faked");
return setTimer(callback, delay, args, false); return setTimer(callback, delay, args, false);
} }
function fakeClearTimeout(id?: unknown) { function fakeClearTimeout(id?: unknown) {
if (!time) throw new TimeError("Time is not faked"); if (!time) throw new TimeError("Cannot clear timeout: time is not faked");
if (typeof id === "number" && dueNodes.has(id)) { if (typeof id === "number" && dueNodes.has(id)) {
dueNodes.delete(id); dueNodes.delete(id);
} }
@ -152,12 +152,12 @@ function fakeSetInterval(
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
...args: any[] ...args: any[]
): number { ): number {
if (!time) throw new TimeError("Time is not faked"); if (!time) throw new TimeError("Cannot set interval: time is not faked");
return setTimer(callback, delay, args, true); return setTimer(callback, delay, args, true);
} }
function fakeClearInterval(id?: unknown) { function fakeClearInterval(id?: unknown) {
if (!time) throw new TimeError("Time is not faked"); if (!time) throw new TimeError("Cannot clear interval: time is not faked");
if (typeof id === "number" && dueNodes.has(id)) { if (typeof id === "number" && dueNodes.has(id)) {
dueNodes.delete(id); dueNodes.delete(id);
} }
@ -294,7 +294,9 @@ export class FakeTime {
start?: number | string | Date | null, start?: number | string | Date | null,
options?: FakeTimeOptions, options?: FakeTimeOptions,
) { ) {
if (time) throw new TimeError("Time is already faked"); if (time) {
throw new TimeError("Cannot construct FakeTime: time is already faked");
}
initializedAt = _internals.Date.now(); initializedAt = _internals.Date.now();
startedAt = start instanceof Date startedAt = start instanceof Date
? start.valueOf() ? start.valueOf()
@ -303,7 +305,11 @@ export class FakeTime {
: typeof start === "string" : typeof start === "string"
? (new Date(start)).valueOf() ? (new Date(start)).valueOf()
: initializedAt; : initializedAt;
if (Number.isNaN(startedAt)) throw new TypeError("Invalid start time"); if (Number.isNaN(startedAt)) {
throw new TypeError(
`Cannot construct FakeTime: invalid start time ${startedAt}`,
);
}
now = startedAt; now = startedAt;
timerId = timerIdGen(); timerId = timerIdGen();
@ -381,7 +387,9 @@ export class FakeTime {
* ``` * ```
*/ */
static restore() { static restore() {
if (!time) throw new TimeError("Time is already restored"); if (!time) {
throw new TimeError("Cannot restore time: time is already restored");
}
time.restore(); time.restore();
} }
@ -417,7 +425,11 @@ export class FakeTime {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
...args: any[] ...args: any[]
): Promise<T> { ): Promise<T> {
if (!time) return Promise.reject(new TimeError("Time is not faked")); if (!time) {
return Promise.reject(
new TimeError("Cannot restore time: time is not faked"),
);
}
restoreGlobals(); restoreGlobals();
try { try {
const result = callback.apply(null, args); const result = callback.apply(null, args);
@ -478,7 +490,11 @@ export class FakeTime {
* @param value The current time (in milliseconds) * @param value The current time (in milliseconds)
*/ */
set now(value: number) { set now(value: number) {
if (value < now) throw new RangeError("Time cannot go backwards"); if (value < now) {
throw new RangeError(
`Cannot set current time in the past, time must be >= ${now}: received ${value}`,
);
}
let dueNode: DueNode | null = dueTree.min(); let dueNode: DueNode | null = dueTree.min();
while (dueNode && dueNode.due <= value) { while (dueNode && dueNode.due <= value) {
const timer: Timer | undefined = dueNode.timers.shift(); const timer: Timer | undefined = dueNode.timers.shift();
@ -803,7 +819,9 @@ export class FakeTime {
* ``` * ```
*/ */
restore() { restore() {
if (!time) throw new TimeError("Time is already restored"); if (!time) {
throw new TimeError("Cannot restore time: time is already restored");
}
time = undefined; time = undefined;
restoreGlobals(); restoreGlobals();
if (advanceIntervalId) clearInterval(advanceIntervalId); if (advanceIntervalId) clearInterval(advanceIntervalId);

View File

@ -339,7 +339,7 @@ Deno.test("FakeTime.restoreFor() returns promise that rejected to TimeError if F
await assertRejects( await assertRejects(
() => FakeTime.restoreFor(() => {}), () => FakeTime.restoreFor(() => {}),
TimeError, TimeError,
"Time is not faked", "Cannot restore time: time is not faked",
); );
}); });
@ -662,15 +662,23 @@ Deno.test("Faked timer functions throws when called after FakeTime is restored",
assertThrows( assertThrows(
() => fakeSetTimeout(() => {}, 0), () => fakeSetTimeout(() => {}, 0),
TimeError, TimeError,
"Time is not faked", "Cannot set timeout: time is not faked",
);
assertThrows(
() => fakeClearTimeout(0),
TimeError,
"Cannot clear timeout: time is not faked",
); );
assertThrows(() => fakeClearTimeout(0), TimeError, "Time is not faked");
assertThrows( assertThrows(
() => fakeSetInterval(() => {}, 0), () => fakeSetInterval(() => {}, 0),
TimeError, TimeError,
"Time is not faked", "Cannot set interval: time is not faked",
);
assertThrows(
() => fakeClearInterval(0),
TimeError,
"Cannot clear interval: time is not faked",
); );
assertThrows(() => fakeClearInterval(0), TimeError, "Time is not faked");
}); });
Deno.test("Faked Date.now returns real time after FakeTime is restored", () => { Deno.test("Faked Date.now returns real time after FakeTime is restored", () => {
@ -700,19 +708,31 @@ Deno.test("FakeTime can be constructed with number, Date, or string", () => {
}); });
Deno.test("FakeTime throws when NaN is provided", () => { Deno.test("FakeTime throws when NaN is provided", () => {
assertThrows(() => new FakeTime(NaN), TypeError, "Invalid start time"); assertThrows(
() => new FakeTime(NaN),
TypeError,
"Cannot construct FakeTime: invalid start time NaN",
);
}); });
Deno.test("FakeTime.restore() throws when the time is already restored", () => { Deno.test("FakeTime.restore() throws when the time is already restored", () => {
const _time = new FakeTime(); const _time = new FakeTime();
FakeTime.restore(); FakeTime.restore();
assertThrows(() => FakeTime.restore(), TimeError, "Time is already restored"); assertThrows(
() => FakeTime.restore(),
TimeError,
"Cannot restore time: time is already restored",
);
}); });
Deno.test("time.restore() throws when the time is already restored", () => { Deno.test("time.restore() throws when the time is already restored", () => {
const time = new FakeTime(); const time = new FakeTime();
time.restore(); time.restore();
assertThrows(() => time.restore(), TimeError, "Time is already restored"); assertThrows(
() => time.restore(),
TimeError,
"Cannot restore time: time is already restored",
);
}); });
Deno.test("time.now = N throws when N < time.now", () => { Deno.test("time.now = N throws when N < time.now", () => {
@ -722,7 +742,7 @@ Deno.test("time.now = N throws when N < time.now", () => {
time.now = 999; time.now = 999;
}, },
RangeError, RangeError,
"Time cannot go backwards", "Cannot set current time in the past, time must be >= 1000: received 999",
); );
}); });