aws-sdk-vitest-mock 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -3
- package/index.cjs +9 -9
- package/index.d.ts +1 -1
- package/index.js +303 -281
- package/lib/mock-client.d.ts +28 -4
- package/lib/utils/debug-logger.d.ts +5 -3
- package/lib/utils/file-helpers.d.ts +1 -1
- package/lib/utils/paginator-helpers.d.ts +1 -1
- package/lib/utils/stream-helpers.d.ts +1 -1
- package/{matchers-Dkkl4vtx.cjs → matchers-CNhdB_9q.cjs} +1 -1
- package/{matchers-ClGOsQx8.js → matchers-DmTtFk31.js} +2 -2
- package/package.json +3 -1
- package/vitest-setup.cjs +1 -1
- package/vitest-setup.js +1 -1
package/README.md
CHANGED
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
<a href="https://www.npmjs.com/package/aws-sdk-vitest-mock">
|
|
13
13
|
<img src="https://img.shields.io/npm/v/aws-sdk-vitest-mock?color=cb3837&logo=npm" alt="npm version" />
|
|
14
14
|
</a>
|
|
15
|
+
<img alt="NPM Downloads" src="https://img.shields.io/npm/dm/aws-sdk-vitest-mock">
|
|
16
|
+
<img alt="GitHub Issues or Pull Requests" src="https://img.shields.io/github/issues/sudokar/aws-sdk-vitest-mock">
|
|
15
17
|
<a href="https://github.com/sudokar/aws-sdk-vitest-mock/actions">
|
|
16
18
|
<img src="https://github.com/sudokar/aws-sdk-vitest-mock/actions/workflows/ci.yml/badge.svg" alt="CI Status" />
|
|
17
19
|
</a>
|
|
18
|
-
<img src="https://img.shields.io/badge/ESM%20Support-yes-4B32C3?logo=
|
|
20
|
+
<img src="https://img.shields.io/badge/ESM%20Support-yes-4B32C3?logo=typescript" alt="ESM Support" />
|
|
19
21
|
<img src="https://img.shields.io/badge/Zero%20Dependencies-yes-brightgreen" alt="Zero Dependencies" />
|
|
20
22
|
<a href="https://eslint.org/">
|
|
21
23
|
<img src="https://img.shields.io/badge/code%20style-eslint-4B32C3?logo=eslint" alt="ESLint" />
|
|
@@ -564,6 +566,46 @@ s3Mock.restore();
|
|
|
564
566
|
s3Mock.disableDebug();
|
|
565
567
|
```
|
|
566
568
|
|
|
569
|
+
#### Global Debug Configuration
|
|
570
|
+
|
|
571
|
+
Enable debug logging for all mocks globally, with the ability to override at the individual mock level:
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
import { setGlobalDebug, mockClient } from "aws-sdk-vitest-mock";
|
|
575
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
576
|
+
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
|
|
577
|
+
|
|
578
|
+
// Enable debug for all mocks
|
|
579
|
+
setGlobalDebug(true);
|
|
580
|
+
|
|
581
|
+
// All mocks will inherit the global debug setting
|
|
582
|
+
const s3Mock = mockClient(S3Client);
|
|
583
|
+
const dynamoMock = mockClient(DynamoDBClient);
|
|
584
|
+
|
|
585
|
+
// Both mocks will log debug information
|
|
586
|
+
s3Mock.on(GetObjectCommand).resolves({ Body: "data" });
|
|
587
|
+
dynamoMock.on(GetItemCommand).resolves({ Item: { id: { S: "1" } } });
|
|
588
|
+
|
|
589
|
+
// Override global setting for a specific mock
|
|
590
|
+
s3Mock.disableDebug(); // This mock won't log, but dynamoMock still will
|
|
591
|
+
|
|
592
|
+
// Disable global debug
|
|
593
|
+
setGlobalDebug(false);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Debug Priority (highest to lowest):**
|
|
597
|
+
|
|
598
|
+
1. Individual mock's `enableDebug()` or `disableDebug()` call (explicit override)
|
|
599
|
+
2. Global debug setting via `setGlobalDebug()`
|
|
600
|
+
3. Default: disabled
|
|
601
|
+
|
|
602
|
+
**Key behaviors:**
|
|
603
|
+
|
|
604
|
+
- When global debug is enabled, all new and existing mocks will log unless explicitly disabled
|
|
605
|
+
- Individual mock settings always take priority over global settings
|
|
606
|
+
- `reset()` preserves individual debug settings
|
|
607
|
+
- Global debug can be changed at any time and affects all mocks without explicit settings
|
|
608
|
+
|
|
567
609
|
Debug mode provides comprehensive logging for:
|
|
568
610
|
|
|
569
611
|
**Mock Configuration:**
|
|
@@ -650,6 +692,8 @@ test("should call DynamoDB", async () => {
|
|
|
650
692
|
|
|
651
693
|
## 📚 API Reference
|
|
652
694
|
|
|
695
|
+
> TypeScript documentation for this library can be found at [here](https://sudokar.github.io/aws-sdk-vitest-mock/)
|
|
696
|
+
|
|
653
697
|
### `mockClient<TClient>(ClientConstructor)`
|
|
654
698
|
|
|
655
699
|
Creates a mock for an AWS SDK client constructor.
|
|
@@ -662,14 +706,18 @@ Mocks an existing AWS SDK client instance.
|
|
|
662
706
|
|
|
663
707
|
**Returns:** `AwsClientStub<TClient>`
|
|
664
708
|
|
|
709
|
+
### Global Debug Functions
|
|
710
|
+
|
|
711
|
+
- `setGlobalDebug(enabled: boolean)` - Enable or disable debug logging globally for all mocks
|
|
712
|
+
|
|
665
713
|
### `AwsClientStub` Methods
|
|
666
714
|
|
|
667
715
|
- `on(Command, matcher?, options?)` - Configure mock for a command
|
|
668
716
|
- `reset()` - Clear call history while preserving mock configurations
|
|
669
717
|
- `restore()` - Restore original client behavior
|
|
670
718
|
- `calls()` - Get call history
|
|
671
|
-
- `enableDebug()` - Enable debug logging for troubleshooting
|
|
672
|
-
- `disableDebug()` - Disable debug logging
|
|
719
|
+
- `enableDebug()` - Enable debug logging for troubleshooting (overrides global setting)
|
|
720
|
+
- `disableDebug()` - Disable debug logging (overrides global setting)
|
|
673
721
|
|
|
674
722
|
### `AwsCommandStub` Methods (Chainable)
|
|
675
723
|
|
package/index.cjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
${
|
|
3
|
-
`),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("vitest"),$=require("./matchers-CNhdB_9q.cjs"),W=require("node:fs"),C=require("node:path"),I=require("node:stream");class d extends Error{constructor(t,o,s,n){super(t),this.name=o,this.code=o,this.statusCode=s,this.retryable=n}}const T=e=>new d(e?`The specified key does not exist. Key: ${e}`:"The specified key does not exist.","NoSuchKey",404,!1),M=e=>new d(e?`The specified bucket does not exist. Bucket: ${e}`:"The specified bucket does not exist.","NoSuchBucket",404,!1),K=e=>new d(e?`Access Denied for resource: ${e}`:"Access Denied","AccessDenied",403,!1),A=e=>new d(e?`Requested resource not found: ${e}`:"Requested resource not found","ResourceNotFoundException",400,!1),B=()=>new d("The conditional request failed","ConditionalCheckFailedException",400,!1),J=()=>new d("Rate exceeded","Throttling",400,!0),q=()=>new d("We encountered an internal error. Please try again.","InternalServerError",500,!0),_=e=>{try{return JSON.stringify(e,void 0,2)}catch{return typeof e=="object"&&e!==null?"[Complex Object]":typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):"[Non-serializable value]"}},k=(e,t)=>{const o=$.colors.magenta("aws-sdk-vitest-mock(debug):");if(t===void 0)console.log(`${o} ${e}`);else{const s=_(t);console.log(`${o} ${e}
|
|
2
|
+
${s}`)}},w=(e=!1)=>({enabled:e,explicitlySet:!1,log(t,o){this.enabled&&k(t,o)},logDirect(t,o){k(t,o)}}),z=e=>{e.enabled=!0,e.explicitlySet=!0},V=e=>{e.enabled=!1,e.explicitlySet=!0},G=e=>{const t=C.resolve(e);try{const o=W.readFileSync(t,"utf8");if(e.endsWith(".json"))try{return JSON.parse(o)}catch(s){const n=s instanceof Error?s.message:String(s);throw new Error(`Failed to parse JSON fixture at ${t}: ${n}`)}return o}catch(o){const s=o instanceof Error?o.message:String(o);throw new Error(`Failed to load fixture at ${t}: ${s}`)}},U=(e,t={})=>{const{pageSize:o=10,tokenKey:s="NextToken",itemsKey:n="Items"}=t;if(e.length===0)return[{[n]:[]}];const c=[];for(let r=0;r<e.length;r+=o){const i=e.slice(r,r+o),l=r+o<e.length,u={[n]:i};if(l){const a=u,f=i[i.length-1];a[s]=f}c.push(u)}return c},H=()=>typeof process<"u"&&process.versions?.node?"node":typeof process<"u"&&process.versions?.bun?"bun":"browser",Q=e=>{const t=typeof e=="string"?Buffer.from(e,"utf8"):Buffer.from(e);let o=!1;return new I.Readable({read(){o||(this.push(t),this.push(null),o=!0)}})},X=e=>{let t;return typeof e=="string"?t=new TextEncoder().encode(e):e instanceof Buffer?t=new Uint8Array(e):t=e,new ReadableStream({start(o){o.enqueue(t),o.close()}})},S=e=>{const t=H();return t==="node"||t==="bun"?Q(e):X(e)};let D=!1;function Y(e){D=e}function b(e){return e.explicitlySet?e.enabled:D}function E(e,t){return Object.keys(t).every(o=>{const s=t[o],n=e[o];return s&&typeof s=="object"&&!Array.isArray(s)?typeof n!="object"||n===null?!1:E(n,s):n===s})}function N(e,t){if(e===t)return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return e===t;const o=Object.keys(e),s=Object.keys(t);return o.length!==s.length?!1:s.every(n=>{if(!Object.prototype.hasOwnProperty.call(e,n))return!1;const c=e,r=t,i=c[n],l=r[n];return typeof i=="object"&&i!==null&&typeof l=="object"&&l!==null?N(i,l):i===l})}function Z(e,t,o){const s=t.map((c,r)=>{const i=c.matcher?JSON.stringify(c.matcher,void 0,2):"any input",l=c.strict?" (strict mode)":"";return` Mock #${r+1}: ${i}${l}`}).join(`
|
|
3
|
+
`),n=JSON.stringify(o,void 0,2);return new Error(`No matching mock found for ${e}.
|
|
4
4
|
|
|
5
|
-
Found ${
|
|
5
|
+
Found ${t.length} mock(s) but none matched the input.
|
|
6
6
|
|
|
7
7
|
Configured mocks:
|
|
8
|
-
${
|
|
8
|
+
${s}
|
|
9
9
|
|
|
10
10
|
Received input:
|
|
11
|
-
${
|
|
11
|
+
${n}
|
|
12
12
|
|
|
13
|
-
Tip: Enable debug mode with enableDebug() for detailed matching information.`)}
|
|
13
|
+
Tip: Enable debug mode with enableDebug() for detailed matching information.`)}function ee(e,t){const o=JSON.stringify(t,void 0,2);return new Error(`No mock configured for command: ${e}.
|
|
14
14
|
|
|
15
15
|
Received input:
|
|
16
|
-
${
|
|
16
|
+
${o}
|
|
17
17
|
|
|
18
|
-
Did you forget to call mockClient.on(${t.constructor.name})
|
|
18
|
+
Did you forget to call mockClient.on(${e})?`)}function te(e,t){return e.findIndex(o=>o.strict?o.matcher&&N(t,o.matcher):!o.matcher||E(t,o.matcher))}function x(e){return async function(t){const o=()=>this,s=b(e.debugLogger),n=t.constructor.name;s&&e.debugLogger.logDirect(`Received command: ${n}`,t.input);const c=e.map.get(t.constructor);if(!c)throw s&&e.debugLogger.logDirect(`No mocks configured for ${n}`),ee(n,t.input);s&&e.debugLogger.logDirect(`Found ${c.length} mock(s) for ${n}`);const r=te(c,t.input);if(r===-1)throw s&&e.debugLogger.logDirect(`No matching mock found for ${n}`,t.input),Z(n,c,t.input);const i=c[r];if(!i)throw new Error(`Mock at index ${r} not found`);return s&&e.debugLogger.logDirect(`Using mock at index ${r} for ${n}`),i.once&&(c.splice(r,1),s&&e.debugLogger.logDirect(`Removed one-time mock for ${n}`)),i.handler(t.input,o())}}const L=(e,t,o)=>({reset(){b(e.debugLogger)&&e.debugLogger.logDirect(o.reset),t.mockClear()},restore(){b(e.debugLogger)&&e.debugLogger.logDirect(o.restore),t.mockRestore(),e.map=new WeakMap},calls(){return t.mock.calls.map(s=>s[0])},__rawCalls(){return t.mock.calls},enableDebug(){z(e.debugLogger)},disableDebug(){V(e.debugLogger)}});function R(e,t,o,s={}){const n=(r,i,l)=>{const u={matcher:o,handler:r,once:i,strict:!!s.strict},a=e.map.get(t)??[],f=b(e.debugLogger);if(i){const g=a.findIndex(h=>!h.once);g===-1?a.push(u):a.splice(g,0,u),e.map.set(t,a),f&&e.debugLogger.logDirect(`Configured ${l}Once for ${t.name}`,o?{matcher:o,strict:!!s.strict}:void 0)}else{const g=a.filter(h=>h.once||JSON.stringify(h.matcher)!==JSON.stringify(o));g.push(u),e.map.set(t,g),f&&e.debugLogger.logDirect(`Configured ${l} for ${t.name}`,o?{matcher:o,strict:!!s.strict}:void 0)}},c={resolves(r){return n(()=>Promise.resolve(r),!1,"resolves"),c},rejects(r){return n(()=>{const i=typeof r=="string"?new Error(r):r;return Promise.reject(i)},!1,"rejects"),c},callsFake(r){return n(r,!1,"callsFake"),c},resolvesOnce(r){return n(()=>Promise.resolve(r),!0,"resolves"),c},rejectsOnce(r){return n(()=>{const i=typeof r=="string"?new Error(r):r;return Promise.reject(i)},!0,"rejects"),c},callsFakeOnce(r){return n(r,!0,"callsFake"),c},resolvesStream(r){return n(()=>Promise.resolve({Body:S(r)}),!1,"resolvesStream"),c},resolvesStreamOnce(r){return n(()=>Promise.resolve({Body:S(r)}),!0,"resolvesStream"),c},resolvesWithDelay(r,i){const l=u=>{setTimeout(()=>u(r),i)};return n(()=>new Promise(l),!1,"resolvesWithDelay"),c},rejectsWithDelay(r,i){const l=typeof r=="string"?new Error(r):r,u=(a,f)=>{setTimeout(()=>f(l),i)};return n(()=>new Promise(u),!1,"rejectsWithDelay"),c},rejectsWithNoSuchKey(r){return n(()=>Promise.reject(T(r)),!1,"rejectsWithNoSuchKey"),c},rejectsWithNoSuchBucket(r){return n(()=>Promise.reject(M(r)),!1,"rejectsWithNoSuchBucket"),c},rejectsWithAccessDenied(r){return n(()=>Promise.reject(K(r)),!1,"rejectsWithAccessDenied"),c},rejectsWithResourceNotFound(r){return n(()=>Promise.reject(A(r)),!1,"rejectsWithResourceNotFound"),c},rejectsWithConditionalCheckFailed(){return n(()=>Promise.reject(B()),!1,"rejectsWithConditionalCheckFailed"),c},rejectsWithThrottling(){return n(()=>Promise.reject(J()),!1,"rejectsWithThrottling"),c},rejectsWithInternalServerError(){return n(()=>Promise.reject(q()),!1,"rejectsWithInternalServerError"),c},resolvesPaginated(r,i={}){const l=U(r,i);let u=0;return e.debugLogger.log(`Configured resolvesPaginated for ${t.name}`,{pageSize:i.pageSize,itemsCount:r.length}),n(a=>{const f=i.tokenKey||"NextToken",g=i.inputTokenKey||f,m=a[g];if(m!=null){const F=i.itemsKey||"Items";let v=0;for(const O of l){const p=O[F];if(p&&p.length>0){const P=p[p.length-1];if(JSON.stringify(P)===JSON.stringify(m)){u=v+1;break}}v++}}else u=0;const y=l[u]||l[l.length-1]||l[0];if(!y)throw new Error("No paginated responses available");return u=Math.min(u+1,l.length-1),Promise.resolve(y)},!1,"resolvesPaginated"),c},resolvesFromFile(r){return e.debugLogger.log(`Configured resolvesFromFile for ${t.name}`,{filePath:r}),n(()=>{const i=G(r);return Promise.resolve(i)},!1,"resolvesFromFile"),c}};return c}const re=e=>{const t={map:new WeakMap,debugLogger:w()},o=e.prototype,s=j.vi.spyOn(o,"send").mockImplementation(x(t)),n=L(t,s,{reset:"Clearing call history (mocks preserved)",restore:"Restoring original client behavior and clearing all mocks"});return{client:void 0,on:(r,i,l)=>R(t,r,i,l),...n}},oe=e=>{const t={map:new WeakMap,debugLogger:w()},o=j.vi.spyOn(e,"send").mockImplementation(x(t)),s=L(t,o,{reset:"Clearing call history (mocks preserved) for client instance",restore:"Restoring original client behavior and clearing all mocks for client instance"});return{client:e,on:(c,r,i)=>R(t,c,r,i),...s}};exports.matchers=$.matchers;exports.mockClient=re;exports.mockClientInstance=oe;exports.setGlobalDebug=Y;
|
package/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* Core Functions for mocking AWS SDK clients
|
|
30
30
|
* @category Core Functions
|
|
31
31
|
*/
|
|
32
|
-
export { mockClient, mockClientInstance } from './lib/mock-client.js';
|
|
32
|
+
export { mockClient, mockClientInstance, setGlobalDebug, } from './lib/mock-client.js';
|
|
33
33
|
/**
|
|
34
34
|
* Command stub interface for configuring mock behaviors
|
|
35
35
|
* @category Command Stub
|
package/index.js
CHANGED
|
@@ -1,454 +1,476 @@
|
|
|
1
|
-
import { vi as
|
|
2
|
-
import { c as
|
|
3
|
-
import { m as
|
|
1
|
+
import { vi as j } from "vitest";
|
|
2
|
+
import { c as O } from "./matchers-DmTtFk31.js";
|
|
3
|
+
import { m as ge } from "./matchers-DmTtFk31.js";
|
|
4
4
|
import { readFileSync as P } from "node:fs";
|
|
5
|
-
import
|
|
6
|
-
import { Readable as
|
|
7
|
-
class
|
|
8
|
-
constructor(t,
|
|
9
|
-
super(t), this.name =
|
|
5
|
+
import C from "node:path";
|
|
6
|
+
import { Readable as I } from "node:stream";
|
|
7
|
+
class d extends Error {
|
|
8
|
+
constructor(t, o, s, n) {
|
|
9
|
+
super(t), this.name = o, this.code = o, this.statusCode = s, this.retryable = n;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
const T = (e) => new d(
|
|
13
|
+
e ? `The specified key does not exist. Key: ${e}` : "The specified key does not exist.",
|
|
14
|
+
"NoSuchKey",
|
|
15
|
+
404,
|
|
16
|
+
!1
|
|
17
|
+
), M = (e) => new d(
|
|
18
|
+
e ? `The specified bucket does not exist. Bucket: ${e}` : "The specified bucket does not exist.",
|
|
19
|
+
"NoSuchBucket",
|
|
20
|
+
404,
|
|
21
|
+
!1
|
|
22
|
+
), K = (e) => new d(
|
|
23
|
+
e ? `Access Denied for resource: ${e}` : "Access Denied",
|
|
24
|
+
"AccessDenied",
|
|
25
|
+
403,
|
|
26
|
+
!1
|
|
27
|
+
), A = (e) => new d(
|
|
28
|
+
e ? `Requested resource not found: ${e}` : "Requested resource not found",
|
|
29
|
+
"ResourceNotFoundException",
|
|
30
|
+
400,
|
|
31
|
+
!1
|
|
32
|
+
), B = () => new d(
|
|
25
33
|
"The conditional request failed",
|
|
26
34
|
"ConditionalCheckFailedException",
|
|
27
35
|
400,
|
|
28
36
|
!1
|
|
29
|
-
),
|
|
37
|
+
), J = () => new d("Rate exceeded", "Throttling", 400, !0), q = () => new d(
|
|
30
38
|
"We encountered an internal error. Please try again.",
|
|
31
39
|
"InternalServerError",
|
|
32
40
|
500,
|
|
33
41
|
!0
|
|
34
|
-
)
|
|
35
|
-
function B(e) {
|
|
42
|
+
), z = (e) => {
|
|
36
43
|
try {
|
|
37
44
|
return JSON.stringify(e, void 0, 2);
|
|
38
45
|
} catch {
|
|
39
46
|
return typeof e == "object" && e !== null ? "[Complex Object]" : typeof e == "string" ? e : typeof e == "number" || typeof e == "boolean" ? String(e) : "[Non-serializable value]";
|
|
40
47
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
e.enabled = !0;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
48
|
+
}, k = (e, t) => {
|
|
49
|
+
const o = O.magenta("aws-sdk-vitest-mock(debug):");
|
|
50
|
+
if (t === void 0)
|
|
51
|
+
console.log(`${o} ${e}`);
|
|
52
|
+
else {
|
|
53
|
+
const s = z(t);
|
|
54
|
+
console.log(`${o} ${e}
|
|
55
|
+
${s}`);
|
|
56
|
+
}
|
|
57
|
+
}, $ = (e = !1) => ({
|
|
58
|
+
enabled: e,
|
|
59
|
+
explicitlySet: !1,
|
|
60
|
+
log(t, o) {
|
|
61
|
+
this.enabled && k(t, o);
|
|
62
|
+
},
|
|
63
|
+
logDirect(t, o) {
|
|
64
|
+
k(t, o);
|
|
65
|
+
}
|
|
66
|
+
}), V = (e) => {
|
|
67
|
+
e.enabled = !0, e.explicitlySet = !0;
|
|
68
|
+
}, _ = (e) => {
|
|
69
|
+
e.enabled = !1, e.explicitlySet = !0;
|
|
70
|
+
}, U = (e) => {
|
|
71
|
+
const t = C.resolve(e);
|
|
72
|
+
try {
|
|
73
|
+
const o = P(t, "utf8");
|
|
74
|
+
if (e.endsWith(".json"))
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(o);
|
|
77
|
+
} catch (s) {
|
|
78
|
+
const n = s instanceof Error ? s.message : String(s);
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Failed to parse JSON fixture at ${t}: ${n}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return o;
|
|
84
|
+
} catch (o) {
|
|
85
|
+
const s = o instanceof Error ? o.message : String(o);
|
|
86
|
+
throw new Error(`Failed to load fixture at ${t}: ${s}`);
|
|
87
|
+
}
|
|
88
|
+
}, G = (e, t = {}) => {
|
|
89
|
+
const { pageSize: o = 10, tokenKey: s = "NextToken", itemsKey: n = "Items" } = t;
|
|
73
90
|
if (e.length === 0)
|
|
74
|
-
return [{ [
|
|
75
|
-
const
|
|
76
|
-
for (let r = 0; r < e.length; r +=
|
|
77
|
-
const
|
|
91
|
+
return [{ [n]: [] }];
|
|
92
|
+
const c = [];
|
|
93
|
+
for (let r = 0; r < e.length; r += o) {
|
|
94
|
+
const i = e.slice(r, r + o), l = r + o < e.length, u = { [n]: i };
|
|
78
95
|
if (l) {
|
|
79
|
-
const
|
|
80
|
-
|
|
96
|
+
const a = u, f = i[i.length - 1];
|
|
97
|
+
a[s] = f;
|
|
81
98
|
}
|
|
82
|
-
|
|
99
|
+
c.push(u);
|
|
83
100
|
}
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
function q() {
|
|
87
|
-
return typeof process < "u" && process.versions?.node ? "node" : typeof process < "u" && process.versions?.bun ? "bun" : "browser";
|
|
88
|
-
}
|
|
89
|
-
function z(e) {
|
|
101
|
+
return c;
|
|
102
|
+
}, H = () => typeof process < "u" && process.versions?.node ? "node" : typeof process < "u" && process.versions?.bun ? "bun" : "browser", Q = (e) => {
|
|
90
103
|
const t = typeof e == "string" ? Buffer.from(e, "utf8") : Buffer.from(e);
|
|
91
|
-
let
|
|
92
|
-
return new
|
|
104
|
+
let o = !1;
|
|
105
|
+
return new I({
|
|
93
106
|
read() {
|
|
94
|
-
|
|
107
|
+
o || (this.push(t), this.push(null), o = !0);
|
|
95
108
|
}
|
|
96
109
|
});
|
|
97
|
-
}
|
|
98
|
-
function V(e) {
|
|
110
|
+
}, X = (e) => {
|
|
99
111
|
let t;
|
|
100
112
|
return typeof e == "string" ? t = new TextEncoder().encode(e) : e instanceof Buffer ? t = new Uint8Array(e) : t = e, new ReadableStream({
|
|
101
|
-
start(
|
|
102
|
-
|
|
113
|
+
start(o) {
|
|
114
|
+
o.enqueue(t), o.close();
|
|
103
115
|
}
|
|
104
116
|
});
|
|
117
|
+
}, S = (e) => {
|
|
118
|
+
const t = H();
|
|
119
|
+
return t === "node" || t === "bun" ? Q(e) : X(e);
|
|
120
|
+
};
|
|
121
|
+
let w = !1;
|
|
122
|
+
function ie(e) {
|
|
123
|
+
w = e;
|
|
105
124
|
}
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
return t === "node" || t === "bun" ? z(e) : V(e);
|
|
125
|
+
function m(e) {
|
|
126
|
+
return e.explicitlySet ? e.enabled : w;
|
|
109
127
|
}
|
|
110
|
-
function
|
|
111
|
-
return Object.keys(t).every((
|
|
112
|
-
const
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
) :
|
|
128
|
+
function E(e, t) {
|
|
129
|
+
return Object.keys(t).every((o) => {
|
|
130
|
+
const s = t[o], n = e[o];
|
|
131
|
+
return s && typeof s == "object" && !Array.isArray(s) ? typeof n != "object" || n === null ? !1 : E(
|
|
132
|
+
n,
|
|
133
|
+
s
|
|
134
|
+
) : n === s;
|
|
117
135
|
});
|
|
118
136
|
}
|
|
119
137
|
function N(e, t) {
|
|
120
138
|
if (e === t) return !0;
|
|
121
139
|
if (typeof e != "object" || e === null || typeof t != "object" || t === null)
|
|
122
140
|
return e === t;
|
|
123
|
-
const
|
|
124
|
-
return
|
|
125
|
-
if (!Object.prototype.hasOwnProperty.call(e,
|
|
126
|
-
const
|
|
127
|
-
return typeof
|
|
141
|
+
const o = Object.keys(e), s = Object.keys(t);
|
|
142
|
+
return o.length !== s.length ? !1 : s.every((n) => {
|
|
143
|
+
if (!Object.prototype.hasOwnProperty.call(e, n)) return !1;
|
|
144
|
+
const c = e, r = t, i = c[n], l = r[n];
|
|
145
|
+
return typeof i == "object" && i !== null && typeof l == "object" && l !== null ? N(i, l) : i === l;
|
|
128
146
|
});
|
|
129
147
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
t.constructor
|
|
139
|
-
);
|
|
140
|
-
if (i) {
|
|
141
|
-
e.debugLogger.log(
|
|
142
|
-
`Found ${i.length} mock(s) for ${t.constructor.name}`
|
|
143
|
-
);
|
|
144
|
-
const s = i.findIndex((r) => r.strict ? r.matcher && N(t.input, r.matcher) : !r.matcher || $(t.input, r.matcher));
|
|
145
|
-
if (s === -1) {
|
|
146
|
-
e.debugLogger.log(
|
|
147
|
-
`No matching mock found for ${t.constructor.name}`,
|
|
148
|
-
t.input
|
|
149
|
-
);
|
|
150
|
-
const r = i.map((l, u) => {
|
|
151
|
-
const g = l.matcher ? JSON.stringify(l.matcher, void 0, 2) : "any input", a = l.strict ? " (strict mode)" : "";
|
|
152
|
-
return ` Mock #${u + 1}: ${g}${a}`;
|
|
153
|
-
}).join(`
|
|
154
|
-
`), c = JSON.stringify(t.input, void 0, 2);
|
|
155
|
-
throw new Error(
|
|
156
|
-
`No matching mock found for ${t.constructor.name}.
|
|
148
|
+
function Y(e, t, o) {
|
|
149
|
+
const s = t.map((c, r) => {
|
|
150
|
+
const i = c.matcher ? JSON.stringify(c.matcher, void 0, 2) : "any input", l = c.strict ? " (strict mode)" : "";
|
|
151
|
+
return ` Mock #${r + 1}: ${i}${l}`;
|
|
152
|
+
}).join(`
|
|
153
|
+
`), n = JSON.stringify(o, void 0, 2);
|
|
154
|
+
return new Error(
|
|
155
|
+
`No matching mock found for ${e}.
|
|
157
156
|
|
|
158
|
-
Found ${
|
|
157
|
+
Found ${t.length} mock(s) but none matched the input.
|
|
159
158
|
|
|
160
159
|
Configured mocks:
|
|
161
|
-
${
|
|
160
|
+
${s}
|
|
162
161
|
|
|
163
162
|
Received input:
|
|
164
|
-
${
|
|
163
|
+
${n}
|
|
165
164
|
|
|
166
165
|
Tip: Enable debug mode with enableDebug() for detailed matching information.`
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
`Using mock at index ${s} for ${t.constructor.name}`
|
|
174
|
-
), r.once && (i.splice(s, 1), e.debugLogger.log(
|
|
175
|
-
`Removed one-time mock for ${t.constructor.name}`
|
|
176
|
-
)), r.handler(
|
|
177
|
-
t.input,
|
|
178
|
-
n()
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
} else
|
|
182
|
-
e.debugLogger.log(
|
|
183
|
-
`No mocks configured for ${t.constructor.name}`
|
|
184
|
-
);
|
|
185
|
-
const o = JSON.stringify(t.input, void 0, 2);
|
|
186
|
-
throw new Error(
|
|
187
|
-
`No mock configured for command: ${t.constructor.name}.
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
function Z(e, t) {
|
|
169
|
+
const o = JSON.stringify(t, void 0, 2);
|
|
170
|
+
return new Error(
|
|
171
|
+
`No mock configured for command: ${e}.
|
|
188
172
|
|
|
189
173
|
Received input:
|
|
190
174
|
${o}
|
|
191
175
|
|
|
192
|
-
Did you forget to call mockClient.on(${
|
|
176
|
+
Did you forget to call mockClient.on(${e})?`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
function ee(e, t) {
|
|
180
|
+
return e.findIndex((o) => o.strict ? o.matcher && N(t, o.matcher) : !o.matcher || E(t, o.matcher));
|
|
181
|
+
}
|
|
182
|
+
function x(e) {
|
|
183
|
+
return async function(t) {
|
|
184
|
+
const o = () => this, s = m(e.debugLogger), n = t.constructor.name;
|
|
185
|
+
s && e.debugLogger.logDirect(
|
|
186
|
+
`Received command: ${n}`,
|
|
187
|
+
t.input
|
|
188
|
+
);
|
|
189
|
+
const c = e.map.get(
|
|
190
|
+
t.constructor
|
|
191
|
+
);
|
|
192
|
+
if (!c)
|
|
193
|
+
throw s && e.debugLogger.logDirect(
|
|
194
|
+
`No mocks configured for ${n}`
|
|
195
|
+
), Z(n, t.input);
|
|
196
|
+
s && e.debugLogger.logDirect(
|
|
197
|
+
`Found ${c.length} mock(s) for ${n}`
|
|
193
198
|
);
|
|
199
|
+
const r = ee(c, t.input);
|
|
200
|
+
if (r === -1)
|
|
201
|
+
throw s && e.debugLogger.logDirect(
|
|
202
|
+
`No matching mock found for ${n}`,
|
|
203
|
+
t.input
|
|
204
|
+
), Y(n, c, t.input);
|
|
205
|
+
const i = c[r];
|
|
206
|
+
if (!i)
|
|
207
|
+
throw new Error(`Mock at index ${r} not found`);
|
|
208
|
+
return s && e.debugLogger.logDirect(
|
|
209
|
+
`Using mock at index ${r} for ${n}`
|
|
210
|
+
), i.once && (c.splice(r, 1), s && e.debugLogger.logDirect(
|
|
211
|
+
`Removed one-time mock for ${n}`
|
|
212
|
+
)), i.handler(t.input, o());
|
|
194
213
|
};
|
|
195
214
|
}
|
|
196
|
-
|
|
197
|
-
|
|
215
|
+
const D = (e, t, o) => ({
|
|
216
|
+
reset() {
|
|
217
|
+
m(e.debugLogger) && e.debugLogger.logDirect(o.reset), t.mockClear();
|
|
218
|
+
},
|
|
219
|
+
restore() {
|
|
220
|
+
m(e.debugLogger) && e.debugLogger.logDirect(o.restore), t.mockRestore(), e.map = /* @__PURE__ */ new WeakMap();
|
|
221
|
+
},
|
|
222
|
+
calls() {
|
|
223
|
+
return t.mock.calls.map((s) => s[0]);
|
|
224
|
+
},
|
|
225
|
+
__rawCalls() {
|
|
226
|
+
return t.mock.calls;
|
|
227
|
+
},
|
|
228
|
+
enableDebug() {
|
|
229
|
+
V(e.debugLogger);
|
|
230
|
+
},
|
|
231
|
+
disableDebug() {
|
|
232
|
+
_(e.debugLogger);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
function L(e, t, o, s = {}) {
|
|
236
|
+
const n = (r, i, l) => {
|
|
198
237
|
const u = {
|
|
199
|
-
matcher:
|
|
238
|
+
matcher: o,
|
|
200
239
|
handler: r,
|
|
201
|
-
once:
|
|
202
|
-
strict: !!
|
|
203
|
-
},
|
|
204
|
-
if (
|
|
205
|
-
const
|
|
206
|
-
|
|
240
|
+
once: i,
|
|
241
|
+
strict: !!s.strict
|
|
242
|
+
}, a = e.map.get(t) ?? [], f = m(e.debugLogger);
|
|
243
|
+
if (i) {
|
|
244
|
+
const g = a.findIndex((h) => !h.once);
|
|
245
|
+
g === -1 ? a.push(u) : a.splice(g, 0, u), e.map.set(
|
|
207
246
|
t,
|
|
208
|
-
|
|
209
|
-
), e.debugLogger.
|
|
247
|
+
a
|
|
248
|
+
), f && e.debugLogger.logDirect(
|
|
210
249
|
`Configured ${l}Once for ${t.name}`,
|
|
211
|
-
|
|
250
|
+
o ? { matcher: o, strict: !!s.strict } : void 0
|
|
212
251
|
);
|
|
213
252
|
} else {
|
|
214
|
-
const
|
|
215
|
-
(
|
|
253
|
+
const g = a.filter(
|
|
254
|
+
(h) => h.once || JSON.stringify(h.matcher) !== JSON.stringify(o)
|
|
216
255
|
);
|
|
217
|
-
|
|
256
|
+
g.push(u), e.map.set(
|
|
218
257
|
t,
|
|
219
|
-
|
|
220
|
-
), e.debugLogger.
|
|
258
|
+
g
|
|
259
|
+
), f && e.debugLogger.logDirect(
|
|
221
260
|
`Configured ${l} for ${t.name}`,
|
|
222
|
-
|
|
261
|
+
o ? { matcher: o, strict: !!s.strict } : void 0
|
|
223
262
|
);
|
|
224
263
|
}
|
|
225
|
-
},
|
|
264
|
+
}, c = {
|
|
226
265
|
resolves(r) {
|
|
227
|
-
return
|
|
266
|
+
return n(() => Promise.resolve(r), !1, "resolves"), c;
|
|
228
267
|
},
|
|
229
268
|
rejects(r) {
|
|
230
|
-
return
|
|
269
|
+
return n(
|
|
231
270
|
() => {
|
|
232
|
-
const
|
|
233
|
-
return Promise.reject(
|
|
271
|
+
const i = typeof r == "string" ? new Error(r) : r;
|
|
272
|
+
return Promise.reject(i);
|
|
234
273
|
},
|
|
235
274
|
!1,
|
|
236
275
|
"rejects"
|
|
237
|
-
),
|
|
276
|
+
), c;
|
|
238
277
|
},
|
|
239
278
|
callsFake(r) {
|
|
240
|
-
return
|
|
279
|
+
return n(r, !1, "callsFake"), c;
|
|
241
280
|
},
|
|
242
281
|
resolvesOnce(r) {
|
|
243
|
-
return
|
|
282
|
+
return n(() => Promise.resolve(r), !0, "resolves"), c;
|
|
244
283
|
},
|
|
245
284
|
rejectsOnce(r) {
|
|
246
|
-
return
|
|
285
|
+
return n(
|
|
247
286
|
() => {
|
|
248
|
-
const
|
|
249
|
-
return Promise.reject(
|
|
287
|
+
const i = typeof r == "string" ? new Error(r) : r;
|
|
288
|
+
return Promise.reject(i);
|
|
250
289
|
},
|
|
251
290
|
!0,
|
|
252
291
|
"rejects"
|
|
253
|
-
),
|
|
292
|
+
), c;
|
|
254
293
|
},
|
|
255
294
|
callsFakeOnce(r) {
|
|
256
|
-
return
|
|
295
|
+
return n(r, !0, "callsFake"), c;
|
|
257
296
|
},
|
|
258
297
|
resolvesStream(r) {
|
|
259
|
-
return
|
|
260
|
-
() => Promise.resolve({
|
|
298
|
+
return n(
|
|
299
|
+
() => Promise.resolve({
|
|
300
|
+
Body: S(r)
|
|
301
|
+
}),
|
|
261
302
|
!1,
|
|
262
303
|
"resolvesStream"
|
|
263
|
-
),
|
|
304
|
+
), c;
|
|
264
305
|
},
|
|
265
306
|
resolvesStreamOnce(r) {
|
|
266
|
-
return
|
|
267
|
-
() => Promise.resolve({
|
|
307
|
+
return n(
|
|
308
|
+
() => Promise.resolve({
|
|
309
|
+
Body: S(r)
|
|
310
|
+
}),
|
|
268
311
|
!0,
|
|
269
312
|
"resolvesStream"
|
|
270
|
-
),
|
|
313
|
+
), c;
|
|
271
314
|
},
|
|
272
|
-
resolvesWithDelay(r,
|
|
315
|
+
resolvesWithDelay(r, i) {
|
|
273
316
|
const l = (u) => {
|
|
274
|
-
setTimeout(() => u(r),
|
|
317
|
+
setTimeout(() => u(r), i);
|
|
275
318
|
};
|
|
276
|
-
return
|
|
319
|
+
return n(
|
|
320
|
+
() => new Promise(l),
|
|
321
|
+
!1,
|
|
322
|
+
"resolvesWithDelay"
|
|
323
|
+
), c;
|
|
277
324
|
},
|
|
278
|
-
rejectsWithDelay(r,
|
|
279
|
-
const l = typeof r == "string" ? new Error(r) : r, u = (
|
|
280
|
-
setTimeout(() =>
|
|
325
|
+
rejectsWithDelay(r, i) {
|
|
326
|
+
const l = typeof r == "string" ? new Error(r) : r, u = (a, f) => {
|
|
327
|
+
setTimeout(() => f(l), i);
|
|
281
328
|
};
|
|
282
|
-
return
|
|
329
|
+
return n(() => new Promise(u), !1, "rejectsWithDelay"), c;
|
|
283
330
|
},
|
|
284
331
|
rejectsWithNoSuchKey(r) {
|
|
285
|
-
return
|
|
286
|
-
() => Promise.reject(
|
|
332
|
+
return n(
|
|
333
|
+
() => Promise.reject(T(r)),
|
|
287
334
|
!1,
|
|
288
335
|
"rejectsWithNoSuchKey"
|
|
289
|
-
),
|
|
336
|
+
), c;
|
|
290
337
|
},
|
|
291
338
|
rejectsWithNoSuchBucket(r) {
|
|
292
|
-
return
|
|
293
|
-
() => Promise.reject(
|
|
339
|
+
return n(
|
|
340
|
+
() => Promise.reject(M(r)),
|
|
294
341
|
!1,
|
|
295
342
|
"rejectsWithNoSuchBucket"
|
|
296
|
-
),
|
|
343
|
+
), c;
|
|
297
344
|
},
|
|
298
345
|
rejectsWithAccessDenied(r) {
|
|
299
|
-
return
|
|
300
|
-
() => Promise.reject(
|
|
346
|
+
return n(
|
|
347
|
+
() => Promise.reject(K(r)),
|
|
301
348
|
!1,
|
|
302
349
|
"rejectsWithAccessDenied"
|
|
303
|
-
),
|
|
350
|
+
), c;
|
|
304
351
|
},
|
|
305
352
|
rejectsWithResourceNotFound(r) {
|
|
306
|
-
return
|
|
307
|
-
() => Promise.reject(
|
|
353
|
+
return n(
|
|
354
|
+
() => Promise.reject(A(r)),
|
|
308
355
|
!1,
|
|
309
356
|
"rejectsWithResourceNotFound"
|
|
310
|
-
),
|
|
357
|
+
), c;
|
|
311
358
|
},
|
|
312
359
|
rejectsWithConditionalCheckFailed() {
|
|
313
|
-
return
|
|
314
|
-
() => Promise.reject(
|
|
360
|
+
return n(
|
|
361
|
+
() => Promise.reject(B()),
|
|
315
362
|
!1,
|
|
316
363
|
"rejectsWithConditionalCheckFailed"
|
|
317
|
-
),
|
|
364
|
+
), c;
|
|
318
365
|
},
|
|
319
366
|
rejectsWithThrottling() {
|
|
320
|
-
return
|
|
321
|
-
() => Promise.reject(
|
|
367
|
+
return n(
|
|
368
|
+
() => Promise.reject(J()),
|
|
322
369
|
!1,
|
|
323
370
|
"rejectsWithThrottling"
|
|
324
|
-
),
|
|
371
|
+
), c;
|
|
325
372
|
},
|
|
326
373
|
rejectsWithInternalServerError() {
|
|
327
|
-
return
|
|
328
|
-
() => Promise.reject(
|
|
374
|
+
return n(
|
|
375
|
+
() => Promise.reject(q()),
|
|
329
376
|
!1,
|
|
330
377
|
"rejectsWithInternalServerError"
|
|
331
|
-
),
|
|
378
|
+
), c;
|
|
332
379
|
},
|
|
333
|
-
resolvesPaginated(r,
|
|
334
|
-
const l =
|
|
380
|
+
resolvesPaginated(r, i = {}) {
|
|
381
|
+
const l = G(r, i);
|
|
335
382
|
let u = 0;
|
|
336
383
|
return e.debugLogger.log(
|
|
337
384
|
`Configured resolvesPaginated for ${t.name}`,
|
|
338
|
-
{ pageSize:
|
|
339
|
-
),
|
|
340
|
-
(
|
|
341
|
-
const
|
|
342
|
-
if (
|
|
343
|
-
const
|
|
344
|
-
let
|
|
345
|
-
for (const
|
|
346
|
-
const p =
|
|
385
|
+
{ pageSize: i.pageSize, itemsCount: r.length }
|
|
386
|
+
), n(
|
|
387
|
+
(a) => {
|
|
388
|
+
const f = i.tokenKey || "NextToken", g = i.inputTokenKey || f, b = a[g];
|
|
389
|
+
if (b != null) {
|
|
390
|
+
const R = i.itemsKey || "Items";
|
|
391
|
+
let v = 0;
|
|
392
|
+
for (const F of l) {
|
|
393
|
+
const p = F[R];
|
|
347
394
|
if (p && p.length > 0) {
|
|
348
395
|
const W = p[p.length - 1];
|
|
349
|
-
if (JSON.stringify(W) === JSON.stringify(
|
|
350
|
-
u =
|
|
396
|
+
if (JSON.stringify(W) === JSON.stringify(b)) {
|
|
397
|
+
u = v + 1;
|
|
351
398
|
break;
|
|
352
399
|
}
|
|
353
400
|
}
|
|
354
|
-
|
|
401
|
+
v++;
|
|
355
402
|
}
|
|
356
403
|
} else
|
|
357
404
|
u = 0;
|
|
358
|
-
const
|
|
405
|
+
const y = (
|
|
359
406
|
// eslint-disable-next-line security/detect-object-injection
|
|
360
407
|
l[u] || // eslint-disable-next-line unicorn/prefer-at -- TypeScript target doesn't support Array.at() method
|
|
361
408
|
l[l.length - 1] || l[0]
|
|
362
409
|
);
|
|
363
|
-
if (!
|
|
410
|
+
if (!y)
|
|
364
411
|
throw new Error("No paginated responses available");
|
|
365
|
-
return u = Math.min(u + 1, l.length - 1), Promise.resolve(
|
|
412
|
+
return u = Math.min(u + 1, l.length - 1), Promise.resolve(y);
|
|
366
413
|
},
|
|
367
414
|
!1,
|
|
368
415
|
"resolvesPaginated"
|
|
369
|
-
),
|
|
416
|
+
), c;
|
|
370
417
|
},
|
|
371
418
|
resolvesFromFile(r) {
|
|
372
419
|
return e.debugLogger.log(
|
|
373
420
|
`Configured resolvesFromFile for ${t.name}`,
|
|
374
421
|
{ filePath: r }
|
|
375
|
-
),
|
|
422
|
+
), n(
|
|
376
423
|
() => {
|
|
377
|
-
const
|
|
378
|
-
return Promise.resolve(
|
|
424
|
+
const i = U(r);
|
|
425
|
+
return Promise.resolve(i);
|
|
379
426
|
},
|
|
380
427
|
!1,
|
|
381
428
|
"resolvesFromFile"
|
|
382
|
-
),
|
|
429
|
+
), c;
|
|
383
430
|
}
|
|
384
431
|
};
|
|
385
|
-
return
|
|
432
|
+
return c;
|
|
386
433
|
}
|
|
387
|
-
const
|
|
434
|
+
const le = (e) => {
|
|
388
435
|
const t = {
|
|
389
436
|
map: /* @__PURE__ */ new WeakMap(),
|
|
390
|
-
debugLogger:
|
|
391
|
-
},
|
|
437
|
+
debugLogger: $()
|
|
438
|
+
}, o = e.prototype, s = j.spyOn(o, "send").mockImplementation(x(t)), n = D(t, s, {
|
|
439
|
+
reset: "Clearing call history (mocks preserved)",
|
|
440
|
+
restore: "Restoring original client behavior and clearing all mocks"
|
|
441
|
+
});
|
|
392
442
|
return {
|
|
393
443
|
client: void 0,
|
|
394
|
-
on: (
|
|
444
|
+
on: (r, i, l) => L(
|
|
395
445
|
t,
|
|
396
|
-
s,
|
|
397
446
|
r,
|
|
398
|
-
|
|
447
|
+
i,
|
|
448
|
+
l
|
|
399
449
|
),
|
|
400
|
-
|
|
401
|
-
t.debugLogger.log("Clearing call history (mocks preserved)"), i.mockClear();
|
|
402
|
-
},
|
|
403
|
-
restore: () => {
|
|
404
|
-
t.debugLogger.log(
|
|
405
|
-
"Restoring original client behavior and clearing all mocks"
|
|
406
|
-
), i.mockRestore(), t.map = /* @__PURE__ */ new WeakMap();
|
|
407
|
-
},
|
|
408
|
-
calls: () => i.mock.calls.map((s) => s[0]),
|
|
409
|
-
__rawCalls: () => i.mock.calls,
|
|
410
|
-
enableDebug: () => {
|
|
411
|
-
S(t.debugLogger);
|
|
412
|
-
},
|
|
413
|
-
disableDebug: () => {
|
|
414
|
-
w(t.debugLogger);
|
|
415
|
-
}
|
|
450
|
+
...n
|
|
416
451
|
};
|
|
417
|
-
},
|
|
452
|
+
}, ue = (e) => {
|
|
418
453
|
const t = {
|
|
419
454
|
map: /* @__PURE__ */ new WeakMap(),
|
|
420
|
-
debugLogger:
|
|
421
|
-
},
|
|
455
|
+
debugLogger: $()
|
|
456
|
+
}, o = j.spyOn(e, "send").mockImplementation(x(t)), s = D(t, o, {
|
|
457
|
+
reset: "Clearing call history (mocks preserved) for client instance",
|
|
458
|
+
restore: "Restoring original client behavior and clearing all mocks for client instance"
|
|
459
|
+
});
|
|
422
460
|
return {
|
|
423
461
|
client: e,
|
|
424
|
-
on: (
|
|
462
|
+
on: (c, r, i) => L(
|
|
425
463
|
t,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
464
|
+
c,
|
|
465
|
+
r,
|
|
466
|
+
i
|
|
429
467
|
),
|
|
430
|
-
|
|
431
|
-
t.debugLogger.log(
|
|
432
|
-
"Clearing call history (mocks preserved) for client instance"
|
|
433
|
-
), n.mockClear();
|
|
434
|
-
},
|
|
435
|
-
restore: () => {
|
|
436
|
-
t.debugLogger.log(
|
|
437
|
-
"Restoring original client behavior and clearing all mocks for client instance"
|
|
438
|
-
), n.mockRestore(), t.map = /* @__PURE__ */ new WeakMap();
|
|
439
|
-
},
|
|
440
|
-
calls: () => n.mock.calls.map((o) => o[0]),
|
|
441
|
-
__rawCalls: () => n.mock.calls,
|
|
442
|
-
enableDebug: () => {
|
|
443
|
-
S(t.debugLogger);
|
|
444
|
-
},
|
|
445
|
-
disableDebug: () => {
|
|
446
|
-
w(t.debugLogger);
|
|
447
|
-
}
|
|
468
|
+
...s
|
|
448
469
|
};
|
|
449
470
|
};
|
|
450
471
|
export {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
472
|
+
ge as matchers,
|
|
473
|
+
le as mockClient,
|
|
474
|
+
ue as mockClientInstance,
|
|
475
|
+
ie as setGlobalDebug
|
|
454
476
|
};
|
package/lib/mock-client.d.ts
CHANGED
|
@@ -3,6 +3,30 @@ import { HttpHandlerOptions, MetadataBearer } from '@smithy/types';
|
|
|
3
3
|
import { Mock } from 'vitest';
|
|
4
4
|
import { PaginatorOptions } from './utils/paginator-helpers.js';
|
|
5
5
|
import { StreamInput } from './utils/stream-helpers.js';
|
|
6
|
+
type DeepPartial<T> = T extends (...args: unknown[]) => unknown ? T : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends object ? {
|
|
7
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
8
|
+
} : T;
|
|
9
|
+
/**
|
|
10
|
+
* Set global debug mode for all mocks.
|
|
11
|
+
* When enabled, all mocks will log debug information unless explicitly disabled at the mock level.
|
|
12
|
+
*
|
|
13
|
+
* @param enabled - Whether to enable debug logging globally
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { setGlobalDebug, mockClient } from 'aws-sdk-vitest-mock';
|
|
18
|
+
* import { S3Client } from '@aws-sdk/client-s3';
|
|
19
|
+
*
|
|
20
|
+
* // Enable debug for all mocks
|
|
21
|
+
* setGlobalDebug(true);
|
|
22
|
+
*
|
|
23
|
+
* const s3Mock = mockClient(S3Client); // Automatically has debug enabled
|
|
24
|
+
*
|
|
25
|
+
* // Disable debug for a specific mock
|
|
26
|
+
* s3Mock.disableDebug(); // This mock won't log, but others will
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function setGlobalDebug(enabled: boolean): void;
|
|
6
30
|
export type StructuralCommand<TInput extends object, TOutput extends MetadataBearer> = SmithyCommand<TInput, TOutput, any, any, any> | {
|
|
7
31
|
readonly input: TInput;
|
|
8
32
|
readonly __awsSdkVitestMockOutput?: TOutput;
|
|
@@ -19,7 +43,7 @@ export type AwsSdkCommand = StructuralCommand<object, MetadataBearer>;
|
|
|
19
43
|
export type ClientConstructor<TClient extends AnyClient> = (abstract new (...args: unknown[]) => TClient) | {
|
|
20
44
|
prototype: TClient;
|
|
21
45
|
};
|
|
22
|
-
type CommandHandler<TInput extends object = object, TOutput extends MetadataBearer = MetadataBearer, TClient extends AnyClient = AnyClient> = (input: TInput, clientInstance: TClient | undefined) => Promise<
|
|
46
|
+
type CommandHandler<TInput extends object = object, TOutput extends MetadataBearer = MetadataBearer, TClient extends AnyClient = AnyClient> = (input: TInput, clientInstance: TClient | undefined) => Promise<DeepPartial<TOutput>>;
|
|
23
47
|
interface MockOptions {
|
|
24
48
|
strict?: boolean;
|
|
25
49
|
}
|
|
@@ -177,7 +201,7 @@ export interface AwsCommandStub<TInput extends object, TOutput extends MetadataB
|
|
|
177
201
|
* s3Mock.on(GetObjectCommand).resolves({ Body: 'file contents' });
|
|
178
202
|
* ```
|
|
179
203
|
*/
|
|
180
|
-
resolves: (output:
|
|
204
|
+
resolves: (output: DeepPartial<TOutput>) => AwsCommandStub<TInput, TOutput, TClient>;
|
|
181
205
|
/**
|
|
182
206
|
* Set a permanent mock rejection that will be used after all one-time handlers are consumed.
|
|
183
207
|
*
|
|
@@ -217,7 +241,7 @@ export interface AwsCommandStub<TInput extends object, TOutput extends MetadataB
|
|
|
217
241
|
* .resolvesOnce({ Body: 'second call' });
|
|
218
242
|
* ```
|
|
219
243
|
*/
|
|
220
|
-
resolvesOnce: (output:
|
|
244
|
+
resolvesOnce: (output: DeepPartial<TOutput>) => AwsCommandStub<TInput, TOutput, TClient>;
|
|
221
245
|
/**
|
|
222
246
|
* Add a one-time mock rejection that will be consumed in order.
|
|
223
247
|
*
|
|
@@ -284,7 +308,7 @@ export interface AwsCommandStub<TInput extends object, TOutput extends MetadataB
|
|
|
284
308
|
* s3Mock.on(GetObjectCommand).resolvesWithDelay({ Body: 'data' }, 1000);
|
|
285
309
|
* ```
|
|
286
310
|
*/
|
|
287
|
-
resolvesWithDelay: (output:
|
|
311
|
+
resolvesWithDelay: (output: DeepPartial<TOutput>, delayMs: number) => AwsCommandStub<TInput, TOutput, TClient>;
|
|
288
312
|
/**
|
|
289
313
|
* Set a permanent mock rejection with a delay in milliseconds.
|
|
290
314
|
*
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export interface DebugLogger {
|
|
2
2
|
enabled: boolean;
|
|
3
|
+
explicitlySet: boolean;
|
|
3
4
|
log: (message: string, data?: unknown) => void;
|
|
5
|
+
logDirect: (message: string, data?: unknown) => void;
|
|
4
6
|
}
|
|
5
|
-
export declare
|
|
6
|
-
export declare
|
|
7
|
-
export declare
|
|
7
|
+
export declare const createDebugLogger: (initialEnabled?: boolean) => DebugLogger;
|
|
8
|
+
export declare const enableDebug: (logger: DebugLogger) => void;
|
|
9
|
+
export declare const disableDebug: (logger: DebugLogger) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const loadFixture: (filePath: string) => unknown;
|
|
@@ -95,4 +95,4 @@ export interface PaginatedResponse<T = unknown> {
|
|
|
95
95
|
* // ]
|
|
96
96
|
* ```
|
|
97
97
|
*/
|
|
98
|
-
export declare
|
|
98
|
+
export declare const createPaginatedResponses: <T>(items: T[], options?: PaginatorOptions) => PaginatedResponse<T>[];
|
|
@@ -3,4 +3,4 @@ export type StreamInput = string | Buffer | Uint8Array;
|
|
|
3
3
|
/**
|
|
4
4
|
* Creates an appropriate stream for the current environment
|
|
5
5
|
*/
|
|
6
|
-
export declare
|
|
6
|
+
export declare const createStream: (data: StreamInput) => Readable | ReadableStream<Uint8Array>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const e={red:t=>`\x1B[31m${t}\x1B[39m`,green:t=>`\x1B[32m${t}\x1B[39m`,yellow:t=>`\x1B[33m${t}\x1B[39m`,blue:t=>`\x1B[34m${t}\x1B[39m`,magenta:t=>`\x1B[35m${t}\x1B[39m`,cyan:t=>`\x1B[36m${t}\x1B[39m`,gray:t=>`\x1B[90m${t}\x1B[39m`,bold:t=>`\x1B[1m${t}\x1B[22m`},$=t=>{const c=t.__rawCalls();return Array.isArray(c)?c.filter(a=>Array.isArray(a)&&a.length>0):[]},f={toHaveReceivedCommand(t,c){const a=$(t),r=a.some(o=>o
|
|
1
|
+
"use strict";const e={red:t=>`\x1B[31m${t}\x1B[39m`,green:t=>`\x1B[32m${t}\x1B[39m`,yellow:t=>`\x1B[33m${t}\x1B[39m`,blue:t=>`\x1B[34m${t}\x1B[39m`,magenta:t=>`\x1B[35m${t}\x1B[39m`,cyan:t=>`\x1B[36m${t}\x1B[39m`,gray:t=>`\x1B[90m${t}\x1B[39m`,bold:t=>`\x1B[1m${t}\x1B[22m`},$=t=>{const c=t.__rawCalls();return Array.isArray(c)?c.filter(a=>Array.isArray(a)&&a.length>0):[]},f={toHaveReceivedCommand(t,c){const a=$(t),r=a.some(([o])=>o instanceof c),m=c.name;return{pass:r,message:()=>{if(r)return`Expected AWS SDK mock not to have received command ${e.red(m)}`;const o=a.map(([n])=>n.constructor?.name??"Unknown");return o.length===0?`Expected AWS SDK mock to have received command ${e.red(m)}, but ${e.gray("no commands were received")}`:`Expected AWS SDK mock to have received command ${e.red(m)}, but received: ${e.yellow(o.join(", "))}`}}},toHaveReceivedCommandTimes(t,c,a){const r=$(t).filter(n=>n[0]instanceof c),m=r.length===a,o=c.name;return{pass:m,message:()=>m?`Expected AWS SDK mock not to have received command ${o} ${a} times`:`Expected AWS SDK mock to have received command ${o} ${a} times, but received ${r.length} times`}},toHaveReceivedCommandWith(t,c,a){const r=$(t).filter(n=>n[0]instanceof c),m=r.some(n=>this.equals(n[0].input,a)),o=c.name;return{pass:m,message:()=>{if(m){const s=e.red(o),u=e.cyan(JSON.stringify(a,void 0,2));return`Expected AWS SDK mock not to have received command ${s} with input:
|
|
2
2
|
${u}`}if(r.length===0){const s=e.red(o),u=e.cyan(JSON.stringify(a,void 0,2)),i=e.gray(`${o} was never called`);return`Expected AWS SDK mock to have received command ${s} with input:
|
|
3
3
|
${u}
|
|
4
4
|
|
|
@@ -31,13 +31,13 @@ const e = {
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
toHaveReceivedCommand(t, c) {
|
|
34
|
-
const a = $(t), r = a.some((o) => o
|
|
34
|
+
const a = $(t), r = a.some(([o]) => o instanceof c), m = c.name;
|
|
35
35
|
return {
|
|
36
36
|
pass: r,
|
|
37
37
|
message: () => {
|
|
38
38
|
if (r)
|
|
39
39
|
return `Expected AWS SDK mock not to have received command ${e.red(m)}`;
|
|
40
|
-
const o = a.map((n) => n
|
|
40
|
+
const o = a.map(([n]) => n.constructor?.name ?? "Unknown");
|
|
41
41
|
return o.length === 0 ? `Expected AWS SDK mock to have received command ${e.red(m)}, but ${e.gray("no commands were received")}` : `Expected AWS SDK mock to have received command ${e.red(m)}, but received: ${e.yellow(o.join(", "))}`;
|
|
42
42
|
}
|
|
43
43
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aws-sdk-vitest-mock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.cjs",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@swc-node/register": "1.11.1",
|
|
56
56
|
"@swc/core": "1.15.3",
|
|
57
57
|
"@swc/helpers": "0.5.17",
|
|
58
|
+
"@types/eslint-plugin-security": "3.0.0",
|
|
58
59
|
"@types/node": "24.10.3",
|
|
59
60
|
"@typescript-eslint/parser": "8.49.0",
|
|
60
61
|
"@vitest/coverage-v8": "4.0.15",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"eslint-plugin-sonarjs": "3.0.5",
|
|
67
68
|
"eslint-plugin-unicorn": "62.0.0",
|
|
68
69
|
"husky": "9.1.7",
|
|
70
|
+
"jiti": "2.6.1",
|
|
69
71
|
"lint-staged": "16.2.7",
|
|
70
72
|
"nx": "22.2.2",
|
|
71
73
|
"prettier": "3.7.4",
|
package/vitest-setup.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const e=require("vitest"),t=require("./matchers-
|
|
1
|
+
"use strict";const e=require("vitest"),t=require("./matchers-CNhdB_9q.cjs");e.expect.extend(t.matchers);
|
package/vitest-setup.js
CHANGED