mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1500 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			1500 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) Meta Platforms, Inc. and affiliates.
 | |
|  *
 | |
|  * This source code is licensed under the MIT license found in the
 | |
|  * LICENSE file in the root directory of this source tree.
 | |
|  */
 | |
| 
 | |
| import { test, expect } from './fixtures';
 | |
| import { expect as expectUnderTest, mock } from '../../packages/playwright/bundles/expect/src/expectBundleImpl';
 | |
| import Immutable from 'immutable';
 | |
| 
 | |
| const expectUnderTestAsAny = expectUnderTest as any;
 | |
| 
 | |
| expectUnderTest.extend({
 | |
|   optionalFn(fn?: unknown) {
 | |
|     const pass = fn === undefined || typeof fn === 'function';
 | |
|     return { message: () => 'expect either a function or undefined', pass };
 | |
|   },
 | |
| });
 | |
| 
 | |
| 
 | |
| // Given a Jest mock function, return a minimal mock of a spy.
 | |
| const createSpy = (fn: mock.Mock) => {
 | |
|   const spy = function() { };
 | |
| 
 | |
|   spy.calls = {
 | |
|     all() {
 | |
|       return fn.mock.calls.map(args => ({ args }));
 | |
|     },
 | |
|     count() {
 | |
|       return fn.mock.calls.length;
 | |
|     },
 | |
|   };
 | |
| 
 | |
|   return spy;
 | |
| };
 | |
| 
 | |
