From 2080f64f03a1ef2b5c2ff1b5930116641dd8b2ee Mon Sep 17 00:00:00 2001 From: Andrew Datsenko Date: Wed, 5 Feb 2025 12:52:21 -0800 Subject: [PATCH] Add `.lastCalledWith` and `.toHaveBeenLastCalledWith` (#49210) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49210 Changelog: [Internal] Add missing jest expect apis Reviewed By: rubennorte Differential Revision: D69131600 fbshipit-source-id: bf7a740a4e830c5ce3403d8489bc3439428ee7b4 --- .../react-native-fantom/runtime/expect.js | 23 +++++++++ .../src/__tests__/expect-itest.js | 47 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/packages/react-native-fantom/runtime/expect.js b/packages/react-native-fantom/runtime/expect.js index 0319fe1d1e7..583db433e60 100644 --- a/packages/react-native-fantom/runtime/expect.js +++ b/packages/react-native-fantom/runtime/expect.js @@ -267,6 +267,27 @@ class Expect { } } + lastCalledWith: (...args: Array) => void; + toHaveBeenLastCalledWith(...args: mixed[]): void { + const mock = this.#requireMock(); + if (mock.calls.length === 0) { + if (this.#isNot) { + return; + } + + throw new ErrorWithCustomBlame( + `Expected ${String(this.#received)} to have been last called with ${stringify(args)}, but it was not called a single time.`, + ); + } + + const pass = deepEqual(mock.lastCall, args, {strict: true}); + if (!this.#isExpectedResult(pass)) { + throw new ErrorWithCustomBlame( + `Expected ${String(this.#received)}${this.#maybeNotLabel()} to have been last called with ${stringify(args)}, but it was last called with ${stringify(mock.lastCall)}.`, + ); + } + } + toBeGreaterThan(expected: number): void { if (typeof this.#received !== 'number') { throw new ErrorWithCustomBlame( @@ -466,6 +487,8 @@ Expect.prototype.toBeCalled = Expect.prototype.toHaveBeenCalled; Expect.prototype.toBeCalledTimes = Expect.prototype.toHaveBeenCalledTimes; // $FlowExpectedError[method-unbinding] Expect.prototype.toBeCalledWith = Expect.prototype.toHaveBeenCalledWith; +// $FlowExpectedError[method-unbinding] +Expect.prototype.lastCalledWith = Expect.prototype.toHaveBeenLastCalledWith; const expect: mixed => Expect = (received: mixed) => new Expect(received); diff --git a/packages/react-native-fantom/src/__tests__/expect-itest.js b/packages/react-native-fantom/src/__tests__/expect-itest.js index 5d7bfeb65fc..2c2f55fe8f4 100644 --- a/packages/react-native-fantom/src/__tests__/expect-itest.js +++ b/packages/react-native-fantom/src/__tests__/expect-itest.js @@ -358,6 +358,53 @@ describe('expect', () => { }), ); + ['lastCalledWith', 'toHaveBeenLastCalledWith'].map( + toHaveBeenLastCalledWithAlias => + test(toHaveBeenLastCalledWithAlias, () => { + const fn = jest.fn(); + + expect(fn).not[toHaveBeenLastCalledWithAlias](); + expect(fn).not[toHaveBeenLastCalledWithAlias]({}); + + expect(() => { + expect(fn)[toHaveBeenLastCalledWithAlias](); + }).toThrow(); + + fn('happy'); + expect(fn)[toHaveBeenLastCalledWithAlias]('happy'); + expect(fn).not[toHaveBeenLastCalledWithAlias](); + + fn(); + expect(fn)[toHaveBeenLastCalledWithAlias](); + expect(fn).not[toHaveBeenLastCalledWithAlias]('happy'); + + fn({a: 1}, 2); + + expect(fn)[toHaveBeenLastCalledWithAlias]({a: 1}, 2); + expect(fn).not[toHaveBeenLastCalledWithAlias](); + expect(fn).not[toHaveBeenLastCalledWithAlias]({a: 1}); + expect(fn).not[toHaveBeenLastCalledWithAlias]({a: 2}, 2); + expect(fn).not[toHaveBeenLastCalledWithAlias]({a: 1}, 2, undefined); + + expect(() => { + expect(fn).not[toHaveBeenLastCalledWithAlias]({a: 1}, 2); + }).toThrow(); + + expect(() => { + expect(fn)[toHaveBeenLastCalledWithAlias](1); + }).toThrow(); + + // Passing functions that aren't mocks should always fail + expect(() => { + expect(() => {})[toHaveBeenLastCalledWithAlias](); + }).toThrow(); + + expect(() => { + expect(() => {}).not[toHaveBeenLastCalledWithAlias](); + }).toThrow(); + }), + ); + describe('jest.fn()', () => { it('tracks execution of functions without implementations', () => { const fn = jest.fn();