Skip to main content
Module

std/testing/mock_test.ts

Deno standard library
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.import { delay } from "../async/delay.ts";import { assertEquals, AssertionError, assertNotEquals, assertRejects, assertThrows,} from "./asserts.ts";import { assertSpyCall, assertSpyCallArg, assertSpyCallArgs, assertSpyCallAsync, assertSpyCalls, MockError, mockSession, mockSessionAsync, resolvesNext, restore, returnsArg, returnsArgs, returnsNext, returnsThis, Spy, spy, stub,} from "./mock.ts";import { Point, PointWithExtra, stringifyPoint } from "./_test_utils.ts";
Deno.test("spy default", () => { const func = spy(); assertSpyCalls(func, 0);
assertEquals(func(), undefined); assertSpyCall(func, 0, { self: undefined, args: [], returned: undefined, }); assertSpyCalls(func, 1);
assertEquals(func("x"), undefined); assertSpyCall(func, 1, { self: undefined, args: ["x"], returned: undefined, }); assertSpyCalls(func, 2);
assertEquals(func({ x: 3 }), undefined); assertSpyCall(func, 2, { self: undefined, args: [{ x: 3 }], returned: undefined, }); assertSpyCalls(func, 3);
assertEquals(func(3, 5, 7), undefined); assertSpyCall(func, 3, { self: undefined, args: [3, 5, 7], returned: undefined, }); assertSpyCalls(func, 4);
const point: Point = new Point(2, 3); assertEquals(func(Point, stringifyPoint, point), undefined); assertSpyCall(func, 4, { self: undefined, args: [Point, stringifyPoint, point], returned: undefined, }); assertSpyCalls(func, 5);
assertEquals(func.restored, false); assertThrows( () => func.restore(), MockError, "function cannot be restore", ); assertEquals(func.restored, false);});
Deno.test("spy function", () => { const func = spy((value) => value); assertSpyCalls(func, 0);
assertEquals(func(undefined), undefined); assertSpyCall(func, 0, { self: undefined, args: [undefined], returned: undefined, }); assertSpyCalls(func, 1);
assertEquals(func("x"), "x"); assertSpyCall(func, 1, { self: undefined, args: ["x"], returned: "x", }); assertSpyCalls(func, 2);
assertEquals(func({ x: 3 }), { x: 3 }); assertSpyCall(func, 2, { self: undefined, args: [{ x: 3 }], returned: { x: 3 }, }); assertSpyCalls(func, 3);
const point = new Point(2, 3); assertEquals(func(point), point); assertSpyCall(func, 3, { self: undefined, args: [point], returned: point, }); assertSpyCalls(func, 4);
assertEquals(func.restored, false); assertThrows( () => func.restore(), MockError, "function cannot be restored", ); assertEquals(func.restored, false);
// Check if the returned type is correct: const explicitTypesSpy = spy(point, "explicitTypes"); assertThrows(() => { assertSpyCall(explicitTypesSpy, 0, { // @ts-expect-error Test if passing incorrect argument types causes an error args: ["not a number", "string"], // @ts-expect-error Test if passing incorrect return type causes an error returned: "not a boolean", }); });
// Calling assertSpyCall with the correct types should not cause any type errors: point.explicitTypes(1, "hello"); assertSpyCall(explicitTypesSpy, 0, { args: [1, "hello"], returned: true, });});
Deno.test("spy instance method", () => { const point = new Point(2, 3); const func = spy(point, "action"); assertSpyCalls(func, 0);
assertEquals(func.call(point), undefined); assertSpyCall(func, 0, { self: point, args: [], returned: undefined, }); assertSpyCalls(func, 1);
assertEquals(point.action(), undefined); assertSpyCall(func, 1, { self: point, args: [] }); assertSpyCalls(func, 2);
assertEquals(func.call(point, "x"), "x"); assertSpyCall(func, 2, { self: point, args: ["x"], returned: "x", }); assertSpyCalls(func, 3);
assertEquals(point.action("x"), "x"); assertSpyCall(func, 3, { self: point, args: ["x"], returned: "x", }); assertSpyCalls(func, 4);
assertEquals(func.call(point, { x: 3 }), { x: 3 }); assertSpyCall(func, 4, { self: point, args: [{ x: 3 }], returned: { x: 3 }, }); assertSpyCalls(func, 5);
assertEquals(point.action({ x: 3 }), { x: 3 }); assertSpyCall(func, 5, { self: point, args: [{ x: 3 }], returned: { x: 3 }, }); assertSpyCalls(func, 6);
assertEquals(func.call(point, 3, 5, 7), 3); assertSpyCall(func, 6, { self: point, args: [3, 5, 7], returned: 3, }); assertSpyCalls(func, 7);
assertEquals(point.action(3, 5, 7), 3); assertSpyCall(func, 7, { self: point, args: [3, 5, 7], returned: 3, }); assertSpyCalls(func, 8);
assertEquals(func.call(point, Point, stringifyPoint, point), Point); assertSpyCall(func, 8, { self: point, args: [Point, stringifyPoint, point], returned: Point, }); assertSpyCalls(func, 9);
assertEquals(point.action(Point, stringifyPoint, point), Point); assertSpyCall(func, 9, { self: point, args: [Point, stringifyPoint, point], returned: Point, }); assertSpyCalls(func, 10);
assertNotEquals(func, Point.prototype.action); assertEquals(point.action, func);
assertEquals(func.restored, false); func.restore(); assertEquals(func.restored, true); assertEquals(point.action, Point.prototype.action); assertThrows( () => func.restore(), MockError, "instance method already restored", ); assertEquals(func.restored, true);});
Deno.test("spy instance method symbol", () => { const point = new Point(2, 3); const func = spy(point, Symbol.iterator); assertSpyCalls(func, 0);
const values: number[] = []; for (const value of point) { values.push(value); } assertSpyCall(func, 0, { self: point, args: [], }); assertSpyCalls(func, 1);
assertEquals(values, [2, 3]); assertEquals([...point], [2, 3]); assertSpyCall(func, 1, { self: point, args: [], }); assertSpyCalls(func, 2);
assertNotEquals(func, Point.prototype[Symbol.iterator]); assertEquals(point[Symbol.iterator], func);
assertEquals(func.restored, false); func.restore(); assertEquals(func.restored, true); assertEquals(point[Symbol.iterator], Point.prototype[Symbol.iterator]); assertThrows( () => func.restore(), MockError, "instance method already restored", ); assertEquals(func.restored, true);});
Deno.test("spy instance method property descriptor", () => { const point = new Point(2, 3); const actionDescriptor: PropertyDescriptor = { configurable: true, enumerable: false, writable: false, value: function (...args: unknown[]) { return args[1]; }, }; Object.defineProperty(point, "action", actionDescriptor); const action = spy(point, "action"); assertSpyCalls(action, 0);
assertEquals(action.call(point), undefined); assertSpyCall(action, 0, { self: point, args: [], returned: undefined, }); assertSpyCalls(action, 1);
assertEquals(point.action(), undefined); assertSpyCall(action, 1, { self: point, args: [], returned: undefined, }); assertSpyCalls(action, 2);
assertEquals(action.call(point, "x", "y"), "y"); assertSpyCall(action, 2, { self: point, args: ["x", "y"], returned: "y", }); assertSpyCalls(action, 3);
assertEquals(point.action("x", "y"), "y"); assertSpyCall(action, 3, { self: point, args: ["x", "y"], returned: "y", }); assertSpyCalls(action, 4);
assertNotEquals(action, actionDescriptor.value); assertEquals(point.action, action);
assertEquals(action.restored, false); action.restore(); assertEquals(action.restored, true); assertEquals(point.action, actionDescriptor.value); assertEquals( Object.getOwnPropertyDescriptor(point, "action"), actionDescriptor, ); assertThrows( () => action.restore(), MockError, "instance method already restored", ); assertEquals(action.restored, true);});
Deno.test("stub default", () => { const point = new Point(2, 3); const func = stub(point, "action");
assertSpyCalls(func, 0);
assertEquals(func.call(point), undefined); assertSpyCall(func, 0, { self: point, args: [], returned: undefined, }); assertSpyCalls(func, 1);
assertEquals(point.action(), undefined); assertSpyCall(func, 1, { self: point, args: [], returned: undefined, }); assertSpyCalls(func, 2);
assertEquals(func.original, Point.prototype.action); assertEquals(point.action, func);
assertEquals(func.restored, false); func.restore(); assertEquals(func.restored, true); assertEquals(point.action, Point.prototype.action); assertThrows( () => func.restore(), MockError, "instance method already restored", ); assertEquals(func.restored, true);});
Deno.test("stub function", () => { const point = new Point(2, 3); const returns = [1, "b", 2, "d"]; const func = stub(point, "action", () => returns.shift());
assertSpyCalls(func, 0);
assertEquals(func.call(point), 1); assertSpyCall(func, 0, { self: point, args: [], returned: 1, }); assertSpyCalls(func, 1);
assertEquals(point.action(), "b"); assertSpyCall(func, 1, { self: point, args: [], returned: "b", }); assertSpyCalls(func, 2);
assertEquals(func.original, Point.prototype.action); assertEquals(point.action, func);
assertEquals(func.restored, false); func.restore(); assertEquals(func.restored, true); assertEquals(point.action, Point.prototype.action); assertThrows( () => func.restore(), MockError, "instance method already restored", ); assertEquals(func.restored, true);});
Deno.test("stub non existent function", () => { const point = new Point(2, 3); const castPoint = point as PointWithExtra; let i = 0; const func = stub(castPoint, "nonExistent", () => { i++; return i; });
assertSpyCalls(func, 0);
assertEquals(func.call(castPoint), 1); assertSpyCall(func, 0, { self: castPoint, args: [], returned: 1, }); assertSpyCalls(func, 1);
assertEquals(castPoint.nonExistent(), 2); assertSpyCall(func, 1, { self: castPoint, args: [], returned: 2, }); assertSpyCalls(func, 2);
assertEquals(func.original, undefined); assertEquals(castPoint.nonExistent, func);
assertEquals(func.restored, false); func.restore(); assertEquals(func.restored, true); assertEquals(castPoint.nonExistent, undefined); assertThrows( () => func.restore(), MockError, "instance method already restored", ); assertEquals(func.restored, true);});
// This doesn't test any runtime code, only if the TypeScript types are correct.Deno.test("stub types", () => { // @ts-expect-error Stubbing with incorrect argument types should cause a type error stub(new Point(2, 3), "explicitTypes", (_x: string, _y: number) => true);
// @ts-expect-error Stubbing with an incorrect return type should cause a type error stub(new Point(2, 3), "explicitTypes", () => "string");
// Stubbing without argument types infers them from the real function stub(new Point(2, 3), "explicitTypes", (_x, _y) => { // `toExponential()` only exists on `number`, so this will error if _x is not a number _x.toExponential(); // `toLowerCase()` only exists on `string`, so this will error if _y is not a string _y.toLowerCase(); return true; });
// Stubbing with returnsNext() should not give any type errors stub(new Point(2, 3), "explicitTypes", returnsNext([true, false, true]));
// Stubbing without argument types should not cause any type errors: const point2 = new Point(2, 3); const explicitTypesFunc = stub(point2, "explicitTypes", () => true);
// Check if the returned type is correct: assertThrows(() => { assertSpyCall(explicitTypesFunc, 0, { // @ts-expect-error Test if passing incorrect argument types causes an error args: ["not a number", "string"], // @ts-expect-error Test if passing incorrect return type causes an error returned: "not a boolean", }); });
// Calling assertSpyCall with the correct types should not cause any type errors point2.explicitTypes(1, "hello"); assertSpyCall(explicitTypesFunc, 0, { args: [1, "hello"], returned: true, });});
Deno.test("mockSession and mockSessionAsync", async () => { const points = Array(6).fill(undefined).map(() => new Point(2, 3)); let actions: Spy<Point, unknown[], unknown>[] = []; function assertRestored(expected: boolean[]) { assertEquals(actions.map((action) => action.restored), expected); } await mockSessionAsync(async () => { actions.push(spy(points[0], "action")); assertRestored([false]); await mockSessionAsync(async () => { await Promise.resolve(); actions.push(spy(points[1], "action")); assertRestored([false, false]); mockSession(() => { actions.push(spy(points[2], "action")); actions.push(spy(points[3], "action")); assertRestored([false, false, false, false]); })(); actions.push(spy(points[4], "action")); assertRestored([false, false, true, true, false]); })(); actions.push(spy(points[5], "action")); assertRestored([false, true, true, true, true, false]); })(); assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true));
actions = []; mockSession(() => { actions = points.map((point) => spy(point, "action")); assertRestored(Array(6).fill(false)); })(); assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true));});
Deno.test("mockSession and restore current session", () => { const points = Array(6).fill(undefined).map(() => new Point(2, 3)); let actions: Spy<Point, unknown[], unknown>[]; function assertRestored(expected: boolean[]) { assertEquals(actions.map((action) => action.restored), expected); } try { actions = points.map((point) => spy(point, "action"));
assertRestored(Array(6).fill(false)); restore(); assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true));
actions = []; try { actions.push(spy(points[0], "action")); try { mockSession(); actions.push(spy(points[1], "action")); try { mockSession(); actions.push(spy(points[2], "action")); actions.push(spy(points[3], "action")); } finally { assertRestored([false, false, false, false]); restore(); } actions.push(spy(points[4], "action")); } finally { assertRestored([false, false, true, true, false]); restore(); } actions.push(spy(points[5], "action")); } finally { assertRestored([false, true, true, true, true, false]); restore(); } assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true));
actions = points.map((point) => spy(point, "action")); assertRestored(Array(6).fill(false)); restore(); assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true)); } finally { restore(); }});
Deno.test("mockSession and restore multiple sessions", () => { const points = Array(6).fill(undefined).map(() => new Point(2, 3)); let actions: Spy<Point, unknown[], unknown>[]; function assertRestored(expected: boolean[]) { assertEquals(actions.map((action) => action.restored), expected); } try { actions = []; try { actions.push(spy(points[0], "action")); const id = mockSession(); try { actions.push(spy(points[1], "action")); actions.push(spy(points[2], "action")); mockSession(); actions.push(spy(points[3], "action")); actions.push(spy(points[4], "action")); } finally { assertRestored([false, false, false, false, false]); restore(id); } actions.push(spy(points[5], "action")); } finally { assertRestored([false, true, true, true, true, false]); restore(); } assertRestored(Array(6).fill(true)); restore(); assertRestored(Array(6).fill(true)); } finally { restore(); }});
Deno.test("assertSpyCalls", () => { const spyFunc = spy();
assertSpyCalls(spyFunc, 0); assertThrows( () => assertSpyCalls(spyFunc, 1), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCalls(spyFunc, 1); assertThrows( () => assertSpyCalls(spyFunc, 0), AssertionError, "spy called more than expected", ); assertThrows( () => assertSpyCalls(spyFunc, 2), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyCall function", () => { const spyFunc = spy((multiplier?: number) => 5 * (multiplier ?? 1));
assertThrows( () => assertSpyCall(spyFunc, 0), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCall(spyFunc, 0); assertSpyCall(spyFunc, 0, { args: [], self: undefined, returned: 5, }); assertSpyCall(spyFunc, 0, { args: [], }); assertSpyCall(spyFunc, 0, { self: undefined, }); assertSpyCall(spyFunc, 0, { returned: 5, });
assertThrows( () => assertSpyCall(spyFunc, 0, { args: [1], self: {}, returned: 2, }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyFunc, 0, { args: [1], }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyFunc, 0, { self: {}, }), AssertionError, "spy not called as method on expected self", ); assertThrows( () => assertSpyCall(spyFunc, 0, { returned: 2, }), AssertionError, "spy call did not return expected value", ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { msgIncludes: "x" }, }), AssertionError, "spy call did not throw an error, a value was returned.", ); assertThrows( () => assertSpyCall(spyFunc, 1), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyCall method", () => { const point = new Point(2, 3); const spyMethod = spy(point, "action");
assertThrows( () => assertSpyCall(spyMethod, 0), AssertionError, "spy not called as much as expected", );
point.action(3, 7); assertSpyCall(spyMethod, 0); assertSpyCall(spyMethod, 0, { args: [3, 7], self: point, returned: 3, }); assertSpyCall(spyMethod, 0, { args: [3, 7], }); assertSpyCall(spyMethod, 0, { self: point, }); assertSpyCall(spyMethod, 0, { returned: 3, });
assertThrows( () => assertSpyCall(spyMethod, 0, { args: [7, 4], self: undefined, returned: 7, }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyMethod, 0, { args: [7, 3], }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyMethod, 0, { self: undefined, }), AssertionError, "spy not expected to be called as method on object", ); assertThrows( () => assertSpyCall(spyMethod, 0, { returned: 7, }), AssertionError, "spy call did not return expected value", ); assertThrows( () => assertSpyCall(spyMethod, 1), AssertionError, "spy not called as much as expected", );
spyMethod.call(point, 9); assertSpyCall(spyMethod, 1); assertSpyCall(spyMethod, 1, { args: [9], self: point, returned: 9, }); assertSpyCall(spyMethod, 1, { args: [9], }); assertSpyCall(spyMethod, 1, { self: point, }); assertSpyCall(spyMethod, 1, { returned: 9, });
assertThrows( () => assertSpyCall(spyMethod, 1, { args: [7, 4], self: point, returned: 7, }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyMethod, 1, { args: [7, 3], }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyMethod, 1, { self: new Point(1, 2), }), AssertionError, "spy not called as method on expected self", ); assertThrows( () => assertSpyCall(spyMethod, 1, { returned: 7, }), AssertionError, "spy call did not return expected value", ); assertThrows( () => assertSpyCall(spyMethod, 1, { error: { msgIncludes: "x" }, }), AssertionError, "spy call did not throw an error, a value was returned.", ); assertThrows( () => assertSpyCall(spyMethod, 2), AssertionError, "spy not called as much as expected", );});
class ExampleError extends Error {}class OtherError extends Error {}
Deno.test("assertSpyCall error", () => { const spyFunc = spy((_value?: number) => { throw new ExampleError("failed"); });
assertThrows(() => spyFunc(), ExampleError, "fail"); assertSpyCall(spyFunc, 0); assertSpyCall(spyFunc, 0, { args: [], self: undefined, error: { Class: ExampleError, msgIncludes: "fail", }, }); assertSpyCall(spyFunc, 0, { args: [], }); assertSpyCall(spyFunc, 0, { self: undefined, }); assertSpyCall(spyFunc, 0, { error: { Class: ExampleError, msgIncludes: "fail", }, }); assertSpyCall(spyFunc, 0, { error: { Class: Error, msgIncludes: "fail", }, });
assertThrows( () => assertSpyCall(spyFunc, 0, { args: [1], self: {}, error: { Class: OtherError, msgIncludes: "fail", }, }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyFunc, 0, { args: [1], }), AssertionError, "spy not called with expected args", ); assertThrows( () => assertSpyCall(spyFunc, 0, { self: {}, }), AssertionError, "spy not called as method on expected self", ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { Class: OtherError, msgIncludes: "fail", }, }), AssertionError, 'Expected error to be instance of "OtherError", but was "ExampleError".', ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { Class: OtherError, msgIncludes: "x", }, }), AssertionError, 'Expected error to be instance of "OtherError", but was "ExampleError".', ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { Class: ExampleError, msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { Class: Error, msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); assertThrows( () => assertSpyCall(spyFunc, 0, { error: { msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); assertThrows( () => assertSpyCall(spyFunc, 0, { returned: 7, }), AssertionError, "spy call did not return expected value, an error was thrown.", ); assertThrows( () => assertSpyCall(spyFunc, 1), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyCallAsync function", async () => { const spyFunc = spy((multiplier?: number) => Promise.resolve(5 * (multiplier ?? 1)) );
await assertRejects( () => assertSpyCallAsync(spyFunc, 0), AssertionError, "spy not called as much as expected", );
await spyFunc(); await assertSpyCallAsync(spyFunc, 0); await assertSpyCallAsync(spyFunc, 0, { args: [], self: undefined, returned: 5, }); await assertSpyCallAsync(spyFunc, 0, { args: [], self: undefined, returned: Promise.resolve(5), }); await assertSpyCallAsync(spyFunc, 0, { args: [], }); await assertSpyCallAsync(spyFunc, 0, { self: undefined, }); await assertSpyCallAsync(spyFunc, 0, { returned: Promise.resolve(5), });
await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { args: [1], self: {}, returned: 2, }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { args: [1], }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { self: {}, }), AssertionError, "spy not called as method on expected self", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { returned: 2, }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { returned: Promise.resolve(2), }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 1), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyCallAsync method", async () => { const point: Point = new Point(2, 3); const spyMethod = stub( point, "action", (x?: number, _y?: number) => Promise.resolve(x), );
await assertRejects( () => assertSpyCallAsync(spyMethod, 0), AssertionError, "spy not called as much as expected", );
await point.action(3, 7); await assertSpyCallAsync(spyMethod, 0); await assertSpyCallAsync(spyMethod, 0, { args: [3, 7], self: point, returned: 3, }); await assertSpyCallAsync(spyMethod, 0, { args: [3, 7], self: point, returned: Promise.resolve(3), }); await assertSpyCallAsync(spyMethod, 0, { args: [3, 7], }); await assertSpyCallAsync(spyMethod, 0, { self: point, }); await assertSpyCallAsync(spyMethod, 0, { returned: 3, }); await assertSpyCallAsync(spyMethod, 0, { returned: Promise.resolve(3), });
await assertRejects( () => assertSpyCallAsync(spyMethod, 0, { args: [7, 4], self: undefined, returned: 7, }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 0, { args: [7, 3], }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 0, { self: undefined, }), AssertionError, "spy not expected to be called as method on object", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 0, { returned: 7, }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 0, { returned: Promise.resolve(7), }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 1), AssertionError, "spy not called as much as expected", );
await spyMethod.call(point, 9); await assertSpyCallAsync(spyMethod, 1); await assertSpyCallAsync(spyMethod, 1, { args: [9], self: point, returned: 9, }); await assertSpyCallAsync(spyMethod, 1, { args: [9], self: point, returned: Promise.resolve(9), }); await assertSpyCallAsync(spyMethod, 1, { args: [9], }); await assertSpyCallAsync(spyMethod, 1, { self: point, }); await assertSpyCallAsync(spyMethod, 1, { returned: 9, }); await assertSpyCallAsync(spyMethod, 1, { returned: Promise.resolve(9), });
await assertRejects( () => assertSpyCallAsync(spyMethod, 1, { args: [7, 4], self: point, returned: 7, }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 1, { args: [7, 3], }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 1, { self: new Point(1, 2), }), AssertionError, "spy not called as method on expected self", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 1, { returned: 7, }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 1, { returned: Promise.resolve(7), }), AssertionError, "spy call did not resolve to expected value", ); await assertRejects( () => assertSpyCallAsync(spyMethod, 2), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyCallAync on sync value", async () => { const spyFunc = spy(() => 4 as unknown as Promise<number>);
spyFunc(); await assertRejects( () => assertSpyCallAsync(spyFunc, 0), AssertionError, "spy call did not return a promise, a value was returned.", );});
Deno.test("assertSpyCallAync on sync error", async () => { const spyFunc = spy(() => { throw new ExampleError("failed"); });
assertThrows(() => spyFunc(), ExampleError, "fail"); await assertRejects( () => assertSpyCallAsync(spyFunc, 0), AssertionError, "spy call did not return a promise, an error was thrown.", );});
Deno.test("assertSpyCallAync error", async () => { const spyFunc = spy((..._args: number[]): Promise<number> => Promise.reject(new ExampleError("failed")) );
await assertRejects(() => spyFunc(), ExampleError, "fail"); await assertSpyCallAsync(spyFunc, 0); await assertSpyCallAsync(spyFunc, 0, { args: [], self: undefined, error: { Class: ExampleError, msgIncludes: "fail", }, }); await assertSpyCallAsync(spyFunc, 0, { args: [], }); await assertSpyCallAsync(spyFunc, 0, { self: undefined, }); await assertSpyCallAsync(spyFunc, 0, { error: { Class: ExampleError, msgIncludes: "fail", }, }); await assertSpyCallAsync(spyFunc, 0, { error: { Class: Error, msgIncludes: "fail", }, });
await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { args: [1], self: {}, error: { Class: OtherError, msgIncludes: "fail", }, }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { args: [1], }), AssertionError, "spy not called with expected args", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { self: {}, }), AssertionError, "spy not called as method on expected self", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { error: { Class: OtherError, msgIncludes: "fail", }, }), AssertionError, 'Expected error to be instance of "OtherError"', ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { error: { Class: OtherError, msgIncludes: "x", }, }), AssertionError, 'Expected error to be instance of "OtherError"', ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { error: { Class: ExampleError, msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { error: { Class: Error, msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { error: { msgIncludes: "x", }, }), AssertionError, 'Expected error message to include "x", but got "failed".', ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { returned: Promise.resolve(7), }), AssertionError, "spy call returned promise was rejected", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 0, { returned: Promise.resolve(7), error: { msgIncludes: "x" }, }), TypeError, "do not expect error and return, only one should be expected", ); await assertRejects( () => assertSpyCallAsync(spyFunc, 1), AssertionError, "spy not called as much as expected", );});
Deno.test("assertSpyArg", () => { const spyFunc = spy();
assertThrows( () => assertSpyCallArg(spyFunc, 0, 0, undefined), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCallArg(spyFunc, 0, 0, undefined); assertSpyCallArg(spyFunc, 0, 1, undefined); assertThrows( () => assertSpyCallArg(spyFunc, 0, 0, 2), AssertionError, "Values are not equal:", );
spyFunc(7, 9); assertSpyCallArg(spyFunc, 1, 0, 7); assertSpyCallArg(spyFunc, 1, 1, 9); assertSpyCallArg(spyFunc, 1, 2, undefined); assertThrows( () => assertSpyCallArg(spyFunc, 0, 0, 9), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArg(spyFunc, 0, 1, 7), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArg(spyFunc, 0, 2, 7), AssertionError, "Values are not equal:", );});
Deno.test("assertSpyArgs without range", () => { const spyFunc = spy();
assertThrows( () => assertSpyCallArgs(spyFunc, 0, []), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCallArgs(spyFunc, 0, []); assertThrows( () => assertSpyCallArgs(spyFunc, 0, [undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 0, [2]), AssertionError, "Values are not equal:", );
spyFunc(7, 9); assertSpyCallArgs(spyFunc, 1, [7, 9]); assertThrows( () => assertSpyCallArgs(spyFunc, 1, [7, 9, undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 1, [9, 7]), AssertionError, "Values are not equal:", );});
Deno.test("assertSpyArgs with start only", () => { const spyFunc = spy();
assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, []), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCallArgs(spyFunc, 0, 1, []); assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, [undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, [2]), AssertionError, "Values are not equal:", );
spyFunc(7, 9, 8); assertSpyCallArgs(spyFunc, 1, 1, [9, 8]); assertThrows( () => assertSpyCallArgs(spyFunc, 1, 1, [9, 8, undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 1, 1, [9, 7]), AssertionError, "Values are not equal:", );});
Deno.test("assertSpyArgs with range", () => { const spyFunc = spy();
assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, 3, []), AssertionError, "spy not called as much as expected", );
spyFunc(); assertSpyCallArgs(spyFunc, 0, 1, 3, []); assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, 3, [undefined, undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 0, 1, 3, [2, 4]), AssertionError, "Values are not equal:", );
spyFunc(7, 9, 8, 5, 6); assertSpyCallArgs(spyFunc, 1, 1, 3, [9, 8]); assertThrows( () => assertSpyCallArgs(spyFunc, 1, 1, 3, [9, 8, undefined]), AssertionError, "Values are not equal:", ); assertThrows( () => assertSpyCallArgs(spyFunc, 1, 1, 3, [9, 7]), AssertionError, "Values are not equal:", );});
Deno.test("returnsThis", () => { const callback = returnsThis(); const obj = { callback, x: 1, y: 2 }; const obj2 = { x: 2, y: 3 }; assertEquals(callback(), undefined); assertEquals(obj.callback(), obj); assertEquals(callback.apply(obj2, []), obj2);});
Deno.test("returnsArg", () => { let callback = returnsArg(0); assertEquals(callback(), undefined); assertEquals(callback("a"), "a"); assertEquals(callback("b", "c"), "b"); callback = returnsArg(1); assertEquals(callback(), undefined); assertEquals(callback("a"), undefined); assertEquals(callback("b", "c"), "c"); assertEquals(callback("d", "e", "f"), "e");});
Deno.test("returnsArgs", () => { let callback = returnsArgs(); assertEquals(callback(), []); assertEquals(callback("a"), ["a"]); assertEquals(callback("b", "c"), ["b", "c"]); callback = returnsArgs(1); assertEquals(callback(), []); assertEquals(callback("a"), []); assertEquals(callback("b", "c"), ["c"]); assertEquals(callback("d", "e", "f"), ["e", "f"]); callback = returnsArgs(1, 3); assertEquals(callback("a"), []); assertEquals(callback("b", "c"), ["c"]); assertEquals(callback("d", "e", "f"), ["e", "f"]); assertEquals(callback("d", "e", "f", "g"), ["e", "f"]);});
Deno.test("returnsNext with array", () => { let results = [1, 2, new Error("oops"), 3]; let callback = returnsNext(results); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", ); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", );
results = []; callback = returnsNext(results); results.push(1, 2, new Error("oops"), 3); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); results.push(4); assertEquals(callback(), 4); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", ); results.push(5); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", );});
Deno.test("returnsNext with iterator", () => { let results = [1, 2, new Error("oops"), 3]; let callback = returnsNext(results.values()); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", ); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", );
results = []; callback = returnsNext(results.values()); results.push(1, 2, new Error("oops"), 3); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); results.push(4); assertEquals(callback(), 4); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", ); results.push(5); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", );});
Deno.test("returnsNext with generator", () => { let results = [1, 2, new Error("oops"), 3]; const generator = function* () { yield* results; }; let callback = returnsNext(generator()); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", ); assertThrows( () => callback(), MockError, "not expected to be called more than 4 times", );
results = []; callback = returnsNext(generator()); results.push(1, 2, new Error("oops"), 3); assertEquals(callback(), 1); assertEquals(callback(), 2); assertThrows(() => callback(), Error, "oops"); assertEquals(callback(), 3); results.push(4); assertEquals(callback(), 4); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", ); results.push(5); assertThrows( () => callback(), MockError, "not expected to be called more than 5 times", );});
Deno.test("resolvesNext with array", async () => { let results = [ 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ]; let callback = resolvesNext(results); const value = callback(); assertEquals(Promise.resolve(value), value); assertEquals(await value, 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", ); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", );
results = []; callback = resolvesNext(results); results.push( 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ); assertEquals(await callback(), 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); results.push(4); assertEquals(await callback(), 4); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", ); results.push(5); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", );});
Deno.test("resolvesNext with iterator", async () => { let results = [ 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ]; let callback = resolvesNext(results.values()); const value = callback(); assertEquals(Promise.resolve(value), value); assertEquals(await value, 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", ); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", );
results = []; callback = resolvesNext(results.values()); results.push( 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ); assertEquals(await callback(), 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); results.push(4); assertEquals(await callback(), 4); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", ); results.push(5); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", );});
Deno.test("resolvesNext with async generator", async () => { let results = [ 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ]; const asyncGenerator = async function* () { await delay(0); yield* results; }; let callback = resolvesNext(asyncGenerator()); const value = callback(); assertEquals(Promise.resolve(value), value); assertEquals(await value, 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", ); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 5 times", );
results = []; callback = resolvesNext(asyncGenerator()); results.push( 1, new Error("oops"), Promise.resolve(2), Promise.resolve(new Error("oops")), 3, ); assertEquals(await callback(), 1); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 2); await assertRejects(() => callback(), Error, "oops"); assertEquals(await callback(), 3); results.push(4); assertEquals(await callback(), 4); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", ); results.push(5); await assertRejects( async () => await callback(), MockError, "not expected to be called more than 6 times", );});