lambder 1.0.131 → 1.0.133
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 +24 -37
- package/dist/LambderMSW.d.ts +48 -101
- package/dist/LambderMSW.js +105 -172
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/docs/LAMBDER_MSW.md +430 -0
- package/docs/TYPE_SAFE_QUICK_START.md +33 -0
- package/examples/msw-testing-example.ts +277 -0
- package/package.json +1 -1
- package/src/LambderMSW.ts +172 -281
- package/src/index.ts +1 -10
- package/docs/MSW_IMPLEMENTATION_COMPLETE.md +0 -191
- package/docs/MSW_MOCKING.md +0 -606
- package/examples/msw-correct-usage.ts +0 -136
- package/examples/msw-mocking-example.ts +0 -241
- package/tests/msw-integration.test.ts +0 -45
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LambderMSW Testing Example
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to use LambderMSW with MSW (Mock Service Worker)
|
|
5
|
+
* to test your Lambder APIs with full type safety.
|
|
6
|
+
*
|
|
7
|
+
* To run this example:
|
|
8
|
+
* 1. Install MSW: npm install msw --save-dev
|
|
9
|
+
* 2. Install a test runner: npm install vitest --save-dev
|
|
10
|
+
* 3. Create this file in your test directory
|
|
11
|
+
*
|
|
12
|
+
* NOTE: This is an example file. Type errors are expected since dependencies
|
|
13
|
+
* may not be installed in the examples directory. Copy this to your project's
|
|
14
|
+
* test directory to use it.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// @ts-nocheck - Example file, types may not be available
|
|
18
|
+
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
|
|
19
|
+
import { setupServer } from 'msw/node';
|
|
20
|
+
import { LambderMSW, LambderCaller, type ApiContract } from '../src/index.ts';
|
|
21
|
+
|
|
22
|
+
// Define your API contract
|
|
23
|
+
type TestApiContract = ApiContract<{
|
|
24
|
+
getUserById: {
|
|
25
|
+
input: { userId: string };
|
|
26
|
+
output: { id: string; name: string; email: string } | null;
|
|
27
|
+
};
|
|
28
|
+
createUser: {
|
|
29
|
+
input: { name: string; email: string };
|
|
30
|
+
output: { id: string; name: string; email: string };
|
|
31
|
+
};
|
|
32
|
+
getUsers: {
|
|
33
|
+
input: { limit?: number };
|
|
34
|
+
output: Array<{ id: string; name: string; email: string }>;
|
|
35
|
+
};
|
|
36
|
+
deleteUser: {
|
|
37
|
+
input: { userId: string };
|
|
38
|
+
output: { success: boolean };
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
|
|
42
|
+
// Setup LambderMSW with type safety
|
|
43
|
+
const lambderMSW = new LambderMSW<TestApiContract>({
|
|
44
|
+
apiPath: '/secure',
|
|
45
|
+
apiVersion: '1.0.0',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Create mock handlers
|
|
49
|
+
const handlers = [
|
|
50
|
+
// Mock getUserById - returns user or null
|
|
51
|
+
lambderMSW.mockApi('getUserById', async (payload) => {
|
|
52
|
+
const users: Record<string, { id: string; name: string; email: string }> = {
|
|
53
|
+
'1': { id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
54
|
+
'2': { id: '2', name: 'Jane Smith', email: 'jane@example.com' },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return users[payload?.userId || ''] || null;
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
// Mock createUser - simulates creating a user
|
|
61
|
+
lambderMSW.mockApi('createUser', async (payload) => {
|
|
62
|
+
return {
|
|
63
|
+
id: Math.random().toString(36).substring(7),
|
|
64
|
+
name: payload?.name || '',
|
|
65
|
+
email: payload?.email || '',
|
|
66
|
+
};
|
|
67
|
+
}, {
|
|
68
|
+
delay: 100, // Simulate 100ms network delay
|
|
69
|
+
message: 'User created successfully'
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
// Mock getUsers - returns a list of users
|
|
73
|
+
lambderMSW.mockApi('getUsers', async (payload) => {
|
|
74
|
+
const allUsers = [
|
|
75
|
+
{ id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
76
|
+
{ id: '2', name: 'Jane Smith', email: 'jane@example.com' },
|
|
77
|
+
{ id: '3', name: 'Bob Johnson', email: 'bob@example.com' },
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const limit = payload?.limit || 10;
|
|
81
|
+
return allUsers.slice(0, limit);
|
|
82
|
+
}),
|
|
83
|
+
|
|
84
|
+
// Mock deleteUser - simulate authorization error
|
|
85
|
+
lambderMSW.mockNotAuthorized('deleteUser'),
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
// Setup MSW server
|
|
89
|
+
const server = setupServer(...handlers);
|
|
90
|
+
|
|
91
|
+
// Setup LambderCaller
|
|
92
|
+
const caller = new LambderCaller<TestApiContract>({
|
|
93
|
+
apiPath: '/secure',
|
|
94
|
+
isCorsEnabled: false,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Test suite
|
|
98
|
+
describe('LambderMSW Testing Example', () => {
|
|
99
|
+
beforeAll(() => {
|
|
100
|
+
server.listen({ onUnhandledRequest: 'error' });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
afterEach(() => {
|
|
104
|
+
server.resetHandlers();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
afterAll(() => {
|
|
108
|
+
server.close();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should fetch user by id', async () => {
|
|
112
|
+
const user = await caller.api('getUserById', { userId: '1' });
|
|
113
|
+
|
|
114
|
+
expect(user).toEqual({
|
|
115
|
+
id: '1',
|
|
116
|
+
name: 'John Doe',
|
|
117
|
+
email: 'john@example.com',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return null for non-existent user', async () => {
|
|
122
|
+
const user = await caller.api('getUserById', { userId: '999' });
|
|
123
|
+
|
|
124
|
+
expect(user).toBeNull();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should create a new user with delay', async () => {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
|
|
130
|
+
const newUser = await caller.api('createUser', {
|
|
131
|
+
name: 'Alice Wonder',
|
|
132
|
+
email: 'alice@example.com',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const endTime = Date.now();
|
|
136
|
+
|
|
137
|
+
expect(newUser?.name).toBe('Alice Wonder');
|
|
138
|
+
expect(newUser?.email).toBe('alice@example.com');
|
|
139
|
+
expect(newUser?.id).toBeDefined();
|
|
140
|
+
|
|
141
|
+
// Check that delay was applied (at least 100ms)
|
|
142
|
+
expect(endTime - startTime).toBeGreaterThanOrEqual(100);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should fetch list of users', async () => {
|
|
146
|
+
const users = await caller.api('getUsers', { limit: 2 });
|
|
147
|
+
|
|
148
|
+
expect(users).toHaveLength(2);
|
|
149
|
+
expect(users?.[0]?.name).toBe('John Doe');
|
|
150
|
+
expect(users?.[1]?.name).toBe('Jane Smith');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should handle authorization error', async () => {
|
|
154
|
+
let errorCaught = false;
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
await caller.api('deleteUser', { userId: '1' });
|
|
158
|
+
} catch (error: any) {
|
|
159
|
+
errorCaught = true;
|
|
160
|
+
expect(error.notAuthorized).toBe(true);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
expect(errorCaught).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should override handler for specific test', async () => {
|
|
167
|
+
// Override the getUserById handler for this test only
|
|
168
|
+
server.use(
|
|
169
|
+
lambderMSW.mockApi('getUserById', async (payload) => {
|
|
170
|
+
return {
|
|
171
|
+
id: payload?.userId || '',
|
|
172
|
+
name: 'Override User',
|
|
173
|
+
email: 'override@example.com',
|
|
174
|
+
};
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const user = await caller.api('getUserById', { userId: '999' });
|
|
179
|
+
|
|
180
|
+
expect(user?.name).toBe('Override User');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should simulate session expired', async () => {
|
|
184
|
+
// Add a handler that simulates session expiration
|
|
185
|
+
server.use(
|
|
186
|
+
lambderMSW.mockSessionExpired('getUserById')
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
let errorCaught = false;
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
await caller.api('getUserById', { userId: '1' });
|
|
193
|
+
} catch (error: any) {
|
|
194
|
+
errorCaught = true;
|
|
195
|
+
expect(error.sessionExpired).toBe(true);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
expect(errorCaught).toBe(true);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should simulate custom error', async () => {
|
|
202
|
+
server.use(
|
|
203
|
+
lambderMSW.mockError('createUser', 'Email already exists')
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
let errorCaught = false;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
await caller.api('createUser', {
|
|
210
|
+
name: 'Duplicate',
|
|
211
|
+
email: 'john@example.com',
|
|
212
|
+
});
|
|
213
|
+
} catch (error: any) {
|
|
214
|
+
errorCaught = true;
|
|
215
|
+
expect(error.errorMessage).toBe('Email already exists');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
expect(errorCaught).toBe(true);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Example: Testing with dynamic responses
|
|
223
|
+
describe('Dynamic Response Testing', () => {
|
|
224
|
+
beforeAll(() => server.listen());
|
|
225
|
+
afterEach(() => server.resetHandlers());
|
|
226
|
+
afterAll(() => server.close());
|
|
227
|
+
|
|
228
|
+
it('should handle different query parameters', async () => {
|
|
229
|
+
server.use(
|
|
230
|
+
lambderMSW.mockApi('getUsers', async (payload) => {
|
|
231
|
+
const limit = payload?.limit || 10;
|
|
232
|
+
|
|
233
|
+
// Generate mock users based on limit
|
|
234
|
+
return Array.from({ length: limit }, (_, i) => ({
|
|
235
|
+
id: `${i + 1}`,
|
|
236
|
+
name: `User ${i + 1}`,
|
|
237
|
+
email: `user${i + 1}@example.com`,
|
|
238
|
+
}));
|
|
239
|
+
})
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const users3 = await caller.api('getUsers', { limit: 3 });
|
|
243
|
+
expect(users3).toHaveLength(3);
|
|
244
|
+
|
|
245
|
+
const users5 = await caller.api('getUsers', { limit: 5 });
|
|
246
|
+
expect(users5).toHaveLength(5);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Example: Testing error conditions
|
|
251
|
+
describe('Error Handling', () => {
|
|
252
|
+
beforeAll(() => server.listen());
|
|
253
|
+
afterEach(() => server.resetHandlers());
|
|
254
|
+
afterAll(() => server.close());
|
|
255
|
+
|
|
256
|
+
it('should handle handler throwing error', async () => {
|
|
257
|
+
server.use(
|
|
258
|
+
lambderMSW.mockApi('getUserById', async () => {
|
|
259
|
+
throw new Error('Database connection failed');
|
|
260
|
+
})
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
let errorCaught = false;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
await caller.api('getUserById', { userId: '1' });
|
|
267
|
+
} catch (error: any) {
|
|
268
|
+
errorCaught = true;
|
|
269
|
+
expect(error.errorMessage).toBe('Database connection failed');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
expect(errorCaught).toBe(true);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
console.log('✅ LambderMSW example tests configured!');
|
|
277
|
+
console.log('📖 See docs/LAMBDER_MSW.md for more information');
|