| for (const called of ['toBeCalled', 'toHaveBeenCalled']) {
 | |
|   test.describe(called, () => {
 | |
|     test('works only on spies or mock.fn', () => {
 | |
|       const fn = function fn() { };
 | |
| 
 | |
|       expect(() => expectUnderTest(fn)[called]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('passes when called', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('arg0', 'arg1', 'arg2');
 | |
|       expectUnderTest(createSpy(fn))[called]();
 | |
|       expectUnderTest(fn)[called]();
 | |
|       expect(() => expectUnderTest(fn).not[called]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes when called', () => {
 | |
|       const fn = mock.fn();
 | |
|       const spy = createSpy(fn);
 | |
| 
 | |
|       expectUnderTest(spy).not[called]();
 | |
|       expectUnderTest(fn).not[called]();
 | |
|       expect(() => expectUnderTest(spy)[called]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('fails with any argument passed', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       fn();
 | |
|       expect(() => expectUnderTest(fn)[called](555)).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not fails with any argument passed', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[called](555),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn().mockName('named-mock');
 | |
| 
 | |
|       fn();
 | |
|       expectUnderTest(fn)[called]();
 | |
|       expect(() => expectUnderTest(fn).not[called]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| for (const calledTimes of ['toBeCalledTimes', 'toHaveBeenCalledTimes']) {
 | |
|   test.describe(calledTimes, () => {
 | |
|     test('.not works only on spies or mock.fn', () => {
 | |
|       const fn = function fn() { };
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[calledTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('only accepts a number argument', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
|       expectUnderTest(fn)[calledTimes](1);
 | |
| 
 | |
|       [{}, [], true, 'a', new Map(), () => { }].forEach(value => {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledTimes](value),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('.not only accepts a number argument', () => {
 | |
|       const fn = mock.fn();
 | |
|       expectUnderTest(fn).not[calledTimes](1);
 | |
| 
 | |
|       [{}, [], true, 'a', new Map(), () => { }].forEach(value => {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledTimes](value),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('passes if function called equal to expected times', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       const spy = createSpy(fn);
 | |
|       expectUnderTest(spy)[calledTimes](2);
 | |
|       expectUnderTest(fn)[calledTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(spy).not[calledTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes if function called more than expected times', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       const spy = createSpy(fn);
 | |
|       expectUnderTest(spy)[calledTimes](3);
 | |
|       expectUnderTest(spy).not[calledTimes](2);
 | |
| 
 | |
|       expectUnderTest(fn)[calledTimes](3);
 | |
|       expectUnderTest(fn).not[calledTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[calledTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes if function called less than expected times', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
| 
 | |
|       const spy = createSpy(fn);
 | |
|       expectUnderTest(spy)[calledTimes](1);
 | |
|       expectUnderTest(spy).not[calledTimes](2);
 | |
| 
 | |
|       expectUnderTest(fn)[calledTimes](1);
 | |
|       expectUnderTest(fn).not[calledTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[calledTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn().mockName('named-mock');
 | |
|       fn();
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[calledTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| for (const calledWith of [
 | |
|   'lastCalledWith',
 | |
|   'toHaveBeenLastCalledWith',
 | |
|   'nthCalledWith',
 | |
|   'toHaveBeenNthCalledWith',
 | |
|   'toBeCalledWith',
 | |
|   'toHaveBeenCalledWith',
 | |
| ]) {
 | |
|   test.describe(calledWith, () => {
 | |
|     function isToHaveNth(
 | |
|       calledWith: string,
 | |
|     ): calledWith is 'nthCalledWith' | 'toHaveBeenNthCalledWith' {
 | |
|       return (
 | |
|         calledWith === 'nthCalledWith' || calledWith === 'toHaveBeenNthCalledWith'
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     test('works only on spies or mock.fn', () => {
 | |
|       const fn = function fn() { };
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expect(() => expectUnderTest(fn)[calledWith]()).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works when not called', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith](1, 'foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with no arguments', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn))[calledWith](1);
 | |
|         expectUnderTest(fn)[calledWith](1);
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn))[calledWith]();
 | |
|         expectUnderTest(fn)[calledWith]();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test("works with arguments that don't match", () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', 'bar1');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith](1, 'foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test("works with arguments that don't match in number of arguments", () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', 'bar', 'plop');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](1, 'foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith](1, 'foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith]('foo', 'bar');
 | |
|         expectUnderTest(fn).not[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test("works with arguments that don't match with matchers", () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', 'bar');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](
 | |
|             1,
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(Number),
 | |
|         );
 | |
|         expectUnderTest(fn).not[calledWith](
 | |
|             1,
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(Number),
 | |
|         );
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](
 | |
|               1,
 | |
|               expectUnderTest.any(String),
 | |
|               expectUnderTest.any(Number),
 | |
|           ),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(Number),
 | |
|         );
 | |
|         expectUnderTest(fn).not[calledWith](
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(Number),
 | |
|         );
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](
 | |
|               expectUnderTest.any(String),
 | |
|               expectUnderTest.any(Number),
 | |
|           ),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test("works with arguments that don't match with matchers even when argument is undefined", () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', undefined);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith](
 | |
|             1,
 | |
|             'foo',
 | |
|             expectUnderTest.any(String),
 | |
|         );
 | |
|         expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTest.any(String));
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTest.any(String)),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn)).not[calledWith]('foo', expectUnderTest.any(String));
 | |
|         expectUnderTest(fn).not[calledWith]('foo', expectUnderTest.any(String));
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', expectUnderTest.any(String)),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test("works with arguments that don't match in size even if one is an optional matcher", () => {
 | |
|       // issue 12463
 | |
|       const fn = mock.fn();
 | |
|       fn('foo');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn());
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn).not[calledWith]('foo', expectUnderTestAsAny.optionalFn());
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', expectUnderTestAsAny.optionalFn()),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with arguments that match', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', 'bar');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn))[calledWith](1, 'foo', 'bar');
 | |
|         expectUnderTest(fn)[calledWith](1, 'foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn))[calledWith]('foo', 'bar');
 | |
|         expectUnderTest(fn)[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with arguments that match with matchers', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', 'bar');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(createSpy(fn))[calledWith](
 | |
|             1,
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(String),
 | |
|         );
 | |
|         expectUnderTest(fn)[calledWith](
 | |
|             1,
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(String),
 | |
|         );
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](
 | |
|               1,
 | |
|               expectUnderTest.any(String),
 | |
|               expectUnderTest.any(String),
 | |
|           ),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(createSpy(fn))[calledWith](
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(String),
 | |
|         );
 | |
|         expectUnderTest(fn)[calledWith](
 | |
|             expectUnderTest.any(String),
 | |
|             expectUnderTest.any(String),
 | |
|         );
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](
 | |
|               expectUnderTest.any(String),
 | |
|               expectUnderTest.any(String),
 | |
|           ),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with trailing undefined arguments', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', undefined);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, 'foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with trailing undefined arguments if requested by the match query', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', undefined);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, 'foo', undefined);
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, 'foo', undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith]('foo', undefined);
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith]('foo', undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with trailing undefined arguments when explicitly requested as optional by matcher', () => {
 | |
|       // issue 12463
 | |
|       const fn = mock.fn();
 | |
|       fn('foo', undefined);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn());
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, 'foo', expectUnderTestAsAny.optionalFn()),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith]('foo', expectUnderTestAsAny.optionalFn());
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith]('foo', expectUnderTestAsAny.optionalFn()),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Map', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       const m1 = new Map([
 | |
|         [1, 2],
 | |
|         [2, 1],
 | |
|       ]);
 | |
|       const m2 = new Map([
 | |
|         [1, 2],
 | |
|         [2, 1],
 | |
|       ]);
 | |
|       const m3 = new Map([
 | |
|         ['a', 'b'],
 | |
|         ['b', 'a'],
 | |
|       ]);
 | |
| 
 | |
|       fn(m1);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, m2);
 | |
|         expectUnderTest(fn).not[calledWith](1, m3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, m2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, m3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith](m2);
 | |
|         expectUnderTest(fn).not[calledWith](m3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](m2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](m3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Set', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       const s1 = new Set([1, 2]);
 | |
|       const s2 = new Set([1, 2]);
 | |
|       const s3 = new Set([3, 4]);
 | |
| 
 | |
|       fn(s1);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, s2);
 | |
|         expectUnderTest(fn).not[calledWith](1, s3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, s2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](1, s3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith](s2);
 | |
|         expectUnderTest(fn).not[calledWith](s3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](s2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith](s3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Immutable.js objects', () => {
 | |
|       const fn = mock.fn();
 | |
|       const directlyCreated = Immutable.Map([['a', { b: 'c' }]]);
 | |
|       const indirectlyCreated = Immutable.Map().set('a', { b: 'c' });
 | |
|       fn(directlyCreated, indirectlyCreated);
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, indirectlyCreated, directlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, indirectlyCreated, directlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith](indirectlyCreated, directlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](indirectlyCreated, directlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     if (!isToHaveNth(calledWith)) {
 | |
|       test('works with many arguments', () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo1', 'bar');
 | |
|         fn('foo', 'bar1');
 | |
|         fn('foo', 'bar');
 | |
| 
 | |
|         expectUnderTest(fn)[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
| 
 | |
|       test("works with many arguments that don't match", () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo', 'bar1');
 | |
|         fn('foo', 'bar2');
 | |
|         fn('foo', 'bar3');
 | |
| 
 | |
|         expectUnderTest(fn).not[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     if (isToHaveNth(calledWith)) {
 | |
|       test('works with three calls', () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo1', 'bar');
 | |
|         fn('foo', 'bar1');
 | |
|         fn('foo', 'bar');
 | |
| 
 | |
|         expectUnderTest(fn)[calledWith](1, 'foo1', 'bar');
 | |
|         expectUnderTest(fn)[calledWith](2, 'foo', 'bar1');
 | |
|         expectUnderTest(fn)[calledWith](3, 'foo', 'bar');
 | |
| 
 | |
|         expect(() => {
 | |
|           expectUnderTest(fn).not[calledWith](1, 'foo1', 'bar');
 | |
|         }).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
| 
 | |
|       test('positive throw matcher error for n that is not positive integer', async () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo1', 'bar');
 | |
| 
 | |
|         expect(() => {
 | |
|           expectUnderTest(fn)[calledWith](0, 'foo1', 'bar');
 | |
|         }).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
| 
 | |
|       test('positive throw matcher error for n that is not integer', async () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo1', 'bar');
 | |
| 
 | |
|         expect(() => {
 | |
|           expectUnderTest(fn)[calledWith](0.1, 'foo1', 'bar');
 | |
|         }).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
| 
 | |
|       test('negative throw matcher error for n that is not integer', async () => {
 | |
|         const fn = mock.fn();
 | |
|         fn('foo1', 'bar');
 | |
| 
 | |
|         expect(() => {
 | |
|           expectUnderTest(fn).not[calledWith](Infinity, 'foo1', 'bar');
 | |
|         }).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn().mockName('named-mock');
 | |
|       fn('foo', 'bar');
 | |
| 
 | |
|       if (isToHaveNth(calledWith)) {
 | |
|         expectUnderTest(fn)[calledWith](1, 'foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith](1, 'foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[calledWith]('foo', 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[calledWith]('foo', 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| for (const returned of ['toReturn', 'toHaveReturned']) {
 | |
|   test.describe(returned, () => {
 | |
|     test('.not works only on mock.fn', () => {
 | |
|       const fn = function fn() { };
 | |
| 
 | |
|       expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('throw matcher error if received is spy', () => {
 | |
|       const spy = createSpy(mock.fn());
 | |
| 
 | |
|       expect(() => expectUnderTest(spy)[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('passes when returned', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       fn();
 | |
|       expectUnderTest(fn)[returned]();
 | |
|       expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('passes when undefined is returned', () => {
 | |
|       const fn = mock.fn(() => undefined);
 | |
|       fn();
 | |
|       expectUnderTest(fn)[returned]();
 | |
|       expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('passes when at least one call does not throw', () => {
 | |
|       const fn = mock.fn((causeError: boolean) => {
 | |
|         if (causeError)
 | |
|           throw new Error('Error!');
 | |
| 
 | |
| 
 | |
|         return 42;
 | |
|       });
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       try {
 | |
|         fn(true);
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       expectUnderTest(fn)[returned]();
 | |
|       expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes when not returned', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       expectUnderTest(fn).not[returned]();
 | |
|       expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes when all calls throw', () => {
 | |
|       const fn = mock.fn(() => {
 | |
|         throw new Error('Error!');
 | |
|       });
 | |
| 
 | |
|       try {
 | |
|         fn();
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       try {
 | |
|         fn();
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       expectUnderTest(fn).not[returned]();
 | |
|       expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes when a call throws undefined', () => {
 | |
|       const fn = mock.fn(() => {
 | |
| 
 | |
|         throw undefined;
 | |
|       });
 | |
| 
 | |
|       try {
 | |
|         fn();
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       expectUnderTest(fn).not[returned]();
 | |
|       expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('fails with any argument passed', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       fn();
 | |
|       expect(() => expectUnderTest(fn)[returned](555)).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not fails with any argument passed', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[returned](555),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn(() => 42).mockName('named-mock');
 | |
|       fn();
 | |
|       expectUnderTest(fn)[returned]();
 | |
|       expect(() => expectUnderTest(fn).not[returned]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('incomplete recursive calls are handled properly', () => {
 | |
|       // sums up all integers from 0 -> value, using recursion
 | |
|       const fn: mock.Mock<(value: number) => number> = mock.fn(value => {
 | |
|         if (value === 0) {
 | |
|           // Before returning from the base case of recursion, none of the
 | |
|           // calls have returned yet.
 | |
|           expectUnderTest(fn).not[returned]();
 | |
|           expect(() => expectUnderTest(fn)[returned]()).toThrowErrorMatchingSnapshot();
 | |
|           return 0;
 | |
|         } else {
 | |
|           return value + fn(value - 1);
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       fn(3);
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| for (const returnedTimes of ['toReturnTimes', 'toHaveReturnedTimes']) {
 | |
|   test.describe(returnedTimes, () => {
 | |
|     test('throw matcher error if received is spy', () => {
 | |
|       const spy = createSpy(mock.fn());
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(spy).not[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('only accepts a number argument', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       fn();
 | |
|       expectUnderTest(fn)[returnedTimes](1);
 | |
| 
 | |
|       [{}, [], true, 'a', new Map(), () => { }].forEach(value => {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedTimes](value),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('.not only accepts a number argument', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       expectUnderTest(fn).not[returnedTimes](2);
 | |
| 
 | |
|       [{}, [], true, 'a', new Map(), () => { }].forEach(value => {
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedTimes](value),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     test('passes if function returned equal to expected times', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('calls that return undefined are counted as returns', () => {
 | |
|       const fn = mock.fn(() => undefined);
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes if function returned more than expected times', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       fn();
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](3);
 | |
|       expectUnderTest(fn).not[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('.not passes if function called less than expected times', () => {
 | |
|       const fn = mock.fn(() => 42);
 | |
|       fn();
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](1);
 | |
|       expectUnderTest(fn).not[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('calls that throw are not counted', () => {
 | |
|       const fn = mock.fn((causeError: boolean) => {
 | |
|         if (causeError)
 | |
|           throw new Error('Error!');
 | |
| 
 | |
| 
 | |
|         return 42;
 | |
|       });
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       try {
 | |
|         fn(true);
 | |
|       } catch {
 | |
|       // ignore error
 | |
|       }
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       expectUnderTest(fn).not[returnedTimes](3);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[returnedTimes](3),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('calls that throw undefined are not counted', () => {
 | |
|       const fn = mock.fn((causeError: boolean) => {
 | |
|         if (causeError)
 | |
| 
 | |
|           throw undefined;
 | |
| 
 | |
| 
 | |
|         return 42;
 | |
|       });
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       try {
 | |
|         fn(true);
 | |
|       } catch {
 | |
|       // ignore error
 | |
|       }
 | |
| 
 | |
|       fn(false);
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn).not[returnedTimes](2),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn(() => 42).mockName('named-mock');
 | |
|       fn();
 | |
|       fn();
 | |
| 
 | |
|       expectUnderTest(fn)[returnedTimes](2);
 | |
| 
 | |
|       expect(() =>
 | |
|         expectUnderTest(fn)[returnedTimes](1),
 | |
|       ).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('incomplete recursive calls are handled properly', () => {
 | |
|     // sums up all integers from 0 -> value, using recursion
 | |
|       const fn: mock.Mock<(value: number) => number> = mock.fn(value => {
 | |
|         if (value === 0) {
 | |
|           return 0;
 | |
|         } else {
 | |
|           const recursiveResult = fn(value - 1);
 | |
| 
 | |
|           if (value === 2) {
 | |
|           // Only 2 of the recursive calls have returned at this point
 | |
|             expectUnderTest(fn)[returnedTimes](2);
 | |
|             expect(() =>
 | |
|               expectUnderTest(fn).not[returnedTimes](2),
 | |
|             ).toThrowErrorMatchingSnapshot();
 | |
|           }
 | |
| 
 | |
|           return value + recursiveResult;
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       fn(3);
 | |
|     });
 | |
|   });
 | |
| }
 | |
| 
 | |
| for (const returnedWith of [
 | |
|   'lastReturnedWith',
 | |
|   'toHaveLastReturnedWith',
 | |
|   'nthReturnedWith',
 | |
|   'toHaveNthReturnedWith',
 | |
|   'toReturnWith',
 | |
|   'toHaveReturnedWith',
 | |
| ]) {
 | |
|   test.describe(returnedWith, () => {
 | |
|     function isToHaveNth(
 | |
|       returnedWith: string,
 | |
|     ): returnedWith is 'nthReturnedWith' | 'toHaveNthReturnedWith' {
 | |
|       return (
 | |
|         returnedWith === 'nthReturnedWith' ||
 | |
|         returnedWith === 'toHaveNthReturnedWith'
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     function isToHaveLast(
 | |
|       returnedWith: string,
 | |
|     ): returnedWith is 'lastReturnedWith' | 'toHaveLastReturnedWith' {
 | |
|       return (
 | |
|         returnedWith === 'lastReturnedWith' ||
 | |
|         returnedWith === 'toHaveLastReturnedWith'
 | |
|       );
 | |
|     }
 | |
|     test('works only on spies or mock.fn', () => {
 | |
|       const fn = function fn() { };
 | |
| 
 | |
|       expect(() => expectUnderTest(fn)[returnedWith]()).toThrowErrorMatchingSnapshot();
 | |
|     });
 | |
| 
 | |
|     test('works when not called', () => {
 | |
|       const fn = mock.fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn).not[returnedWith](1, 'foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, 'foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn).not[returnedWith]('foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith]('foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with no arguments', () => {
 | |
|       const fn = mock.fn();
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith))
 | |
|         expectUnderTest(fn)[returnedWith](1);
 | |
|       else
 | |
|         expectUnderTest(fn)[returnedWith]();
 | |
| 
 | |
|     });
 | |
| 
 | |
|     test('works with argument that does not match', () => {
 | |
|       const fn = mock.fn(() => 'foo');
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn).not[returnedWith](1, 'bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, 'bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn).not[returnedWith]('bar');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith]('bar'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with argument that does match', () => {
 | |
|       const fn = mock.fn(() => 'foo');
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, 'foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, 'foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith]('foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith]('foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with undefined', () => {
 | |
|       const fn = mock.fn(() => undefined);
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith](undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Map', () => {
 | |
|       const m1 = new Map([
 | |
|         [1, 2],
 | |
|         [2, 1],
 | |
|       ]);
 | |
|       const m2 = new Map([
 | |
|         [1, 2],
 | |
|         [2, 1],
 | |
|       ]);
 | |
|       const m3 = new Map([
 | |
|         ['a', 'b'],
 | |
|         ['b', 'a'],
 | |
|       ]);
 | |
| 
 | |
|       const fn = mock.fn(() => m1);
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, m2);
 | |
|         expectUnderTest(fn).not[returnedWith](1, m3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, m2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, m3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith](m2);
 | |
|         expectUnderTest(fn).not[returnedWith](m3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](m2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](m3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Set', () => {
 | |
|       const s1 = new Set([1, 2]);
 | |
|       const s2 = new Set([1, 2]);
 | |
|       const s3 = new Set([3, 4]);
 | |
| 
 | |
|       const fn = mock.fn(() => s1);
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, s2);
 | |
|         expectUnderTest(fn).not[returnedWith](1, s3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, s2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, s3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith](s2);
 | |
|         expectUnderTest(fn).not[returnedWith](s3);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](s2),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](s3),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Immutable.js objects directly created', () => {
 | |
|       const directlyCreated = Immutable.Map([['a', { b: 'c' }]]);
 | |
|       const fn = mock.fn(() => directlyCreated);
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, directlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, directlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith](directlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](directlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('works with Immutable.js objects indirectly created', () => {
 | |
|       const indirectlyCreated = Immutable.Map().set('a', { b: 'c' });
 | |
|       const fn = mock.fn(() => indirectlyCreated);
 | |
|       fn();
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn)[returnedWith](1, indirectlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](1, indirectlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn)[returnedWith](indirectlyCreated);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn).not[returnedWith](indirectlyCreated),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('a call that throws is not considered to have returned', () => {
 | |
|       const fn = mock.fn(() => {
 | |
|         throw new Error('Error!');
 | |
|       });
 | |
| 
 | |
|       try {
 | |
|         fn();
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         // It doesn't matter what return value is tested if the call threw
 | |
|         expectUnderTest(fn).not[returnedWith](1, 'foo');
 | |
|         expectUnderTest(fn).not[returnedWith](1, null);
 | |
|         expectUnderTest(fn).not[returnedWith](1, undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         // It doesn't matter what return value is tested if the call threw
 | |
|         expectUnderTest(fn).not[returnedWith]('foo');
 | |
|         expectUnderTest(fn).not[returnedWith](null);
 | |
|         expectUnderTest(fn).not[returnedWith](undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     test('a call that throws undefined is not considered to have returned', () => {
 | |
|       const fn = mock.fn(() => {
 | |
| 
 | |
|         throw undefined;
 | |
|       });
 | |
| 
 | |
|       try {
 | |
|         fn();
 | |
|       } catch {
 | |
|         // ignore error
 | |
|       }
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         // It doesn't matter what return value is tested if the call threw
 | |
|         expectUnderTest(fn).not[returnedWith](1, 'foo');
 | |
|         expectUnderTest(fn).not[returnedWith](1, null);
 | |
|         expectUnderTest(fn).not[returnedWith](1, undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         // It doesn't matter what return value is tested if the call threw
 | |
|         expectUnderTest(fn).not[returnedWith]('foo');
 | |
|         expectUnderTest(fn).not[returnedWith](null);
 | |
|         expectUnderTest(fn).not[returnedWith](undefined);
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](undefined),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     if (!isToHaveNth(returnedWith)) {
 | |
|       test.describe('returnedWith', () => {
 | |
|         test('works with more calls than the limit', () => {
 | |
|           const fn = mock.fn<() => string>();
 | |
|           fn.mockReturnValueOnce('foo1');
 | |
|           fn.mockReturnValueOnce('foo2');
 | |
|           fn.mockReturnValueOnce('foo3');
 | |
|           fn.mockReturnValueOnce('foo4');
 | |
|           fn.mockReturnValueOnce('foo5');
 | |
|           fn.mockReturnValueOnce('foo6');
 | |
| 
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
| 
 | |
|           expectUnderTest(fn).not[returnedWith]('bar');
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn)[returnedWith]('bar');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('incomplete recursive calls are handled properly', () => {
 | |
|           // sums up all integers from 0 -> value, using recursion
 | |
|           const fn: mock.Mock<(value: number) => number> = mock.fn(value => {
 | |
|             if (value === 0) {
 | |
|               // Before returning from the base case of recursion, none of the
 | |
|               // calls have returned yet.
 | |
|               // This test ensures that the incomplete calls are not incorrectly
 | |
|               // interpreted as have returned undefined
 | |
|               expectUnderTest(fn).not[returnedWith](undefined);
 | |
|               expect(() =>
 | |
|                 expectUnderTest(fn)[returnedWith](undefined),
 | |
|               ).toThrowErrorMatchingSnapshot();
 | |
| 
 | |
|               return 0;
 | |
|             } else {
 | |
|               return value + fn(value - 1);
 | |
|             }
 | |
|           });
 | |
| 
 | |
|           fn(3);
 | |
|         });
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     if (isToHaveNth(returnedWith)) {
 | |
|       test.describe('nthReturnedWith', () => {
 | |
|         test('works with three calls', () => {
 | |
|           const fn = mock.fn<() => string>();
 | |
|           fn.mockReturnValueOnce('foo1');
 | |
|           fn.mockReturnValueOnce('foo2');
 | |
|           fn.mockReturnValueOnce('foo3');
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
| 
 | |
|           expectUnderTest(fn)[returnedWith](1, 'foo1');
 | |
|           expectUnderTest(fn)[returnedWith](2, 'foo2');
 | |
|           expectUnderTest(fn)[returnedWith](3, 'foo3');
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn).not[returnedWith](1, 'foo1');
 | |
|             expectUnderTest(fn).not[returnedWith](2, 'foo2');
 | |
|             expectUnderTest(fn).not[returnedWith](3, 'foo3');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('should replace 1st, 2nd, 3rd with first, second, third', async () => {
 | |
|           const fn = mock.fn<() => string>();
 | |
|           fn.mockReturnValueOnce('foo1');
 | |
|           fn.mockReturnValueOnce('foo2');
 | |
|           fn.mockReturnValueOnce('foo3');
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn)[returnedWith](1, 'bar1');
 | |
|             expectUnderTest(fn)[returnedWith](2, 'bar2');
 | |
|             expectUnderTest(fn)[returnedWith](3, 'bar3');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn).not[returnedWith](1, 'foo1');
 | |
|             expectUnderTest(fn).not[returnedWith](2, 'foo2');
 | |
|             expectUnderTest(fn).not[returnedWith](3, 'foo3');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('positive throw matcher error for n that is not positive integer', async () => {
 | |
|           const fn = mock.fn(() => 'foo');
 | |
|           fn();
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn)[returnedWith](0, 'foo');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('should reject nth value greater than number of calls', async () => {
 | |
|           const fn = mock.fn(() => 'foo');
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn)[returnedWith](4, 'foo');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('positive throw matcher error for n that is not integer', async () => {
 | |
|           const fn = mock.fn<(a: string) => string>(() => 'foo');
 | |
|           fn('foo');
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn)[returnedWith](0.1, 'foo');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('negative throw matcher error for n that is not number', async () => {
 | |
|           const fn = mock.fn<(a: string) => string>(() => 'foo');
 | |
|           fn('foo');
 | |
| 
 | |
|           expect(() => {
 | |
|             // @ts-expect-error: Testing runtime error
 | |
|             expectUnderTest(fn).not[returnedWith]();
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('incomplete recursive calls are handled properly', () => {
 | |
|           // sums up all integers from 0 -> value, using recursion
 | |
|           const fn: mock.Mock<(value: number) => number> = mock.fn(value => {
 | |
|             if (value === 0) {
 | |
|               return 0;
 | |
|             } else {
 | |
|               const recursiveResult = fn(value - 1);
 | |
| 
 | |
|               if (value === 2) {
 | |
|                 // Only 2 of the recursive calls have returned at this point
 | |
|                 expectUnderTest(fn).not[returnedWith](1, 6);
 | |
|                 expectUnderTest(fn).not[returnedWith](2, 3);
 | |
|                 expectUnderTest(fn)[returnedWith](3, 1);
 | |
|                 expectUnderTest(fn)[returnedWith](4, 0);
 | |
| 
 | |
|                 expect(() =>
 | |
|                   expectUnderTest(fn)[returnedWith](1, 6),
 | |
|                 ).toThrowErrorMatchingSnapshot();
 | |
|                 expect(() =>
 | |
|                   expectUnderTest(fn)[returnedWith](2, 3),
 | |
|                 ).toThrowErrorMatchingSnapshot();
 | |
|                 expect(() =>
 | |
|                   expectUnderTest(fn).not[returnedWith](3, 1),
 | |
|                 ).toThrowErrorMatchingSnapshot();
 | |
|                 expect(() =>
 | |
|                   expectUnderTest(fn).not[returnedWith](4, 0),
 | |
|                 ).toThrowErrorMatchingSnapshot();
 | |
|               }
 | |
| 
 | |
|               return value + recursiveResult;
 | |
|             }
 | |
|           });
 | |
| 
 | |
|           fn(3);
 | |
|         });
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     if (isToHaveLast(returnedWith)) {
 | |
|       test.describe('lastReturnedWith', () => {
 | |
|         test('works with three calls', () => {
 | |
|           const fn = mock.fn<() => string>();
 | |
|           fn.mockReturnValueOnce('foo1');
 | |
|           fn.mockReturnValueOnce('foo2');
 | |
|           fn.mockReturnValueOnce('foo3');
 | |
|           fn();
 | |
|           fn();
 | |
|           fn();
 | |
| 
 | |
|           expectUnderTest(fn)[returnedWith]('foo3');
 | |
| 
 | |
|           expect(() => {
 | |
|             expectUnderTest(fn).not[returnedWith]('foo3');
 | |
|           }).toThrowErrorMatchingSnapshot();
 | |
|         });
 | |
| 
 | |
|         test('incomplete recursive calls are handled properly', () => {
 | |
|           // sums up all integers from 0 -> value, using recursion
 | |
|           const fn: mock.Mock<(value: number) => number> = mock.fn(value => {
 | |
|             if (value === 0) {
 | |
|               // Before returning from the base case of recursion, none of the
 | |
|               // calls have returned yet.
 | |
|               expectUnderTest(fn).not[returnedWith](0);
 | |
|               expect(() =>
 | |
|                 expectUnderTest(fn)[returnedWith](0),
 | |
|               ).toThrowErrorMatchingSnapshot();
 | |
|               return 0;
 | |
|             } else {
 | |
|               return value + fn(value - 1);
 | |
|             }
 | |
|           });
 | |
| 
 | |
|           fn(3);
 | |
|         });
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     test('includes the custom mock name in the error message', () => {
 | |
|       const fn = mock.fn().mockName('named-mock');
 | |
| 
 | |
|       if (isToHaveNth(returnedWith)) {
 | |
|         expectUnderTest(fn).not[returnedWith](1, 'foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith](1, 'foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       } else {
 | |
|         expectUnderTest(fn).not[returnedWith]('foo');
 | |
| 
 | |
|         expect(() =>
 | |
|           expectUnderTest(fn)[returnedWith]('foo'),
 | |
|         ).toThrowErrorMatchingSnapshot();
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| }
 | 
