import { Client, Command, MetadataBearer } from '@smithy/types'; import { SinonSpyCall, SinonStub } from 'sinon'; export type AwsClientBehavior = TClient extends Client ? Behavior : never; export interface Behavior { onAnyCommand(input?: Partial, strict?: boolean): Behavior; on(command: new (input: TCmdInput) => AwsCommand, input?: Partial, strict?: boolean): Behavior; resolves(response: CommandResponse): AwsStub; resolvesOnce(response: CommandResponse): Behavior; rejects(error?: string | Error | AwsError): AwsStub; rejectsOnce(error?: string | Error | AwsError): Behavior; callsFake(fn: (input: any, getClient: () => Client) => any): AwsStub; callsFakeOnce(fn: (input: any, getClient: () => Client) => any): Behavior; } /** * Type for {@link AwsStub} class, * but with the AWS Client class type as an only generic parameter. * * @example * ```ts * let snsMock: AwsClientStub; * snsMock = mockClient(SNSClient); * ``` */ export type AwsClientStub = TClient extends Client ? AwsStub : never; /** * Wrapper on the mocked `Client#send()` method, * allowing to configure its behavior. * * Without any configuration, `Client#send()` invocation returns `undefined`. * * To define resulting variable type easily, use {@link AwsClientStub}. */ export declare class AwsStub implements Behavior { private client; /** * Underlying `Client#send()` method Sinon stub. * * Install `@types/sinon` for TypeScript typings. */ send: SinonStub<[AwsCommand], Promise>; constructor(client: Client, send: SinonStub<[AwsCommand], Promise>); /** Returns the class name of the underlying mocked client class */ clientName(): string; /** * Resets stub. It will replace the stub with a new one, with clean history and behavior. */ reset(): AwsStub; /** Resets stub's calls history. */ resetHistory(): AwsStub; /** Replaces stub with original `Client#send()` method. */ restore(): void; /** * Returns recorded calls to the stub. * Clear history with {@link resetHistory} or {@link reset}. */ calls(): SinonSpyCall<[AwsCommand], Promise>[]; /** * Returns n-th recorded call to the stub. */ call(n: number): SinonSpyCall<[AwsCommand], Promise>; /** * Returns recorded calls of given Command only. * @param commandType Command type to match * @param input Command payload to match * @param strict Should the payload match strictly (default false, will match if all defined payload properties match) */ commandCalls, TCmdInput extends TCmd extends AwsCommand ? TIn : never, TCmdOutput extends TCmd extends AwsCommand ? TOut : never>(commandType: new (input: TCmdInput) => TCmd, input?: Partial, strict?: boolean): SinonSpyCall<[TCmd], Promise>[]; /** * Allows specifying the behavior for any Command with given input (parameters). * * If the input is not specified, the given behavior will be used for any Command with any input. * * Calling `onAnyCommand()` without parameters is not required to specify the default behavior for any Command, * but can be used for readability. * * @example * ```js * clientMock.onAnyCommand().resolves({}) * ``` * * @param input Command payload to match * @param strict Should the payload match strictly (default false, will match if all defined payload properties match) */ onAnyCommand(input?: Partial, strict?: boolean): CommandBehavior; /** * Allows specifying the behavior for a given Command type and its input (parameters). * * If the input is not specified, it will match any Command of that type. * * @example * ```js * snsMock * .on(PublishCommand, {Message: 'My message'}) * .resolves({MessageId: '111'}); * ``` * * @param command Command type to match * @param input Command payload to match * @param strict Should the payload match strictly (default false, will match if all defined payload properties match) */ on(command: new (input: TCmdInput) => AwsCommand, input?: Partial, strict?: boolean): CommandBehavior; private createInputMatcher; /** * Sets a successful response that will be returned from any `Client#send()` invocation. * * @example * ```js * snsMock * .resolves({MessageId: '111'}); * ``` * * @param response Content to be returned */ resolves(response: CommandResponse): AwsStub; /** * Sets a successful response that will be returned from one `Client#send()` invocation. * * Can be chained so that successive invocations return different responses. When there are no more * `resolvesOnce()` responses to use, invocations will return a response specified by `resolves()`. * * @example * ```js * snsMock * .resolvesOnce({MessageId: '111'}) // first call * .resolvesOnce({MessageId: '222'}) // second call * .resolves({MessageId: '333'}); // default * ``` * * @param response Content to be returned */ resolvesOnce(response: CommandResponse): CommandBehavior; /** * Sets a failure response that will be returned from any `Client#send()` invocation. * The response will always be an `Error` instance. * * @example * ```js * snsMock * .rejects('mocked rejection'); *``` * * @example * ```js * const throttlingError = new Error('mocked rejection'); * throttlingError.name = 'ThrottlingException'; * snsMock * .rejects(throttlingError); * ``` * * @param error Error text, Error instance or Error parameters to be returned */ rejects(error?: string | Error | AwsError): AwsStub; /** * Sets a failure response that will be returned from one `Client#send()` invocation. * The response will always be an `Error` instance. * * Can be chained so that successive invocations return different responses. When there are no more * `rejectsOnce()` responses to use, invocations will return a response specified by `rejects()`. * * @example * ```js * snsMock * .rejectsOnce('first mocked rejection') * .rejectsOnce('second mocked rejection') * .rejects('default mocked rejection'); * ``` * * @param error Error text, Error instance or Error parameters to be returned */ rejectsOnce(error?: string | Error | AwsError): CommandBehavior; /** * Sets a function that will be called on any `Client#send()` invocation. * * @example * ```js * snsMock * .callsFake(input => { * if (input.Message === 'My message') { * return {MessageId: '111'}; * } else { * throw new Error('mocked rejection'); * } * }); * ``` * * @example * Result based on the `Client` configuration: * ```js * snsMock * .callsFake(async (input, getClient) => { * const client = getClient(); * const region = await client.config.region(); * return {MessageId: region.substring(0, 2)}; * }); * ``` * * @param fn Function taking Command input and returning result */ callsFake(fn: (input: any, getClient: () => Client) => any): AwsStub; /** * Sets a function that will be called once, on any `Client#send()` invocation. * * Can be chained so that successive invocations call different functions. When there are no more * `callsFakeOnce()` functions to use, invocations will call a function specified by `callsFake()`. * * @example * ```js * snsMock * .callsFakeOnce(cmd => {MessageId: '111'}) // first call * .callsFakeOnce(cmd => {MessageId: '222'}) // second call * .callsFake(cmd => {MessageId: '000'}); // default * ``` * * @param fn Function taking Command input and returning result */ callsFakeOnce(fn: (input: any, getClient: () => Client) => any): CommandBehavior; } export declare class CommandBehavior implements Behavior { private clientStub; private send; /** * Counter to simulate chainable `resolvesOnce()` and similar `*Once()` methods with Sinon `Stub#onCall()`. * The counter is increased with every `*Once()` method call. */ private nextChainableCallNumber; /** * Function to get the current Client object from inside the `callsFake()` callback. * Since this is called from the callback when the mock function is executed, * the current Client is the last on the Sinon `Stub#thisValues` list. */ private getClient; constructor(clientStub: AwsStub, send: SinonStub<[AwsCommand], unknown>); /** * @deprecated Using this method means that the previously set `.on(Command)` was not followed by resolves/rejects/callsFake call. * If this is legitimate behavior, please open an issue with your use case. */ onAnyCommand(input?: Partial, strict?: boolean): Behavior; /** * @deprecated Using this method means that the previously set `.on(Command)` was not followed by resolves/rejects/callsFake call. * If this is legitimate behavior, please open an issue with your use case. */ on(command: new (input: TCmdInput) => AwsCommand, input?: Partial, strict?: boolean): CommandBehavior; /** * Sets a successful response that will be returned from `Client#send()` invocation for the current `Command`. * * @example * ```js * snsMock * .on(PublishCommand) * .resolves({MessageId: '111'}); * ``` * * @param response Content to be returned */ resolves(response: CommandResponse): AwsStub; /** * Sets a successful response that will be returned from one `Client#send()` invocation for the current `Command`. * * Can be chained so that successive invocations return different responses. When there are no more * `resolvesOnce()` responses to use, invocations will return a response specified by `resolves()`. * * @example * ```js * snsMock * .on(PublishCommand) * .resolvesOnce({MessageId: '111'}) // first call * .resolvesOnce({MessageId: '222'}) // second call * .resolves({MessageId: '333'}); // default * ``` * * @param response Content to be returned */ resolvesOnce(response: CommandResponse): CommandBehavior; /** * Sets a failure response that will be returned from `Client#send()` invocation for the current `Command`. * The response will always be an `Error` instance. * * @example * ```js * snsMock * .on(PublishCommand) * .rejects('mocked rejection'); *``` * * @example * ```js * const throttlingError = new Error('mocked rejection'); * throttlingError.name = 'ThrottlingException'; * snsMock * .on(PublishCommand) * .rejects(throttlingError); * ``` * * @param error Error text, Error instance or Error parameters to be returned */ rejects(error?: string | Error | AwsError): AwsStub; /** * Sets a failure response that will be returned from one `Client#send()` invocation for the current `Command`. * The response will always be an `Error` instance. * * Can be chained so that successive invocations return different responses. When there are no more * `rejectsOnce()` responses to use, invocations will return a response specified by `rejects()`. * * @example * ```js * snsMock * .on(PublishCommand) * .rejectsOnce('first mocked rejection') * .rejectsOnce('second mocked rejection') * .rejects('default mocked rejection'); * ``` * * @param error Error text, Error instance or Error parameters to be returned */ rejectsOnce(error?: string | Error | AwsError): CommandBehavior; private static normalizeError; /** * Sets a function that will be called on `Client#send()` invocation for the current `Command`. * * @example * ```js * snsMock * .on(PublishCommand) * .callsFake(input => { * if (input.Message === 'My message') { * return {MessageId: '111'}; * } else { * throw new Error('mocked rejection'); * } * }); * ``` * * @example * Result based on the `Client` configuration: * ```js * snsMock * .on(PublishCommand) * .callsFake(async (input, getClient) => { * const client = getClient(); * const region = await client.config.region(); * return {MessageId: region.substring(0, 2)}; * }); * ``` * * @param fn Function taking Command input and returning result */ callsFake(fn: (input: any, getClient: () => Client) => any): AwsStub; /** * Sets a function that will be called once on `Client#send()` invocation for the current `Command`. * * Can be chained so that successive invocations call different functions. When there are no more * `callsFakeOnce()` functions to use, invocations will call a function specified by `callsFake()`. * * @example * ```js * snsMock * .on(PublishCommand) * .callsFakeOnce(cmd => {MessageId: '111'}) // first call * .callsFakeOnce(cmd => {MessageId: '222'}) // second call * .callsFake(cmd => {MessageId: '000'}); // default * ``` * * @param fn Function taking Command input and returning result */ callsFakeOnce(fn: (input: any, getClient: () => Client) => any): CommandBehavior; private fakeFnWrapper; } export type AwsCommand = Command; type CommandResponse = Partial | PromiseLike>; export interface AwsError extends Partial, Partial { Type?: string; Code?: string; $fault?: 'client' | 'server'; $service?: string; } export {};