Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support toHaveReceivedAnyCommand matcher #202

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@ import 'aws-sdk-client-mock-jest';
// a PublishCommand was sent to SNS
expect(snsMock).toHaveReceivedCommand(PublishCommand);

// Any command was sent to SNS
expect(snsMock).toHaveReceivedAnyCommand();

// two PublishCommands were sent to SNS
expect(snsMock).toHaveReceivedCommandTimes(PublishCommand, 2);

Expand Down
40 changes: 36 additions & 4 deletions packages/aws-sdk-client-mock-jest/src/jestMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ interface AwsSdkJestMockBaseMatchers<R> extends Record<string, Function> {
command: new (input: TCmdInput) => AwsCommand<TCmdInput, TCmdOutput>,
input: Partial<TCmdInput>,
): R;

/**
* Asserts {@link AwsStub Aws Client Mock} received any command
*/
toHaveReceivedAnyCommand(): R;
}

interface AwsSdkJestMockAliasMatchers<R> extends Record<string, Function> {
Expand Down Expand Up @@ -138,6 +143,11 @@ interface AwsSdkJestMockAliasMatchers<R> extends Record<string, Function> {
command: new (input: TCmdInput) => AwsCommand<TCmdInput, TCmdOutput>,
input: Partial<TCmdInput>,
): R;

/**
* Asserts {@link AwsStub Aws Client Mock} received any command
*/
toReceiveAnyCommand(): R;
}

/**
Expand Down Expand Up @@ -191,6 +201,7 @@ type MessageFunctionParams<CheckData> = {
cmd: string;
client: string;
commandCalls: AnySpyCall[];
calls: AnySpyCall[];
data: CheckData;
notPrefix: string;
};
Expand All @@ -214,15 +225,15 @@ const printCalls = (ctx: MatcherContext, calls: AnySpyCall[]): string[] =>
const processMatch = <CheckData = undefined>({ctx, mockClient, command, check, message}: {
ctx: MatcherContext;
mockClient: unknown;
command: new () => AnyCommand;
command?: new () => AnyCommand;
check: (params: { calls: AnySpyCall[]; commandCalls: AnySpyCall[] }) => {
pass: boolean;
data: CheckData;
};
message: (params: MessageFunctionParams<CheckData>) => string[];
}): ExpectationResult => {
assert(mockClient instanceof AwsStub, 'The actual must be a client mock instance');
assert(
command && assert(
command &&
typeof command === 'function' &&
typeof command.name === 'string' &&
Expand All @@ -231,19 +242,20 @@ const processMatch = <CheckData = undefined>({ctx, mockClient, command, check, m
);

const calls = mockClient.calls();
const commandCalls = mockClient.commandCalls(command);
const commandCalls = command ? mockClient.commandCalls(command) : [];

const {pass, data} = check({calls, commandCalls});

const msg = (): string => {
const cmd = ctx.utils.printExpected(command.name);
const cmd = ctx.utils.printExpected(command?.name || 'Any Command');
const client = mockClient.clientName();

return [
...message({
client,
cmd,
data,
calls,
commandCalls,
notPrefix: ctx.isNot ? 'not ' : '',
}),
Expand Down Expand Up @@ -462,6 +474,25 @@ const baseMatchers: { [P in keyof AwsSdkJestMockBaseMatchers<unknown>]: MatcherF
],
});
},
/**
* implementation of {@link AwsSdkJestMockMatchers.toHaveReceivedAnyCommand} matcher
*/
toHaveReceivedAnyCommand(
this: MatcherContext,
mockClient: unknown,
...other: unknown[]
) {
ensureNoOtherArgs(other);
return processMatch({
ctx: this,
mockClient,
check: ({calls}) => ({pass: calls.length > 0, data: undefined}),
message: ({client, notPrefix, calls}) => [
`Expected ${client} to ${notPrefix}receive any command`,
`${client} received any command ${this.utils.printReceived(calls.length)} times`,
],
});
},
};

/* typing ensures keys matching */
Expand All @@ -471,6 +502,7 @@ const aliasMatchers: { [P in keyof AwsSdkJestMockAliasMatchers<unknown>]: Matche
toReceiveCommandWith: baseMatchers.toHaveReceivedCommandWith,
toReceiveNthCommandWith: baseMatchers.toHaveReceivedNthCommandWith,
toReceiveNthSpecificCommandWith: baseMatchers.toHaveReceivedNthSpecificCommandWith,
toReceiveAnyCommand: baseMatchers.toHaveReceivedAnyCommand,
};

// Skip registration if jest expect does not exist
Expand Down
2 changes: 2 additions & 0 deletions packages/aws-sdk-client-mock-jest/test-d/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ expect(1).toHaveReceivedCommand(PublishCommand);
expect(mockClient(SNSClient)).toHaveReceivedCommand(PublishCommand);
expectError(expect(mockClient(SNSClient)).toHaveReceivedCommand(String));

expect(mockClient(SNSClient)).toHaveReceivedAnyCommand();

expect(mockClient(SNSClient)).toHaveReceivedCommandTimes(PublishCommand, 1);
expectError(expect(mockClient(SNSClient)).toHaveReceivedCommandTimes(PublishCommand));

Expand Down
22 changes: 21 additions & 1 deletion packages/aws-sdk-client-mock-jest/test/jestMatchers.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AwsClientStub, mockClient} from 'aws-sdk-client-mock';
import {AwsClientStub, AwsCommand, mockClient} from 'aws-sdk-client-mock';
import {PublishCommand, SNSClient} from '@aws-sdk/client-sns';
import {publishCmd1, publishCmd2, subscribeCmd1} from 'aws-sdk-client-mock/test/fixtures';
import '../src';
Expand Down Expand Up @@ -273,3 +273,23 @@ Calls:
`);
});
});

describe('toHaveReceivedAnyCommand', () => {
it.each`
command
${publishCmd1}
${subscribeCmd1}
`('passes on receiving any command', async ({ command }: { command: AwsCommand<any, any> }) => {
const sns = new SNSClient({});
await sns.send(command); // eslint-disable-line @typescript-eslint/no-unsafe-argument

expect(() => expect(snsMock).toHaveReceivedAnyCommand()).not.toThrow();
});

it('fails on not receiving any command', () => {
expect(() => expect(snsMock).toHaveReceivedAnyCommand()).toThrowErrorMatchingInlineSnapshot(`
"Expected SNSClient to receive any command
SNSClient received any command <red>0</color> times"
`);
});
});
Loading