@digitaldefiance/express-suite-test-utils 1.0.10 → 1.0.11

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 CHANGED
@@ -157,12 +157,194 @@ describe('User model', () => {
157
157
 
158
158
  **Note:** Requires `mongoose` as a peer dependency and `mongodb-memory-server` as a dependency (already included).
159
159
 
160
+ ## Testing Approach
161
+
162
+ This package provides comprehensive testing utilities for Express Suite projects, including custom Jest matchers, console mocks, database helpers, and more.
163
+
164
+ ### Test Utilities Overview
165
+
166
+ **Custom Matchers**: `toThrowType` for type-safe error testing
167
+ **Console Mocks**: Mock and spy on console methods
168
+ **Direct Log Mocks**: Mock `fs.writeSync` for stdout/stderr testing
169
+ **Database Helpers**: MongoDB Memory Server integration
170
+ **React Mocks**: Mock React components and hooks
171
+
172
+ ### Usage Patterns
173
+
174
+ #### Using toThrowType Matcher
175
+
176
+ ```typescript
177
+ import '@digitaldefiance/express-suite-test-utils';
178
+
179
+ class CustomError extends Error {
180
+ constructor(public code: number) {
181
+ super('Custom error');
182
+ }
183
+ }
184
+
185
+ describe('Error Testing', () => {
186
+ it('should throw specific error type', () => {
187
+ expect(() => {
188
+ throw new CustomError(404);
189
+ }).toThrowType(CustomError);
190
+ });
191
+
192
+ it('should validate error properties', () => {
193
+ expect(() => {
194
+ throw new CustomError(404);
195
+ }).toThrowType(CustomError, (error) => {
196
+ expect(error.code).toBe(404);
197
+ });
198
+ });
199
+ });
200
+ ```
201
+
202
+ #### Using Console Mocks
203
+
204
+ ```typescript
205
+ import { withConsoleMocks, spyContains } from '@digitaldefiance/express-suite-test-utils';
206
+
207
+ describe('Console Output', () => {
208
+ it('should capture console.log', async () => {
209
+ await withConsoleMocks({ mute: true }, async (spies) => {
210
+ console.log('test message');
211
+
212
+ expect(spies.log).toHaveBeenCalledWith('test message');
213
+ expect(spyContains(spies.log, 'test', 'message')).toBe(true);
214
+ });
215
+ });
216
+
217
+ it('should capture console.error', async () => {
218
+ await withConsoleMocks({ mute: true }, async (spies) => {
219
+ console.error('error message');
220
+
221
+ expect(spies.error).toHaveBeenCalledWith('error message');
222
+ });
223
+ });
224
+ });
225
+ ```
226
+
227
+ #### Using Direct Log Mocks
228
+
229
+ ```typescript
230
+ import { withDirectLogMocks, directLogContains, getDirectLogMessages } from '@digitaldefiance/express-suite-test-utils';
231
+ import * as fs from 'fs';
232
+
233
+ // Mock fs at module level
234
+ jest.mock('fs', () => ({
235
+ ...jest.requireActual('fs'),
236
+ writeSync: jest.fn(),
237
+ }));
238
+
239
+ describe('Direct Logging', () => {
240
+ it('should capture stdout writes', async () => {
241
+ await withDirectLogMocks({ mute: true }, async (spies) => {
242
+ const buffer = Buffer.from('hello world\n', 'utf8');
243
+ fs.writeSync(1, buffer); // stdout
244
+
245
+ expect(directLogContains(spies.writeSync, 1, 'hello', 'world')).toBe(true);
246
+ expect(getDirectLogMessages(spies.writeSync, 1)).toEqual(['hello world\n']);
247
+ });
248
+ });
249
+ });
250
+ ```
251
+
252
+ #### Using MongoDB Memory Server
253
+
254
+ ```typescript
255
+ import { connectMemoryDB, disconnectMemoryDB, clearMemoryDB } from '@digitaldefiance/express-suite-test-utils';
256
+ import { User } from './models/user';
257
+
258
+ describe('Database Tests', () => {
259
+ beforeAll(async () => {
260
+ await connectMemoryDB();
261
+ });
262
+
263
+ afterAll(async () => {
264
+ await disconnectMemoryDB();
265
+ });
266
+
267
+ afterEach(async () => {
268
+ await clearMemoryDB();
269
+ });
270
+
271
+ it('should validate user schema', async () => {
272
+ const user = new User({
273
+ username: 'test',
274
+ email: 'test@example.com'
275
+ });
276
+
277
+ await user.validate(); // Real Mongoose validation!
278
+ await user.save();
279
+
280
+ const found = await User.findOne({ username: 'test' });
281
+ expect(found).toBeDefined();
282
+ });
283
+
284
+ it('should reject invalid data', async () => {
285
+ const invalid = new User({ username: 'ab' }); // too short
286
+
287
+ await expect(invalid.validate()).rejects.toThrow();
288
+ });
289
+ });
290
+ ```
291
+
292
+ ### Testing Best Practices
293
+
294
+ 1. **Always clean up** after tests (disconnect DB, restore mocks)
295
+ 2. **Use memory database** for fast, isolated tests
296
+ 3. **Mock external dependencies** to avoid side effects
297
+ 4. **Test error conditions** with `toThrowType` matcher
298
+ 5. **Capture console output** when testing logging behavior
299
+
300
+ ### Cross-Package Testing
301
+
302
+ These utilities are designed to work seamlessly with all Express Suite packages:
303
+
304
+ ```typescript
305
+ import { connectMemoryDB, disconnectMemoryDB } from '@digitaldefiance/express-suite-test-utils';
306
+ import { Application } from '@digitaldefiance/node-express-suite';
307
+ import { UserService } from '@digitaldefiance/node-express-suite';
308
+
309
+ describe('Integration Tests', () => {
310
+ let app: Application;
311
+
312
+ beforeAll(async () => {
313
+ await connectMemoryDB();
314
+ app = new Application({
315
+ mongoUri: global.__MONGO_URI__,
316
+ jwtSecret: 'test-secret'
317
+ });
318
+ });
319
+
320
+ afterAll(async () => {
321
+ await app.stop();
322
+ await disconnectMemoryDB();
323
+ });
324
+
325
+ it('should create and find user', async () => {
326
+ const userService = new UserService(app);
327
+ const user = await userService.create({
328
+ username: 'alice',
329
+ email: 'alice@example.com'
330
+ });
331
+
332
+ const found = await userService.findByUsername('alice');
333
+ expect(found).toBeDefined();
334
+ });
335
+ });
336
+ ```
337
+
160
338
  ## License
161
339
 
162
340
  MIT
163
341
 
164
342
  ## ChangeLog
165
343
 
344
+ ### v1.0.11
345
+
346
+ - Fix mongoose to use @digitaldefiance/mongoose-types
347
+
166
348
  ### v1.0.10
167
349
 
168
350
  - Fix direct-log mocks to work with non-configurable fs.writeSync in newer Node.js versions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/express-suite-test-utils",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Test utilities for Digital Defiance Express Suite",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -1,4 +1,4 @@
1
- import { Connection } from 'mongoose';
1
+ import { Connection } from '@digitaldefiance/mongoose-types';
2
2
  /**
3
3
  * Connect to in-memory MongoDB for testing
4
4
  * @returns Object with both the connection and URI
@@ -1 +1 @@
1
- {"version":3,"file":"mongoose-memory.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-express-suite-test-utils/src/lib/mongoose-memory.ts"],"names":[],"mappings":"AACA,OAAiB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKhD;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBxF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWxD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAOnD"}
1
+ {"version":3,"file":"mongoose-memory.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-express-suite-test-utils/src/lib/mongoose-memory.ts"],"names":[],"mappings":"AAAA,OAAiB,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAMvE;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAsBD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWxD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAOnD"}
@@ -4,8 +4,8 @@ exports.connectMemoryDB = connectMemoryDB;
4
4
  exports.disconnectMemoryDB = disconnectMemoryDB;
5
5
  exports.clearMemoryDB = clearMemoryDB;
6
6
  const tslib_1 = require("tslib");
7
+ const mongoose_types_1 = tslib_1.__importDefault(require("@digitaldefiance/mongoose-types"));
7
8
  const mongodb_memory_server_1 = require("mongodb-memory-server");
8
- const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
9
9
  let mongoServer;
10
10
  let connection;
11
11
  /**
@@ -14,8 +14,8 @@ let connection;
14
14
  */
15
15
  async function connectMemoryDB() {
16
16
  // If mongoose is connected but we don't have our server, disconnect first
17
- if (mongoose_1.default.connection.readyState !== 0 && !mongoServer) {
18
- await mongoose_1.default.disconnect();
17
+ if (mongoose_types_1.default.connection.readyState !== 0 && !mongoServer) {
18
+ await mongoose_types_1.default.disconnect();
19
19
  connection = undefined;
20
20
  }
21
21
  // Create new server if needed
@@ -24,10 +24,10 @@ async function connectMemoryDB() {
24
24
  }
25
25
  const uri = mongoServer.getUri();
26
26
  // Connect if not already connected
27
- if (mongoose_1.default.connection.readyState === 0) {
28
- await mongoose_1.default.connect(uri);
27
+ if (mongoose_types_1.default.connection.readyState === 0) {
28
+ await mongoose_types_1.default.connect(uri);
29
29
  }
30
- connection = mongoose_1.default.connection;
30
+ connection = mongoose_types_1.default.connection;
31
31
  return { connection, uri };
32
32
  }
33
33
  /**
@@ -36,7 +36,7 @@ async function connectMemoryDB() {
36
36
  async function disconnectMemoryDB() {
37
37
  if (connection) {
38
38
  await connection.dropDatabase();
39
- await mongoose_1.default.disconnect();
39
+ await mongoose_types_1.default.disconnect();
40
40
  connection = undefined;
41
41
  }
42
42
  if (mongoServer) {