aws-sdk-vitest-mock 0.3.0 → 0.4.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 +136 -86
- package/index.cjs +1 -1
- package/index.js +34 -33
- package/lib/utils/paginator-helpers.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ pnpm add -D aws-sdk-vitest-mock
|
|
|
43
43
|
|
|
44
44
|
### Basic Usage
|
|
45
45
|
|
|
46
|
+
> **Note:** `mockClient()` mocks **all instances** of a client class. Use `mockClientInstance()` when you need to mock a specific instance.
|
|
47
|
+
|
|
46
48
|
```typescript
|
|
47
49
|
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
48
50
|
import { mockClient } from "aws-sdk-vitest-mock";
|
|
@@ -65,10 +67,10 @@ describe("DocumentService", () => {
|
|
|
65
67
|
let documentService: DocumentService;
|
|
66
68
|
|
|
67
69
|
beforeEach(() => {
|
|
68
|
-
// Mock
|
|
70
|
+
// Mock all instances of S3Client
|
|
69
71
|
s3Mock = mockClient(S3Client);
|
|
70
72
|
|
|
71
|
-
//
|
|
73
|
+
// Any S3Client instance created after this will be mocked
|
|
72
74
|
const s3Client = new S3Client({ region: "us-east-1" });
|
|
73
75
|
documentService = new DocumentService(s3Client);
|
|
74
76
|
});
|
|
@@ -93,6 +95,18 @@ describe("DocumentService", () => {
|
|
|
93
95
|
});
|
|
94
96
|
```
|
|
95
97
|
|
|
98
|
+
## 🎯 Key Concepts
|
|
99
|
+
|
|
100
|
+
Understanding these concepts will help you use the library effectively:
|
|
101
|
+
|
|
102
|
+
- **`mockClient(ClientClass)`** - Mocks **all instances** of a client class. Use this in most test scenarios where you control client creation.
|
|
103
|
+
- **`mockClientInstance(instance)`** - Mocks a **specific client instance**. Use when the client is created outside your test (e.g., in application bootstrap).
|
|
104
|
+
- **Command Matching** - Commands are matched by constructor. Optionally match by input properties (partial matching by default, strict matching available).
|
|
105
|
+
- **Sequential Responses** - Use `resolvesOnce()` / `rejectsOnce()` for one-time behaviors that fall back to permanent handlers set with `resolves()` / `rejects()`.
|
|
106
|
+
- **Chainable API** - All mock configuration methods return the stub, allowing method chaining for cleaner test setup.
|
|
107
|
+
|
|
108
|
+
## 📖 Usage Guide
|
|
109
|
+
|
|
96
110
|
### Request Matching
|
|
97
111
|
|
|
98
112
|
```typescript
|
|
@@ -121,56 +135,66 @@ s3Mock
|
|
|
121
135
|
// All other calls return 'subsequent calls'
|
|
122
136
|
```
|
|
123
137
|
|
|
124
|
-
###
|
|
125
|
-
|
|
126
|
-
Load mock responses from files for easier test data management:
|
|
138
|
+
### Error Handling
|
|
127
139
|
|
|
128
140
|
```typescript
|
|
129
|
-
|
|
130
|
-
s3Mock.on(GetObjectCommand).resolvesFromFile("./fixtures/s3-response.json");
|
|
141
|
+
s3Mock.on(GetObjectCommand).rejects(new Error("Not found"));
|
|
131
142
|
|
|
132
|
-
//
|
|
133
|
-
s3Mock
|
|
143
|
+
// Or with rejectsOnce
|
|
144
|
+
s3Mock
|
|
145
|
+
.on(GetObjectCommand)
|
|
146
|
+
.rejectsOnce(new Error("Temporary failure"))
|
|
147
|
+
.resolves({ Body: "success" });
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Custom Handlers
|
|
134
151
|
|
|
135
|
-
|
|
136
|
-
|
|
152
|
+
```typescript
|
|
153
|
+
s3Mock.on(GetObjectCommand).callsFake(async (input, getClient) => {
|
|
154
|
+
const client = getClient();
|
|
155
|
+
console.log("Bucket:", input.Bucket);
|
|
156
|
+
return { Body: `Dynamic response for ${input.Key}` };
|
|
157
|
+
});
|
|
137
158
|
```
|
|
138
159
|
|
|
139
|
-
###
|
|
160
|
+
### Mocking Existing Instances
|
|
140
161
|
|
|
141
|
-
|
|
162
|
+
Use `mockClientInstance()` when you need to mock a client that's already been created:
|
|
142
163
|
|
|
143
164
|
```typescript
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}));
|
|
165
|
+
// Your application service that uses an injected S3 client
|
|
166
|
+
class FileUploadService {
|
|
167
|
+
constructor(private s3Client: S3Client) {}
|
|
148
168
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
169
|
+
async uploadFile(bucket: string, key: string, data: string) {
|
|
170
|
+
return await this.s3Client.send(
|
|
171
|
+
new PutObjectCommand({ Bucket: bucket, Key: key, Body: data }),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
154
175
|
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
176
|
+
test("should mock existing S3 client instance", async () => {
|
|
177
|
+
// Client is already created (e.g., in application bootstrap)
|
|
178
|
+
const s3Client = new S3Client({ region: "us-east-1" });
|
|
179
|
+
const service = new FileUploadService(s3Client);
|
|
158
180
|
|
|
159
|
-
// Mock
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
}));
|
|
181
|
+
// Mock the specific client instance
|
|
182
|
+
const mock = mockClientInstance(s3Client);
|
|
183
|
+
mock.on(PutObjectCommand).resolves({ ETag: "mock-etag" });
|
|
163
184
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
// Test your service
|
|
186
|
+
const result = await service.uploadFile("bucket", "key", "data");
|
|
187
|
+
|
|
188
|
+
expect(result.ETag).toBe("mock-etag");
|
|
189
|
+
expect(mock).toHaveReceivedCommand(PutObjectCommand);
|
|
168
190
|
});
|
|
169
191
|
```
|
|
170
192
|
|
|
193
|
+
## 🔧 AWS Service Examples
|
|
194
|
+
|
|
171
195
|
### DynamoDB with Marshal/Unmarshal
|
|
172
196
|
|
|
173
|
-
Mock DynamoDB operations using
|
|
197
|
+
Mock DynamoDB operations using marshal/unmarshal utilities for type-safe data handling:
|
|
174
198
|
|
|
175
199
|
```typescript
|
|
176
200
|
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
@@ -265,7 +289,9 @@ describe("UserService with DynamoDB", () => {
|
|
|
265
289
|
});
|
|
266
290
|
```
|
|
267
291
|
|
|
268
|
-
|
|
292
|
+
## 🚀 Advanced Features
|
|
293
|
+
|
|
294
|
+
### Stream Mocking (S3)
|
|
269
295
|
|
|
270
296
|
Mock S3 operations that return streams with automatic environment detection:
|
|
271
297
|
|
|
@@ -283,21 +309,70 @@ s3Mock
|
|
|
283
309
|
.resolvesStream("Subsequent calls");
|
|
284
310
|
```
|
|
285
311
|
|
|
286
|
-
###
|
|
312
|
+
### Paginator Support
|
|
287
313
|
|
|
288
|
-
|
|
314
|
+
Mock AWS SDK v3 pagination with automatic token handling:
|
|
289
315
|
|
|
290
316
|
```typescript
|
|
291
|
-
//
|
|
292
|
-
|
|
317
|
+
// Mock DynamoDB scan with pagination
|
|
318
|
+
// DynamoDB uses different keys for input (ExclusiveStartKey) and output (LastEvaluatedKey)
|
|
319
|
+
const items = Array.from({ length: 25 }, (_, i) => ({
|
|
320
|
+
id: { S: `item-${i + 1}` },
|
|
321
|
+
}));
|
|
293
322
|
|
|
294
|
-
|
|
295
|
-
|
|
323
|
+
dynamoMock.on(ScanCommand).resolvesPaginated(items, {
|
|
324
|
+
pageSize: 10,
|
|
325
|
+
itemsKey: "Items",
|
|
326
|
+
tokenKey: "LastEvaluatedKey", // Token key in response
|
|
327
|
+
inputTokenKey: "ExclusiveStartKey", // Token key in request (when different from response)
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// First call returns items 1-10 with LastEvaluatedKey
|
|
331
|
+
const result1 = await client.send(new ScanCommand({ TableName: "test" }));
|
|
332
|
+
// result1.LastEvaluatedKey = "token-10"
|
|
333
|
+
|
|
334
|
+
// Second call with ExclusiveStartKey returns items 11-20
|
|
335
|
+
const result2 = await client.send(
|
|
336
|
+
new ScanCommand({
|
|
337
|
+
TableName: "test",
|
|
338
|
+
ExclusiveStartKey: result1.LastEvaluatedKey,
|
|
339
|
+
}),
|
|
340
|
+
);
|
|
341
|
+
// result2.LastEvaluatedKey = "token-20"
|
|
342
|
+
|
|
343
|
+
// Third call returns items 21-25 without LastEvaluatedKey
|
|
344
|
+
const result3 = await client.send(
|
|
345
|
+
new ScanCommand({
|
|
346
|
+
TableName: "test",
|
|
347
|
+
ExclusiveStartKey: result2.LastEvaluatedKey,
|
|
348
|
+
}),
|
|
349
|
+
);
|
|
350
|
+
// result3.LastEvaluatedKey = undefined (no more pages)
|
|
351
|
+
|
|
352
|
+
// Mock S3 list objects with pagination
|
|
353
|
+
// S3 uses the same key for input and output, so inputTokenKey is optional
|
|
354
|
+
const objects = Array.from({ length: 15 }, (_, i) => ({
|
|
355
|
+
Key: `file-${i + 1}.txt`,
|
|
356
|
+
}));
|
|
357
|
+
|
|
358
|
+
s3Mock.on(ListObjectsV2Command).resolvesPaginated(objects, {
|
|
359
|
+
pageSize: 10,
|
|
360
|
+
itemsKey: "Contents",
|
|
361
|
+
tokenKey: "NextContinuationToken", // Used for both input and output
|
|
362
|
+
});
|
|
296
363
|
```
|
|
297
364
|
|
|
365
|
+
**Pagination Options:**
|
|
366
|
+
|
|
367
|
+
- `pageSize` - Number of items per page (default: 10)
|
|
368
|
+
- `itemsKey` - Property name for items array in response (default: "Items")
|
|
369
|
+
- `tokenKey` - Property name for pagination token in response (default: "NextToken")
|
|
370
|
+
- `inputTokenKey` - Property name for pagination token in request (default: same as `tokenKey`)
|
|
371
|
+
- Use this when AWS service uses different names for input/output tokens (e.g., DynamoDB's `ExclusiveStartKey` vs `LastEvaluatedKey`)
|
|
372
|
+
|
|
298
373
|
### AWS Error Simulation
|
|
299
374
|
|
|
300
|
-
Convenient methods for common AWS errors:
|
|
375
|
+
Convenient helper methods for common AWS errors:
|
|
301
376
|
|
|
302
377
|
```typescript
|
|
303
378
|
// S3 Errors
|
|
@@ -314,61 +389,34 @@ s3Mock.on(GetObjectCommand).rejectsWithThrottling();
|
|
|
314
389
|
s3Mock.on(GetObjectCommand).rejectsWithInternalServerError();
|
|
315
390
|
```
|
|
316
391
|
|
|
317
|
-
###
|
|
392
|
+
### Delay/Latency Simulation
|
|
393
|
+
|
|
394
|
+
Simulate network delays for testing timeouts and race conditions:
|
|
318
395
|
|
|
319
396
|
```typescript
|
|
320
|
-
|
|
397
|
+
// Resolve with delay
|
|
398
|
+
s3Mock.on(GetObjectCommand).resolvesWithDelay({ Body: "data" }, 1000);
|
|
321
399
|
|
|
322
|
-
//
|
|
323
|
-
s3Mock
|
|
324
|
-
.on(GetObjectCommand)
|
|
325
|
-
.rejectsOnce(new Error("Temporary failure"))
|
|
326
|
-
.resolves({ Body: "success" });
|
|
400
|
+
// Reject with delay
|
|
401
|
+
s3Mock.on(GetObjectCommand).rejectsWithDelay("Network timeout", 500);
|
|
327
402
|
```
|
|
328
403
|
|
|
329
|
-
###
|
|
330
|
-
|
|
331
|
-
```typescript
|
|
332
|
-
s3Mock.on(GetObjectCommand).callsFake(async (input, getClient) => {
|
|
333
|
-
const client = getClient();
|
|
334
|
-
console.log("Bucket:", input.Bucket);
|
|
335
|
-
return { Body: `Dynamic response for ${input.Key}` };
|
|
336
|
-
});
|
|
337
|
-
```
|
|
404
|
+
### Fixture Loading
|
|
338
405
|
|
|
339
|
-
|
|
406
|
+
Load mock responses from files for easier test data management:
|
|
340
407
|
|
|
341
408
|
```typescript
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
constructor(private s3Client: S3Client) {}
|
|
345
|
-
|
|
346
|
-
async uploadFile(bucket: string, key: string, data: string) {
|
|
347
|
-
return await this.s3Client.send(
|
|
348
|
-
new PutObjectCommand({ Bucket: bucket, Key: key, Body: data }),
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
test("should mock existing S3 client instance", async () => {
|
|
354
|
-
// Create the client your application will use
|
|
355
|
-
const s3Client = new S3Client({ region: "us-east-1" });
|
|
356
|
-
const service = new FileUploadService(s3Client);
|
|
357
|
-
|
|
358
|
-
// Mock the existing client instance
|
|
359
|
-
const mock = mockClientInstance(s3Client);
|
|
360
|
-
mock.on(PutObjectCommand).resolves({ ETag: "mock-etag" });
|
|
361
|
-
|
|
362
|
-
// Test your service
|
|
363
|
-
const result = await service.uploadFile("bucket", "key", "data");
|
|
409
|
+
// Load JSON response from file (automatically parsed)
|
|
410
|
+
s3Mock.on(GetObjectCommand).resolvesFromFile("./fixtures/s3-response.json");
|
|
364
411
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
});
|
|
412
|
+
// Load text response from file (returned as string)
|
|
413
|
+
s3Mock.on(GetObjectCommand).resolvesFromFile("./fixtures/response.txt");
|
|
368
414
|
```
|
|
369
415
|
|
|
370
416
|
### Debug Mode
|
|
371
417
|
|
|
418
|
+
Enable debug logging to troubleshoot mock configurations when they're not matching as expected:
|
|
419
|
+
|
|
372
420
|
Enable debug logging to troubleshoot mock configurations and see detailed information about command matching:
|
|
373
421
|
|
|
374
422
|
```typescript
|
|
@@ -543,9 +591,11 @@ bun nx build
|
|
|
543
591
|
|
|
544
592
|
See [CONTRIBUTING.md](./CONTRIBUTING.md) for the complete guide.
|
|
545
593
|
|
|
546
|
-
##
|
|
594
|
+
## Acknowledgements
|
|
595
|
+
|
|
596
|
+
This library is based on the core ideas and API patterns introduced by [aws-sdk-client-mock](https://github.com/m-radzikowski/aws-sdk-client-mock), which is no longer actively maintained.
|
|
547
597
|
|
|
548
|
-
|
|
598
|
+
It reimagines those concepts for Vitest, while extending them with additional features, improved ergonomics, and ongoing maintenance.
|
|
549
599
|
|
|
550
600
|
## 📝 License
|
|
551
601
|
|
package/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("vitest"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("vitest"),R=require("node:fs"),N=require("node:path"),C=require("node:stream"),W=require("./matchers-Rq18z2C7.cjs");class d extends Error{constructor(e,s,c,n){super(e),this.name="AwsError",this.code=s,this.statusCode=c,this.retryable=n}}const M=t=>{const e=t?`The specified key does not exist. Key: ${t}`:"The specified key does not exist.";return new d(e,"NoSuchKey",404,!1)},T=t=>{const e=t?`The specified bucket does not exist. Bucket: ${t}`:"The specified bucket does not exist.";return new d(e,"NoSuchBucket",404,!1)},$=t=>{const e=t?`Access Denied for resource: ${t}`:"Access Denied";return new d(e,"AccessDenied",403,!1)},D=t=>{const e=t?`Requested resource not found: ${t}`:"Requested resource not found";return new d(e,"ResourceNotFoundException",400,!1)},I=()=>new d("The conditional request failed","ConditionalCheckFailedException",400,!1),O=()=>new d("Rate exceeded","Throttling",400,!0),F=()=>new d("We encountered an internal error. Please try again.","InternalServerError",500,!0);function k(){return{enabled:!1,log(t,e){this.enabled&&(e===void 0?console.log(`[aws-sdk-vitest-mock](Debug) ${t}`):console.log(`[aws-sdk-vitest-mock](Debug) ${t}`,e))}}}function y(t){t.enabled=!0}function v(t){t.enabled=!1}function L(t){const e=N.resolve(t),s=R.readFileSync(e,"utf8");return t.endsWith(".json")?JSON.parse(s):s}function K(t,e={}){const{pageSize:s=10,tokenKey:c="NextToken",itemsKey:n="Items"}=e;if(t.length===0)return[{[n]:[]}];const o=[];for(let r=0;r<t.length;r+=s){const u=t.slice(r,r+s),i=r+s<t.length,l={[n]:u};if(i){const a=l;a[c]=`token-${r+s}`}o.push(l)}return o}function A(){return typeof process<"u"&&process.versions?.node?"node":typeof process<"u"&&process.versions?.bun?"bun":"browser"}function q(t){const e=typeof t=="string"?Buffer.from(t,"utf8"):Buffer.from(t);let s=!1;return new C.Readable({read(){s||(this.push(e),this.push(null),s=!0)}})}function B(t){let e;return typeof t=="string"?e=new TextEncoder().encode(t):t instanceof Buffer?e=new Uint8Array(t):e=t,new ReadableStream({start(s){s.enqueue(e),s.close()}})}function h(t){const e=A();return e==="node"||e==="bun"?q(t):B(t)}function w(t,e){return Object.keys(e).every(s=>{const c=e[s],n=t[s];return c&&typeof c=="object"&&!Array.isArray(c)?typeof n!="object"||n===null?!1:w(n,c):n===c})}function j(t,e){if(t===e)return!0;if(typeof t!="object"||t===null||typeof e!="object"||e===null)return t===e;const s=Object.keys(t),c=Object.keys(e);return s.length!==c.length?!1:c.every(n=>{if(!Object.prototype.hasOwnProperty.call(t,n))return!1;const o=t,r=e,u=o[n],i=r[n];return typeof u=="object"&&u!==null&&typeof i=="object"&&i!==null?j(u,i):u===i})}function S(t){return async function(e){const s=()=>this;t.debugLogger.log(`Received command: ${e.constructor.name}`,e.input);const c=t.map.get(e.constructor);if(c){t.debugLogger.log(`Found ${c.length} mock(s) for ${e.constructor.name}`);const n=c.findIndex(o=>o.strict?o.matcher&&j(e.input,o.matcher):!o.matcher||w(e.input,o.matcher));if(n===-1)t.debugLogger.log(`No matching mock found for ${e.constructor.name}`,e.input);else{const o=c[n];if(!o)throw new Error(`Mock at index ${n} not found`);return t.debugLogger.log(`Using mock at index ${n} for ${e.constructor.name}`),o.once&&(c.splice(n,1),t.debugLogger.log(`Removed one-time mock for ${e.constructor.name}`)),o.handler(e.input,s())}}else t.debugLogger.log(`No mocks configured for ${e.constructor.name}`);throw new Error(`No mock configured for command: ${e.constructor.name}`)}}function x(t,e,s,c={}){const n=(r,u)=>{const i={matcher:s,handler:r,once:u,strict:!!c.strict},l=t.map.get(e)??[];if(u){const a=l.findIndex(f=>!f.once);a===-1?l.push(i):l.splice(a,0,i),t.map.set(e,l)}else{const a=l.filter(f=>f.once||JSON.stringify(f.matcher)!==JSON.stringify(s));a.push(i),t.map.set(e,a)}},o={resolves(r){return n(()=>Promise.resolve(r),!1),o},rejects(r){return n(()=>{const u=typeof r=="string"?new Error(r):r;return Promise.reject(u)},!1),o},callsFake(r){return n(r,!1),o},resolvesOnce(r){return n(()=>Promise.resolve(r),!0),o},rejectsOnce(r){return n(()=>{const u=typeof r=="string"?new Error(r):r;return Promise.reject(u)},!0),o},callsFakeOnce(r){return n(r,!0),o},resolvesStream(r){return n(()=>Promise.resolve({Body:h(r)}),!1),o},resolvesStreamOnce(r){return n(()=>Promise.resolve({Body:h(r)}),!0),o},resolvesWithDelay(r,u){const i=l=>{setTimeout(()=>l(r),u)};return n(()=>new Promise(i),!1),o},rejectsWithDelay(r,u){const i=typeof r=="string"?new Error(r):r,l=(a,f)=>{setTimeout(()=>f(i),u)};return n(()=>new Promise(l),!1),o},rejectsWithNoSuchKey(r){return n(()=>Promise.reject(M(r)),!1),o},rejectsWithNoSuchBucket(r){return n(()=>Promise.reject(T(r)),!1),o},rejectsWithAccessDenied(r){return n(()=>Promise.reject($(r)),!1),o},rejectsWithResourceNotFound(r){return n(()=>Promise.reject(D(r)),!1),o},rejectsWithConditionalCheckFailed(){return n(()=>Promise.reject(I()),!1),o},rejectsWithThrottling(){return n(()=>Promise.reject(O()),!1),o},rejectsWithInternalServerError(){return n(()=>Promise.reject(F()),!1),o},resolvesPaginated(r,u={}){const i=K(r,u);let l=0;return n(a=>{const f=u.tokenKey||"NextToken",E=u.inputTokenKey||f,p=a[E];if(p){const g=/token-(\d+)/.exec(p);if(g&&g[1]){const P=g[1];l=Math.floor(Number.parseInt(P,10)/(u.pageSize||10))}}else l=0;const m=i[l]||i[i.length-1]||i[0];if(!m)throw new Error("No paginated responses available");return l=Math.min(l+1,i.length-1),Promise.resolve(m)},!1),o},resolvesFromFile(r){return n(()=>{const u=L(r);return Promise.resolve(u)},!1),o}};return o}const _=t=>{const e={map:new WeakMap,debugLogger:k()},s=t.prototype,c=b.vi.spyOn(s,"send").mockImplementation(S(e));return{client:void 0,on:(o,r,u)=>x(e,o,r,u),reset:()=>{c.mockClear(),e.map=new WeakMap},restore:()=>{c.mockRestore(),e.map=new WeakMap},calls:()=>c.mock.calls.map(o=>o[0]),__rawCalls:()=>c.mock.calls,enableDebug:()=>{y(e.debugLogger)},disableDebug:()=>{v(e.debugLogger)}}},V=t=>{const e={map:new WeakMap,debugLogger:k()},s=b.vi.spyOn(t,"send").mockImplementation(S(e));return{client:t,on:(n,o,r)=>x(e,n,o,r),reset:()=>{s.mockClear(),e.map=new WeakMap},restore:()=>{s.mockRestore(),e.map=new WeakMap},calls:()=>s.mock.calls.map(n=>n[0]),__rawCalls:()=>s.mock.calls,enableDebug:()=>{y(e.debugLogger)},disableDebug:()=>{v(e.debugLogger)}}};exports.matchers=W.matchers;exports.mockClient=_;exports.mockClientInstance=V;
|
package/index.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { vi as b } from "vitest";
|
|
2
|
-
import { readFileSync as
|
|
3
|
-
import
|
|
4
|
-
import { Readable as
|
|
5
|
-
import { m as
|
|
2
|
+
import { readFileSync as R } from "node:fs";
|
|
3
|
+
import N from "node:path";
|
|
4
|
+
import { Readable as W } from "node:stream";
|
|
5
|
+
import { m as Y } from "./matchers-C6AtmwWz.js";
|
|
6
6
|
class d extends Error {
|
|
7
7
|
constructor(e, s, c, n) {
|
|
8
8
|
super(e), this.name = "AwsError", this.code = s, this.statusCode = c, this.retryable = n;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
const
|
|
11
|
+
const C = (t) => {
|
|
12
12
|
const e = t ? `The specified key does not exist. Key: ${t}` : "The specified key does not exist.";
|
|
13
13
|
return new d(e, "NoSuchKey", 404, !1);
|
|
14
|
-
},
|
|
14
|
+
}, $ = (t) => {
|
|
15
15
|
const e = t ? `The specified bucket does not exist. Bucket: ${t}` : "The specified bucket does not exist.";
|
|
16
16
|
return new d(e, "NoSuchBucket", 404, !1);
|
|
17
|
-
},
|
|
17
|
+
}, D = (t) => {
|
|
18
18
|
const e = t ? `Access Denied for resource: ${t}` : "Access Denied";
|
|
19
19
|
return new d(e, "AccessDenied", 403, !1);
|
|
20
|
-
},
|
|
20
|
+
}, M = (t) => {
|
|
21
21
|
const e = t ? `Requested resource not found: ${t}` : "Requested resource not found";
|
|
22
22
|
return new d(e, "ResourceNotFoundException", 400, !1);
|
|
23
|
-
},
|
|
23
|
+
}, T = () => new d(
|
|
24
24
|
"The conditional request failed",
|
|
25
25
|
"ConditionalCheckFailedException",
|
|
26
26
|
400,
|
|
@@ -45,11 +45,11 @@ function y(t) {
|
|
|
45
45
|
function w(t) {
|
|
46
46
|
t.enabled = !1;
|
|
47
47
|
}
|
|
48
|
-
function
|
|
49
|
-
const e =
|
|
48
|
+
function F(t) {
|
|
49
|
+
const e = N.resolve(t), s = R(e, "utf8");
|
|
50
50
|
return t.endsWith(".json") ? JSON.parse(s) : s;
|
|
51
51
|
}
|
|
52
|
-
function
|
|
52
|
+
function L(t, e = {}) {
|
|
53
53
|
const { pageSize: s = 10, tokenKey: c = "NextToken", itemsKey: n = "Items" } = e;
|
|
54
54
|
if (t.length === 0)
|
|
55
55
|
return [{ [n]: [] }];
|
|
@@ -64,18 +64,19 @@ function F(t, e = {}) {
|
|
|
64
64
|
}
|
|
65
65
|
return o;
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function K() {
|
|
68
68
|
return typeof process < "u" && process.versions?.node ? "node" : typeof process < "u" && process.versions?.bun ? "bun" : "browser";
|
|
69
69
|
}
|
|
70
70
|
function A(t) {
|
|
71
71
|
const e = typeof t == "string" ? Buffer.from(t, "utf8") : Buffer.from(t);
|
|
72
|
-
|
|
72
|
+
let s = !1;
|
|
73
|
+
return new W({
|
|
73
74
|
read() {
|
|
74
|
-
this.push(e), this.push(
|
|
75
|
+
s || (this.push(e), this.push(null), s = !0);
|
|
75
76
|
}
|
|
76
77
|
});
|
|
77
78
|
}
|
|
78
|
-
function
|
|
79
|
+
function B(t) {
|
|
79
80
|
let e;
|
|
80
81
|
return typeof t == "string" ? e = new TextEncoder().encode(t) : t instanceof Buffer ? e = new Uint8Array(t) : e = t, new ReadableStream({
|
|
81
82
|
start(s) {
|
|
@@ -84,8 +85,8 @@ function K(t) {
|
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
function h(t) {
|
|
87
|
-
const e =
|
|
88
|
-
return e === "node" || e === "bun" ? A(t) :
|
|
88
|
+
const e = K();
|
|
89
|
+
return e === "node" || e === "bun" ? A(t) : B(t);
|
|
89
90
|
}
|
|
90
91
|
function v(t, e) {
|
|
91
92
|
return Object.keys(e).every((s) => {
|
|
@@ -222,23 +223,23 @@ function S(t, e, s, c = {}) {
|
|
|
222
223
|
return n(() => new Promise(l), !1), o;
|
|
223
224
|
},
|
|
224
225
|
rejectsWithNoSuchKey(r) {
|
|
225
|
-
return n(() => Promise.reject(
|
|
226
|
+
return n(() => Promise.reject(C(r)), !1), o;
|
|
226
227
|
},
|
|
227
228
|
rejectsWithNoSuchBucket(r) {
|
|
228
|
-
return n(() => Promise.reject(
|
|
229
|
+
return n(() => Promise.reject($(r)), !1), o;
|
|
229
230
|
},
|
|
230
231
|
rejectsWithAccessDenied(r) {
|
|
231
|
-
return n(() => Promise.reject(
|
|
232
|
+
return n(() => Promise.reject(D(r)), !1), o;
|
|
232
233
|
},
|
|
233
234
|
rejectsWithResourceNotFound(r) {
|
|
234
235
|
return n(
|
|
235
|
-
() => Promise.reject(
|
|
236
|
+
() => Promise.reject(M(r)),
|
|
236
237
|
!1
|
|
237
238
|
), o;
|
|
238
239
|
},
|
|
239
240
|
rejectsWithConditionalCheckFailed() {
|
|
240
241
|
return n(
|
|
241
|
-
() => Promise.reject(
|
|
242
|
+
() => Promise.reject(T()),
|
|
242
243
|
!1
|
|
243
244
|
), o;
|
|
244
245
|
},
|
|
@@ -249,16 +250,16 @@ function S(t, e, s, c = {}) {
|
|
|
249
250
|
return n(() => Promise.reject(O()), !1), o;
|
|
250
251
|
},
|
|
251
252
|
resolvesPaginated(r, u = {}) {
|
|
252
|
-
const i =
|
|
253
|
+
const i = L(r, u);
|
|
253
254
|
let l = 0;
|
|
254
255
|
return n((a) => {
|
|
255
|
-
const f = u.tokenKey || "NextToken", p = a[
|
|
256
|
+
const f = u.tokenKey || "NextToken", E = u.inputTokenKey || f, p = a[E];
|
|
256
257
|
if (p) {
|
|
257
258
|
const g = /token-(\d+)/.exec(p);
|
|
258
259
|
if (g && g[1]) {
|
|
259
|
-
const
|
|
260
|
+
const P = g[1];
|
|
260
261
|
l = Math.floor(
|
|
261
|
-
Number.parseInt(
|
|
262
|
+
Number.parseInt(P, 10) / (u.pageSize || 10)
|
|
262
263
|
);
|
|
263
264
|
}
|
|
264
265
|
} else
|
|
@@ -275,14 +276,14 @@ function S(t, e, s, c = {}) {
|
|
|
275
276
|
},
|
|
276
277
|
resolvesFromFile(r) {
|
|
277
278
|
return n(() => {
|
|
278
|
-
const u =
|
|
279
|
+
const u = F(r);
|
|
279
280
|
return Promise.resolve(u);
|
|
280
281
|
}, !1), o;
|
|
281
282
|
}
|
|
282
283
|
};
|
|
283
284
|
return o;
|
|
284
285
|
}
|
|
285
|
-
const
|
|
286
|
+
const G = (t) => {
|
|
286
287
|
const e = {
|
|
287
288
|
map: /* @__PURE__ */ new WeakMap(),
|
|
288
289
|
debugLogger: k()
|
|
@@ -310,7 +311,7 @@ const U = (t) => {
|
|
|
310
311
|
w(e.debugLogger);
|
|
311
312
|
}
|
|
312
313
|
};
|
|
313
|
-
},
|
|
314
|
+
}, H = (t) => {
|
|
314
315
|
const e = {
|
|
315
316
|
map: /* @__PURE__ */ new WeakMap(),
|
|
316
317
|
debugLogger: k()
|
|
@@ -340,7 +341,7 @@ const U = (t) => {
|
|
|
340
341
|
};
|
|
341
342
|
};
|
|
342
343
|
export {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
Y as matchers,
|
|
345
|
+
G as mockClient,
|
|
346
|
+
H as mockClientInstance
|
|
346
347
|
};
|