|
| 1 | +/* eslint-disable @typescript-eslint/no-empty-interface */ |
| 2 | +import type { MatcherContext } from 'expect'; |
| 3 | +import { expect } from 'expect'; |
| 4 | +import type { AwsSdkMockMatchers } from './jestMatchers'; |
| 5 | +import { createBaseMatchers } from './jestMatchers'; |
| 6 | +import type { |
| 7 | + AnySpyCall, |
| 8 | + AwsSdkMockAliasMatchers, |
| 9 | + CommonMatcherUtils, |
| 10 | + MatcherFunction, |
| 11 | +} from './types'; |
| 12 | + |
| 13 | +/** |
| 14 | + * Prettyprints command calls for message |
| 15 | + */ |
| 16 | +function addCalls( |
| 17 | + ctxUtils: CommonMatcherUtils, |
| 18 | + calls: AnySpyCall[], |
| 19 | + ...msgs: string[] |
| 20 | +) { |
| 21 | + if (calls.length === 0) return msgs.join('\n'); |
| 22 | + |
| 23 | + return [ |
| 24 | + ...msgs, |
| 25 | + '', |
| 26 | + 'Calls:', |
| 27 | + ...calls.map( |
| 28 | + (c, i) => |
| 29 | + ` ${i + 1}. ${c.args[0].constructor.name}: ${ctxUtils.printReceived( |
| 30 | + c.args[0].input |
| 31 | + )}` |
| 32 | + ), |
| 33 | + ].join('\n'); |
| 34 | +} |
| 35 | + |
| 36 | +const baseMatchers = createBaseMatchers<MatcherContext['utils']>({ |
| 37 | + toHaveReceivedCommand: ({ |
| 38 | + client, |
| 39 | + cmd, |
| 40 | + notPrefix, |
| 41 | + calls, |
| 42 | + commandCalls, |
| 43 | + ctxUtils, |
| 44 | + }) => |
| 45 | + addCalls( |
| 46 | + ctxUtils, |
| 47 | + calls, |
| 48 | + `Expected ${client} to ${notPrefix}receive ${ctxUtils.printExpected(cmd)}`, |
| 49 | + `${client} received ${ctxUtils.printExpected(cmd)} ${ctxUtils.printReceived(commandCalls.length)} times` |
| 50 | + ), |
| 51 | + toHaveReceivedCommandTimes: |
| 52 | + (expectedCalls) => |
| 53 | + ({ calls, client, cmd, commandCalls, notPrefix, ctxUtils }) => |
| 54 | + addCalls( |
| 55 | + ctxUtils, |
| 56 | + calls, |
| 57 | + `Expected ${client} to ${notPrefix}receive ${ctxUtils.printExpected(cmd)} ${ctxUtils.printExpected(expectedCalls)} times`, |
| 58 | + `${client} received ${ctxUtils.printExpected(cmd)} ${ctxUtils.printReceived(commandCalls.length)} times` |
| 59 | + ), |
| 60 | + |
| 61 | + toHaveReceivedCommandWith: |
| 62 | + (input) => |
| 63 | + ({ client, cmd, notPrefix, data, calls, ctxUtils }) => |
| 64 | + addCalls( |
| 65 | + ctxUtils, |
| 66 | + calls, |
| 67 | + `Expected ${client} to ${notPrefix}receive ${ctxUtils.printExpected(cmd)} with ${ctxUtils.printExpected(input)}`, |
| 68 | + `${client} received matching ${ctxUtils.printExpected(cmd)} ${ctxUtils.printReceived(data.matchCount)} times` |
| 69 | + ), |
| 70 | + |
| 71 | + toHaveReceivedNthCommandWith: |
| 72 | + (call, input) => |
| 73 | + ({ cmd, client, data, notPrefix, ctxUtils, calls }) => |
| 74 | + addCalls( |
| 75 | + ctxUtils, |
| 76 | + calls, |
| 77 | + `Expected ${client} to ${notPrefix}receive ${call}. ${ctxUtils.printExpected(cmd)} with ${ctxUtils.printExpected(input)}`, |
| 78 | + ...(data.received |
| 79 | + ? [ |
| 80 | + `${client} received ${ctxUtils.printReceived(data.received.constructor.name)} with input:`, |
| 81 | + ctxUtils.printDiffOrStringify(input, data.received.input, 'Expected', 'Received', false), |
| 82 | + ] |
| 83 | + : []) |
| 84 | + ), |
| 85 | + toHaveReceivedNthSpecificCommandWith: |
| 86 | + (call, input) => |
| 87 | + ({ cmd, client, data, notPrefix, ctxUtils, calls }) => |
| 88 | + addCalls( |
| 89 | + ctxUtils, |
| 90 | + calls, |
| 91 | + `Expected ${client} to ${notPrefix}receive ${call}. ${ctxUtils.printExpected(cmd)} with ${ctxUtils.printExpected(input)}`, |
| 92 | + ...(data.received |
| 93 | + ? [ |
| 94 | + `${client} received ${ctxUtils.printReceived(data.received.constructor.name)} with input:`, |
| 95 | + ctxUtils.printDiffOrStringify(input, data.received.input, 'Expected', 'Received', false), |
| 96 | + ] |
| 97 | + : []) |
| 98 | + ), |
| 99 | + toHaveReceivedAnyCommand: ({ client, notPrefix, calls, ctxUtils }) => |
| 100 | + addCalls( |
| 101 | + ctxUtils, |
| 102 | + calls, |
| 103 | + `Expected ${client} to ${notPrefix}receive any command`, |
| 104 | + `${client} received any command ${ctxUtils.printReceived(calls.length)} times` |
| 105 | + ), |
| 106 | +}, |
| 107 | +(sample: Record<string, unknown>) => expect.objectContaining(sample) |
| 108 | +); |
| 109 | + |
| 110 | +/* typing ensures keys matching */ |
| 111 | +const aliasMatchers: { |
| 112 | + [P in keyof AwsSdkMockAliasMatchers<unknown>]: MatcherFunction<MatcherContext['utils']>; |
| 113 | +} = { |
| 114 | + toReceiveCommandTimes: baseMatchers.toHaveReceivedCommandTimes, |
| 115 | + toReceiveCommand: baseMatchers.toHaveReceivedCommand, |
| 116 | + toReceiveCommandWith: baseMatchers.toHaveReceivedCommandWith, |
| 117 | + toReceiveNthCommandWith: baseMatchers.toHaveReceivedNthCommandWith, |
| 118 | + toReceiveNthSpecificCommandWith:baseMatchers.toHaveReceivedNthSpecificCommandWith, |
| 119 | + toReceiveAnyCommand: baseMatchers.toHaveReceivedAnyCommand, |
| 120 | +}; |
| 121 | + |
| 122 | +// Skip registration if jest expect does not exist |
| 123 | +if (typeof expect !== 'undefined' && typeof expect.extend === 'function') { |
| 124 | + expect.extend({ ...baseMatchers, ...aliasMatchers }); |
| 125 | +} |
| 126 | + |
| 127 | +/** |
| 128 | + * Types for @types/jest |
| 129 | + */ |
| 130 | +declare global { |
| 131 | + namespace jest { |
| 132 | + interface Matchers<R = void> extends AwsSdkMockMatchers<R> {} |
| 133 | + } |
| 134 | +} |
| 135 | +declare module 'expect' { |
| 136 | + interface Matchers<R = void> extends AwsSdkMockMatchers<R> {} |
| 137 | +} |
0 commit comments