m-radzikowski / aws-sdk-client-mock

AWS JavaScript SDK v3 mocks for easy unit testing. 🖋️ Typed 🔬 Tested 📄 Documented 🛠️ Maintained
https://m-radzikowski.github.io/aws-sdk-client-mock/
MIT License
811 stars 40 forks source link

Improve diffing of Jest Matchers #236

Open elliot-tt opened 2 months ago

elliot-tt commented 2 months ago

Love the library. It is much more ergonomic compared to the mocking I was doing by hand!

Jest can show a diff between the received and actual calls when I use .toHaveBeenCalledWith(...) including when there are multiple non-matches.

Diff Examples in a Details so this ticket doesn't look super long ```ts describe('diff demo', () => { it('diffs the real call and expected', () => { const mockFn = jest.fn(); mockFn({ RoleArn: 'abc', RoleSessionName: 'def' }); expect(mockFn).toHaveBeenCalledWith({ SomeField: 'xyz', RoleArn: 'ABC', RoleSessionName: 'def', }); }); }); ``` ```diff expect(jest.fn()).toHaveBeenCalledWith(...expected) - Expected + Received Object { - "RoleArn": "ABC", + "RoleArn": "abc", "RoleSessionName": "def", - "SomeField": "xyz", }, Number of calls: 1 ``` ```ts it('diffs the real call and expected with multiple calls', () => { const mockFn = jest.fn(); mockFn({ RoleArn: 'abc', RoleSessionName: 'def' }); mockFn({ SomeField: 'xyz', RoleSessionName: 'def' }); expect(mockFn).toHaveBeenCalledWith({ SomeField: 'xyz', RoleArn: 'ABC', RoleSessionName: 'def', }); }); ``` ```diff expect(jest.fn()).toHaveBeenCalledWith(...expected) Expected: {"RoleArn": "ABC", "RoleSessionName": "def", "SomeField": "xyz"} Received 1 Object { - "RoleArn": "ABC", + "RoleArn": "abc", "RoleSessionName": "def", - "SomeField": "xyz", }, 2 Object { - "RoleArn": "ABC", "RoleSessionName": "def", "SomeField": "xyz", }, Number of calls: 2 ```

Whereas when I use aws-sdk-client-mock-jest matcher .toHaveReceivedCommandWith

it("Doesn't diff the real call and expected", async () => {
    const mockedClient = new STSClient();
    await mockedClient.send(
        new AssumeRoleCommand({
            RoleArn: 'abc',
            RoleSessionName: 'def',
        }),
    );

    expect(stsMock).toHaveReceivedCommandWith(AssumeRoleCommand, {
        RoleArn: 'ABC',
        RoleSessionName: 'def',
        SourceIdentity: 'xyz',
    });
});
Expected STSClient to receive "AssumeRoleCommand" with {"RoleArn": "ABC", "RoleSessionName": "def", "SourceIdentity": "xyz"}
STSClient received matching "AssumeRoleCommand" 0 times

Calls:
  1. AssumeRoleCommand: {"RoleArn": "abc", "RoleSessionName": "def"}

particularly when the difference between expected and actual is subtle (the example that prompted this feature request was an arn with a : v.s. :: it would be nice to see the diff output (which I naively assume Jest can do for us? 🤞)

If this is a feature you'd support I'd happily contribute some time to making it happen.

m-radzikowski commented 2 months ago

The main problem here is that toHaveReceivedCommandWith() does not simply compare 2 objects but compares the expected object with all received values, of which there can be 0, 1, or multiple. So if we received 2 calls and none of them match, we don't know to which we should compare in a "nice" output.

However:

  1. In most cases, like your example, we receive only a single call, so we could show the nice diff then (because 99% it is the call we expected and want to compare to), otherwise defaulting to the current behavior (listing all received calls).
  2. There is toHaveReceivedNthCommandWith() which compares expected value and single received value, so we can show the nice diff here as well.

This sounds like a nice improvement. If you are willing to do so, please create a PR.