90dc-core 1.16.14 → 1.16.15
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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/testing/testHelpers.d.ts +0 -126
- package/dist/lib/testing/testHelpers.d.ts.map +1 -1
- package/dist/lib/testing/testHelpers.js +0 -161
- package/dist/lib/testing/testHelpers.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { NotificationClient } from "./lib/utils/NotificationClient.js";
|
|
|
15
15
|
export { Log } from "./lib/utils/Logger.js";
|
|
16
16
|
export { SecretManager } from "./lib/utils/SecretManager.js";
|
|
17
17
|
export { initializeSentry, isSentryEnabled, scrubObject, captureRequestBody, extractUserContext, buildRequestContext, buildResponseContext, reportErrorToSentry, reportMessageToSentry, type ErrorReportOptions, type SeverityLevel, } from "./lib/utils/SentryUtil.js";
|
|
18
|
-
export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase,
|
|
18
|
+
export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase, flushPromises, assertions, executeRoute, type BaseContext, type AuthenticatedContext, type RouterContext, type RouterMiddleware, type RouterLayer, type RouterLike, type SequelizeModelMethods, } from "./lib/testing/testHelpers.js";
|
|
19
19
|
export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError, type BaseConfig } from "./lib/config/ConfigValidator.js";
|
|
20
20
|
export { AppError, ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, ServiceUnavailableError, DatabaseError, ExternalAPIError, isAppError, isOperationalError, toAppError } from "./lib/Errors/AppError.js";
|
|
21
21
|
export { ErrorMiddleware, } from "./lib/middlewares/ErrorMiddleware.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GACd,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,yBAAyB,CAAA;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAChF,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAA;AAChG,YAAY,EACV,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,GACd,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAGlF,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,aAAa,GACnB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,aAAa,EACb,UAAU,EACV,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,eAAe,GAChB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAG5F,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAGvF,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAC,cAAc,EAAE,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -18,17 +18,7 @@ export { Log } from "./lib/utils/Logger.js";
|
|
|
18
18
|
export { SecretManager } from "./lib/utils/SecretManager.js";
|
|
19
19
|
export { initializeSentry, isSentryEnabled, scrubObject, captureRequestBody, extractUserContext, buildRequestContext, buildResponseContext, reportErrorToSentry, reportMessageToSentry } from "./lib/utils/SentryUtil.js";
|
|
20
20
|
//Testing Utilities
|
|
21
|
-
export {
|
|
22
|
-
createMockContext, createMockUser, createAuthenticatedContext, // Database mocks
|
|
23
|
-
mockDatabase, setupDatabaseMocks, // Async helpers
|
|
24
|
-
flushPromises, // Assertions
|
|
25
|
-
assertions, // Route execution
|
|
26
|
-
executeRoute, // Factory helpers
|
|
27
|
-
createMockFile, createMockFiles, createMockTransaction, // Time mocking
|
|
28
|
-
setupTimeMocks, // Mock errors
|
|
29
|
-
MockValidationError, MockNotFoundError, MockDatabaseError, // Typed mocking helpers
|
|
30
|
-
createTypedMock, spyOnPrototype, // Constants
|
|
31
|
-
TEST_CONSTANTS } from "./lib/testing/testHelpers.js";
|
|
21
|
+
export { createMockContext, createMockUser, createAuthenticatedContext, mockDatabase, flushPromises, assertions, executeRoute } from "./lib/testing/testHelpers.js";
|
|
32
22
|
//Config
|
|
33
23
|
export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError } from "./lib/config/ConfigValidator.js";
|
|
34
24
|
//Errors
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\nexport type {\n SendTemplateEmailRequest,\n BatchTemplateEmailRequest,\n EmailResponse,\n} from \"./lib/clients/EmailClient.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models - Export all models and model arrays\nexport * from \"./lib/dbmodels/index.js\"\n\n//Clients\nexport { EmailClient } from \"./lib/clients/EmailClient.js\"\nexport { PushNotificationClient } from \"./lib/clients/PushNotificationClient.js\"\nexport { FirebasePushNotificationClient } from \"./lib/clients/FirebasePushNotificationClient.js\"\nexport type {\n SendTemplateEmailRequest,\n BatchTemplateEmailRequest,\n EmailResponse,\n} from \"./lib/clients/EmailClient.js\"\nexport type { NotificationPayload } from \"./lib/clients/PushNotificationClient.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\nexport {SecretManager} from \"./lib/utils/SecretManager.js\"\nexport {\n initializeSentry,\n isSentryEnabled,\n scrubObject,\n captureRequestBody,\n extractUserContext,\n buildRequestContext,\n buildResponseContext,\n reportErrorToSentry,\n reportMessageToSentry,\n type ErrorReportOptions,\n type SeverityLevel,\n} from \"./lib/utils/SentryUtil.js\"\n\n//Testing Utilities\nexport {\n createMockContext,\n createMockUser,\n createAuthenticatedContext,\n mockDatabase,\n flushPromises,\n assertions,\n executeRoute,\n type BaseContext,\n type AuthenticatedContext,\n type RouterContext,\n type RouterMiddleware,\n type RouterLayer,\n type RouterLike,\n type SequelizeModelMethods,\n} from \"./lib/testing/testHelpers.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n ErrorMiddleware,\n} from \"./lib/middlewares/ErrorMiddleware.js\"\nexport { validate, type ValidationConfig } from \"./lib/middlewares/ValidationMiddleware.js\";\n\n//Controllers\nexport { BaseController, type RouteConfig } from \"./lib/controllers/BaseController.js\";\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\"\nexport {DatabaseClient, type DatabaseConfig} from \"./lib/classes/Database.js\""],"names":["EmailClient","PushNotificationClient","FirebasePushNotificationClient","AuthenticationUtil","NotificationsUtil","NotificationClient","Log","SecretManager","initializeSentry","isSentryEnabled","scrubObject","captureRequestBody","extractUserContext","buildRequestContext","buildResponseContext","reportErrorToSentry","reportMessageToSentry","createMockContext","createMockUser","createAuthenticatedContext","mockDatabase","flushPromises","assertions","executeRoute","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","ErrorMiddleware","validate","BaseController","RedisClient","DatabaseClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,gDAAgD;AAChD,cAAc,iBAAyB;AAEvC,SAAS;AACT,SAASA,WAAW,QAAQ,+BAA8B;AAC1D,SAASC,sBAAsB,QAAQ,0CAAyC;AAChF,SAASC,8BAA8B,QAAQ,kDAAiD;AAQhG,OAAO;AACP,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AACzC,SAAQC,aAAa,QAAO,+BAA8B;AAC1D,SACEC,gBAAgB,EAChBC,eAAe,EACfC,WAAW,EACXC,kBAAkB,EAClBC,kBAAkB,EAClBC,mBAAmB,EACnBC,oBAAoB,EACpBC,mBAAmB,EACnBC,qBAAqB,QAGhB,4BAA2B;AAElC,mBAAmB;AACnB,SACEC,iBAAiB,EACjBC,cAAc,EACdC,0BAA0B,EAC1BC,YAAY,EACZC,aAAa,EACbC,UAAU,EACVC,YAAY,QAQP,+BAA8B;AAErC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,eAAe,QACV,uCAAsC;AAC7C,SAASC,QAAQ,QAA+B,4CAA4C;AAE5F,aAAa;AACb,SAASC,cAAc,QAA0B,sCAAsC;AAGvF,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,cAAc,QAA4B,4BAA2B"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { UserTypes } from '../models/UserInterfaces.js';
|
|
2
|
-
export type Mock = any;
|
|
3
2
|
export interface BaseContext {
|
|
4
3
|
request: {
|
|
5
4
|
body?: unknown;
|
|
@@ -43,131 +42,6 @@ export declare const mockDatabase: {
|
|
|
43
42
|
mockModel<T = unknown>(methods?: Partial<SequelizeModelMethods<T>>): SequelizeModelMethods<T>;
|
|
44
43
|
};
|
|
45
44
|
export declare function flushPromises(): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* ============================================================================
|
|
48
|
-
* TEST DATA FACTORIES
|
|
49
|
-
* Following industry best practices from Testing Blueprint
|
|
50
|
-
* ============================================================================
|
|
51
|
-
*/
|
|
52
|
-
/**
|
|
53
|
-
* Constants for testing - avoids magic values
|
|
54
|
-
*/
|
|
55
|
-
export declare const TEST_CONSTANTS: {
|
|
56
|
-
readonly VALID_UUID: "123e4567-e89b-12d3-a456-426614174000";
|
|
57
|
-
readonly INVALID_UUID: "invalid-uuid";
|
|
58
|
-
readonly VALID_TIMEZONE: "America/New_York";
|
|
59
|
-
readonly INVALID_TIMEZONE: "Invalid/Timezone";
|
|
60
|
-
readonly DEFAULT_TIMEZONE: "UTC";
|
|
61
|
-
readonly TEST_DATE: "2026-02-25T10:00:00Z";
|
|
62
|
-
readonly WEEK_START: "2026-02-23";
|
|
63
|
-
readonly MAX_JSON_SIZE: number;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Mock file upload structure (multer format)
|
|
67
|
-
*/
|
|
68
|
-
export interface MockFile {
|
|
69
|
-
fieldname: string;
|
|
70
|
-
originalname: string;
|
|
71
|
-
encoding: string;
|
|
72
|
-
mimetype: string;
|
|
73
|
-
buffer: Buffer;
|
|
74
|
-
size: number;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Creates a mock file for upload testing
|
|
78
|
-
*/
|
|
79
|
-
export declare function createMockFile(overrides?: Partial<MockFile>): MockFile;
|
|
80
|
-
/**
|
|
81
|
-
* Creates multiple mock files
|
|
82
|
-
*/
|
|
83
|
-
export declare function createMockFiles(count: number): MockFile[];
|
|
84
|
-
/**
|
|
85
|
-
* Mock transaction for database testing
|
|
86
|
-
*/
|
|
87
|
-
export interface MockTransaction {
|
|
88
|
-
commit: Mock;
|
|
89
|
-
rollback: Mock;
|
|
90
|
-
finished?: string;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Creates a mock Sequelize transaction
|
|
94
|
-
*/
|
|
95
|
-
export declare function createMockTransaction(): MockTransaction;
|
|
96
|
-
/**
|
|
97
|
-
* ============================================================================
|
|
98
|
-
* MOCK CONFIGURATIONS
|
|
99
|
-
* Pre-configured mocks for common testing scenarios
|
|
100
|
-
* ============================================================================
|
|
101
|
-
*/
|
|
102
|
-
/**
|
|
103
|
-
* Database mock configuration
|
|
104
|
-
*/
|
|
105
|
-
export interface DatabaseMocks {
|
|
106
|
-
findOne: Mock;
|
|
107
|
-
findOrCreate: Mock;
|
|
108
|
-
findByPk: Mock;
|
|
109
|
-
findAll: Mock;
|
|
110
|
-
create: Mock;
|
|
111
|
-
update: Mock;
|
|
112
|
-
upsert: Mock;
|
|
113
|
-
bulkCreate: Mock;
|
|
114
|
-
destroy: Mock;
|
|
115
|
-
reset: () => void;
|
|
116
|
-
restore: () => void;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Creates a set of database operation mocks with reset/restore functionality
|
|
120
|
-
*/
|
|
121
|
-
export declare function setupDatabaseMocks(): DatabaseMocks;
|
|
122
|
-
/**
|
|
123
|
-
* Time-related mock utilities
|
|
124
|
-
*/
|
|
125
|
-
export interface TimeMocks {
|
|
126
|
-
setTime: (date: string | Date) => void;
|
|
127
|
-
advanceTime: (ms: number) => void;
|
|
128
|
-
restore: () => void;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Sets up fake timers for timezone testing
|
|
132
|
-
* Usage:
|
|
133
|
-
* ```typescript
|
|
134
|
-
* describe('My test', () => {
|
|
135
|
-
* const timeMocks = setupTimeMocks();
|
|
136
|
-
*
|
|
137
|
-
* it('test with fixed time', () => {
|
|
138
|
-
* timeMocks.setTime('2026-02-25T10:00:00Z');
|
|
139
|
-
* // ... test code
|
|
140
|
-
* });
|
|
141
|
-
* });
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
export declare function setupTimeMocks(): TimeMocks;
|
|
145
|
-
/**
|
|
146
|
-
* Mock error instances for testing error handling
|
|
147
|
-
*/
|
|
148
|
-
export declare class MockValidationError extends Error {
|
|
149
|
-
issues: any[];
|
|
150
|
-
constructor(message: string, issues?: any[]);
|
|
151
|
-
}
|
|
152
|
-
export declare class MockNotFoundError extends Error {
|
|
153
|
-
constructor(message: string);
|
|
154
|
-
}
|
|
155
|
-
export declare class MockDatabaseError extends Error {
|
|
156
|
-
constructor(message: string);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Helper to create a typed mock function
|
|
160
|
-
*/
|
|
161
|
-
export declare function createTypedMock(): Mock;
|
|
162
|
-
/**
|
|
163
|
-
* Helper to create a typed spy on a prototype method
|
|
164
|
-
* Usage:
|
|
165
|
-
* ```typescript
|
|
166
|
-
* const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');
|
|
167
|
-
* mockMethod.mockResolvedValue({ success: true });
|
|
168
|
-
* ```
|
|
169
|
-
*/
|
|
170
|
-
export declare function spyOnPrototype<T, K extends keyof T>(prototype: T, method: K): Mock;
|
|
171
45
|
export declare const assertions: {
|
|
172
46
|
assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T;
|
|
173
47
|
assertStatusCode(ctx: BaseContext | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,
|
|
1
|
+
{"version":3,"file":"testHelpers.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/testHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -73,167 +73,6 @@ export const mockDatabase = {
|
|
|
73
73
|
export async function flushPromises() {
|
|
74
74
|
return new Promise((resolve)=>setImmediate(resolve));
|
|
75
75
|
}
|
|
76
|
-
/**
|
|
77
|
-
* ============================================================================
|
|
78
|
-
* TEST DATA FACTORIES
|
|
79
|
-
* Following industry best practices from Testing Blueprint
|
|
80
|
-
* ============================================================================
|
|
81
|
-
*/ /**
|
|
82
|
-
* Constants for testing - avoids magic values
|
|
83
|
-
*/ export const TEST_CONSTANTS = {
|
|
84
|
-
VALID_UUID: '123e4567-e89b-12d3-a456-426614174000',
|
|
85
|
-
INVALID_UUID: 'invalid-uuid',
|
|
86
|
-
VALID_TIMEZONE: 'America/New_York',
|
|
87
|
-
INVALID_TIMEZONE: 'Invalid/Timezone',
|
|
88
|
-
DEFAULT_TIMEZONE: 'UTC',
|
|
89
|
-
TEST_DATE: '2026-02-25T10:00:00Z',
|
|
90
|
-
WEEK_START: '2026-02-23',
|
|
91
|
-
MAX_JSON_SIZE: 1024 * 1024
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
* Creates a mock file for upload testing
|
|
95
|
-
*/ export function createMockFile(overrides = {}) {
|
|
96
|
-
return {
|
|
97
|
-
fieldname: 'photos',
|
|
98
|
-
originalname: 'test-photo.jpg',
|
|
99
|
-
encoding: '7bit',
|
|
100
|
-
mimetype: 'image/jpeg',
|
|
101
|
-
buffer: Buffer.from('fake-image-data'),
|
|
102
|
-
size: 1024,
|
|
103
|
-
...overrides
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Creates multiple mock files
|
|
108
|
-
*/ export function createMockFiles(count) {
|
|
109
|
-
return Array.from({
|
|
110
|
-
length: count
|
|
111
|
-
}, (_, i)=>createMockFile({
|
|
112
|
-
originalname: `test-photo-${i}.jpg`,
|
|
113
|
-
size: 1024 * (i + 1)
|
|
114
|
-
}));
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Creates a mock Sequelize transaction
|
|
118
|
-
*/ export function createMockTransaction() {
|
|
119
|
-
const mockFn = globalThis.jest?.fn || (()=>{
|
|
120
|
-
throw new Error('jest.fn is not available. Make sure jest is properly configured.');
|
|
121
|
-
});
|
|
122
|
-
return {
|
|
123
|
-
commit: mockFn().mockResolvedValue(undefined),
|
|
124
|
-
rollback: mockFn().mockResolvedValue(undefined)
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Creates a set of database operation mocks with reset/restore functionality
|
|
129
|
-
*/ export function setupDatabaseMocks() {
|
|
130
|
-
// Note: jest must be imported in the test file for this to work
|
|
131
|
-
const mockFn = globalThis.jest?.fn || (()=>{
|
|
132
|
-
throw new Error('jest.fn is not available. Make sure jest is properly configured.');
|
|
133
|
-
});
|
|
134
|
-
const mocks = {
|
|
135
|
-
findOne: mockFn(),
|
|
136
|
-
findOrCreate: mockFn(),
|
|
137
|
-
findByPk: mockFn(),
|
|
138
|
-
findAll: mockFn(),
|
|
139
|
-
create: mockFn(),
|
|
140
|
-
update: mockFn(),
|
|
141
|
-
upsert: mockFn(),
|
|
142
|
-
bulkCreate: mockFn(),
|
|
143
|
-
destroy: mockFn()
|
|
144
|
-
};
|
|
145
|
-
return {
|
|
146
|
-
...mocks,
|
|
147
|
-
reset: ()=>{
|
|
148
|
-
Object.values(mocks).forEach((mock)=>mock.mockReset?.());
|
|
149
|
-
},
|
|
150
|
-
restore: ()=>{
|
|
151
|
-
Object.values(mocks).forEach((mock)=>mock.mockRestore?.());
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Sets up fake timers for timezone testing
|
|
157
|
-
* Usage:
|
|
158
|
-
* ```typescript
|
|
159
|
-
* describe('My test', () => {
|
|
160
|
-
* const timeMocks = setupTimeMocks();
|
|
161
|
-
*
|
|
162
|
-
* it('test with fixed time', () => {
|
|
163
|
-
* timeMocks.setTime('2026-02-25T10:00:00Z');
|
|
164
|
-
* // ... test code
|
|
165
|
-
* });
|
|
166
|
-
* });
|
|
167
|
-
* ```
|
|
168
|
-
*/ export function setupTimeMocks() {
|
|
169
|
-
const jestGlobal = globalThis.jest;
|
|
170
|
-
const beforeEachGlobal = globalThis.beforeEach;
|
|
171
|
-
const afterEachGlobal = globalThis.afterEach;
|
|
172
|
-
if (beforeEachGlobal) {
|
|
173
|
-
beforeEachGlobal(()=>{
|
|
174
|
-
jestGlobal?.useFakeTimers();
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
if (afterEachGlobal) {
|
|
178
|
-
afterEachGlobal(()=>{
|
|
179
|
-
jestGlobal?.useRealTimers();
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
setTime: (date)=>{
|
|
184
|
-
jestGlobal?.setSystemTime(new Date(date));
|
|
185
|
-
},
|
|
186
|
-
advanceTime: (ms)=>{
|
|
187
|
-
jestGlobal?.advanceTimersByTime(ms);
|
|
188
|
-
},
|
|
189
|
-
restore: ()=>{
|
|
190
|
-
jestGlobal?.useRealTimers();
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Mock error instances for testing error handling
|
|
196
|
-
*/ export class MockValidationError extends Error {
|
|
197
|
-
issues;
|
|
198
|
-
constructor(message, issues = []){
|
|
199
|
-
super(message), this.issues = issues;
|
|
200
|
-
this.name = 'ValidationError';
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
export class MockNotFoundError extends Error {
|
|
204
|
-
constructor(message){
|
|
205
|
-
super(message);
|
|
206
|
-
this.name = 'NotFoundError';
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
export class MockDatabaseError extends Error {
|
|
210
|
-
constructor(message){
|
|
211
|
-
super(message);
|
|
212
|
-
this.name = 'SequelizeDatabaseError';
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Helper to create a typed mock function
|
|
217
|
-
*/ export function createTypedMock() {
|
|
218
|
-
const mockFn = globalThis.jest?.fn || (()=>{
|
|
219
|
-
throw new Error('jest.fn is not available. Make sure jest is properly configured.');
|
|
220
|
-
});
|
|
221
|
-
return mockFn();
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Helper to create a typed spy on a prototype method
|
|
225
|
-
* Usage:
|
|
226
|
-
* ```typescript
|
|
227
|
-
* const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');
|
|
228
|
-
* mockMethod.mockResolvedValue({ success: true });
|
|
229
|
-
* ```
|
|
230
|
-
*/ export function spyOnPrototype(prototype, method) {
|
|
231
|
-
const jestGlobal = globalThis.jest;
|
|
232
|
-
if (!jestGlobal?.spyOn) {
|
|
233
|
-
throw new Error('jest.spyOn is not available. Make sure jest is properly configured.');
|
|
234
|
-
}
|
|
235
|
-
return jestGlobal.spyOn(prototype, method);
|
|
236
|
-
}
|
|
237
76
|
export const assertions = {
|
|
238
77
|
assertDefined (value, message) {
|
|
239
78
|
if (value === null || value === undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/testing/testHelpers.ts"],"sourcesContent":["import type { UserTypes } from '../models/UserInterfaces.js';\n\n// Mock type definition to avoid jest-mock dependency\nexport type Mock = any;\n\n\nexport interface BaseContext {\n request: {\n body?: unknown;\n headers?: Record<string, string | string[] | undefined>;\n files?: unknown;\n };\n response: {\n status: number;\n body?: unknown;\n };\n params?: Record<string, string>;\n query?: Record<string, string | string[] | undefined>;\n state: Record<string, unknown>;\n status: number;\n body?: unknown;\n headers: Record<string, string | string[] | undefined>;\n method?: string;\n path?: string;\n get: (field: string) => string | string[] | undefined;\n set: (field: string, value: string) => void;\n}\n\n\nexport function createMockContext<T extends BaseContext = BaseContext>(\n overrides: Partial<T> = {},\n): T {\n const ctx: BaseContext = {\n request: {\n body: {},\n headers: {},\n ...overrides.request,\n },\n response: {\n status: 200,\n body: undefined,\n ...overrides.response,\n },\n params: overrides.params || {},\n query: overrides.query || {},\n state: overrides.state || {},\n status: overrides.status || 200,\n body: overrides.body,\n headers: overrides.headers || {},\n method: overrides.method || 'GET',\n path: overrides.path || '/',\n get: (field: string) => {\n return ctx.headers[field.toLowerCase()];\n },\n set: (field: string, value: string) => {\n ctx.headers[field.toLowerCase()] = value;\n },\n };\n\n return { ...ctx, ...overrides } as T;\n}\n\n\nexport function createMockUser(overrides: Partial<UserTypes> = {}): UserTypes {\n return {\n userUuid: overrides.userUuid || 'test-user-uuid',\n email: overrides.email || 'test@example.com',\n firstName: overrides.firstName || 'Test',\n lastName: overrides.lastName || 'User',\n avatar: overrides.avatar || '1',\n role: overrides.role || 'user',\n isSubscriptionActive: overrides.isSubscriptionActive ?? true,\n ...overrides,\n };\n}\n\n\nexport interface AuthenticatedContext extends BaseContext {\n state: {\n user: UserTypes;\n [key: string]: unknown;\n };\n}\n\n\nexport function createAuthenticatedContext<T extends BaseContext = AuthenticatedContext>(\n userOverrides: Partial<UserTypes> = {},\n contextOverrides: Partial<T> = {},\n): T {\n const user = createMockUser(userOverrides);\n\n return createMockContext<T>({\n ...contextOverrides,\n state: {\n user,\n ...(contextOverrides.state || {}),\n },\n headers: {\n authorization: 'Bearer mock-token',\n ...(contextOverrides.headers || {}),\n },\n } as Partial<T>);\n}\n\nexport interface SequelizeModelMethods<T = unknown> {\n findOne: ((options?: unknown) => Promise<T | null>) | undefined;\n findAll: ((options?: unknown) => Promise<T[]>) | undefined;\n findByPk: ((id: string | number, options?: unknown) => Promise<T | null>) | undefined;\n create: ((values: Partial<T>, options?: unknown) => Promise<T>) | undefined;\n update: ((values: Partial<T>, options?: unknown) => Promise<[number, T[]]>) | undefined;\n destroy: ((options?: unknown) => Promise<number>) | undefined;\n count: ((options?: unknown) => Promise<number>) | undefined;\n}\n\n\nexport const mockDatabase = {\n\n mockModel<T = unknown>(\n methods: Partial<SequelizeModelMethods<T>> = {},\n ): SequelizeModelMethods<T> {\n return {\n findOne: undefined,\n findAll: undefined,\n findByPk: undefined,\n create: undefined,\n update: undefined,\n destroy: undefined,\n count: undefined,\n ...methods,\n };\n },\n};\n\n\nexport async function flushPromises(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * ============================================================================\n * TEST DATA FACTORIES\n * Following industry best practices from Testing Blueprint\n * ============================================================================\n */\n\n/**\n * Constants for testing - avoids magic values\n */\nexport const TEST_CONSTANTS = {\n VALID_UUID: '123e4567-e89b-12d3-a456-426614174000',\n INVALID_UUID: 'invalid-uuid',\n VALID_TIMEZONE: 'America/New_York',\n INVALID_TIMEZONE: 'Invalid/Timezone',\n DEFAULT_TIMEZONE: 'UTC',\n TEST_DATE: '2026-02-25T10:00:00Z',\n WEEK_START: '2026-02-23',\n MAX_JSON_SIZE: 1024 * 1024, // 1MB\n} as const;\n\n/**\n * Mock file upload structure (multer format)\n */\nexport interface MockFile {\n fieldname: string;\n originalname: string;\n encoding: string;\n mimetype: string;\n buffer: Buffer;\n size: number;\n}\n\n/**\n * Creates a mock file for upload testing\n */\nexport function createMockFile(overrides: Partial<MockFile> = {}): MockFile {\n return {\n fieldname: 'photos',\n originalname: 'test-photo.jpg',\n encoding: '7bit',\n mimetype: 'image/jpeg',\n buffer: Buffer.from('fake-image-data'),\n size: 1024,\n ...overrides,\n };\n}\n\n/**\n * Creates multiple mock files\n */\nexport function createMockFiles(count: number): MockFile[] {\n return Array.from({ length: count }, (_, i) =>\n createMockFile({\n originalname: `test-photo-${i}.jpg`,\n size: 1024 * (i + 1),\n }),\n );\n}\n\n/**\n * Mock transaction for database testing\n */\nexport interface MockTransaction {\n commit: Mock;\n rollback: Mock;\n finished?: string;\n}\n\n/**\n * Creates a mock Sequelize transaction\n */\nexport function createMockTransaction(): MockTransaction {\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n\n return {\n commit: mockFn().mockResolvedValue(undefined),\n rollback: mockFn().mockResolvedValue(undefined),\n };\n}\n\n/**\n * ============================================================================\n * MOCK CONFIGURATIONS\n * Pre-configured mocks for common testing scenarios\n * ============================================================================\n */\n\n/**\n * Database mock configuration\n */\nexport interface DatabaseMocks {\n findOne: Mock;\n findOrCreate: Mock;\n findByPk: Mock;\n findAll: Mock;\n create: Mock;\n update: Mock;\n upsert: Mock;\n bulkCreate: Mock;\n destroy: Mock;\n reset: () => void;\n restore: () => void;\n}\n\n/**\n * Creates a set of database operation mocks with reset/restore functionality\n */\nexport function setupDatabaseMocks(): DatabaseMocks {\n // Note: jest must be imported in the test file for this to work\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n\n const mocks = {\n findOne: mockFn(),\n findOrCreate: mockFn(),\n findByPk: mockFn(),\n findAll: mockFn(),\n create: mockFn(),\n update: mockFn(),\n upsert: mockFn(),\n bulkCreate: mockFn(),\n destroy: mockFn(),\n };\n\n return {\n ...mocks,\n reset: () => {\n Object.values(mocks).forEach((mock) => mock.mockReset?.());\n },\n restore: () => {\n Object.values(mocks).forEach((mock) => mock.mockRestore?.());\n },\n };\n}\n\n/**\n * Time-related mock utilities\n */\nexport interface TimeMocks {\n setTime: (date: string | Date) => void;\n advanceTime: (ms: number) => void;\n restore: () => void;\n}\n\n/**\n * Sets up fake timers for timezone testing\n * Usage:\n * ```typescript\n * describe('My test', () => {\n * const timeMocks = setupTimeMocks();\n *\n * it('test with fixed time', () => {\n * timeMocks.setTime('2026-02-25T10:00:00Z');\n * // ... test code\n * });\n * });\n * ```\n */\nexport function setupTimeMocks(): TimeMocks {\n const jestGlobal = (globalThis as any).jest;\n const beforeEachGlobal = (globalThis as any).beforeEach;\n const afterEachGlobal = (globalThis as any).afterEach;\n\n if (beforeEachGlobal) {\n beforeEachGlobal(() => {\n jestGlobal?.useFakeTimers();\n });\n }\n\n if (afterEachGlobal) {\n afterEachGlobal(() => {\n jestGlobal?.useRealTimers();\n });\n }\n\n return {\n setTime: (date: string | Date) => {\n jestGlobal?.setSystemTime(new Date(date));\n },\n advanceTime: (ms: number) => {\n jestGlobal?.advanceTimersByTime(ms);\n },\n restore: () => {\n jestGlobal?.useRealTimers();\n },\n };\n}\n\n/**\n * Mock error instances for testing error handling\n */\nexport class MockValidationError extends Error {\n constructor(\n message: string,\n public issues: any[] = [],\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\nexport class MockNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotFoundError';\n }\n}\n\nexport class MockDatabaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SequelizeDatabaseError';\n }\n}\n\n/**\n * Helper to create a typed mock function\n */\nexport function createTypedMock(): Mock {\n const mockFn = (globalThis as any).jest?.fn || (() => {\n throw new Error('jest.fn is not available. Make sure jest is properly configured.');\n });\n return mockFn() as Mock;\n}\n\n/**\n * Helper to create a typed spy on a prototype method\n * Usage:\n * ```typescript\n * const mockMethod = spyOnPrototype(MyService.prototype, 'methodName');\n * mockMethod.mockResolvedValue({ success: true });\n * ```\n */\nexport function spyOnPrototype<T, K extends keyof T>(\n prototype: T,\n method: K,\n): Mock {\n const jestGlobal = (globalThis as any).jest;\n if (!jestGlobal?.spyOn) {\n throw new Error('jest.spyOn is not available. Make sure jest is properly configured.');\n }\n return jestGlobal.spyOn(prototype as any, method as any) as any;\n}\n\n\nexport const assertions = {\n\n assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to be defined');\n }\n },\n\n\n assertStatusCode(ctx: BaseContext | { status: number; body?: unknown }, expected: number): void {\n if (ctx.status !== expected) {\n throw new Error(\n `Expected status ${expected} but got ${ctx.status}. Body: ${JSON.stringify(ctx.body)}`,\n );\n }\n },\n\n assertResponseShape(\n body: unknown,\n expectedKeys: string[],\n ): asserts body is Record<string, unknown> {\n if (typeof body !== 'object' || body === null) {\n throw new Error('Expected body to be an object');\n }\n const actualKeys = Object.keys(body);\n const missingKeys = expectedKeys.filter((key) => !actualKeys.includes(key));\n if (missingKeys.length > 0) {\n throw new Error(\n `Missing expected keys in response: ${missingKeys.join(', ')}. Got: ${actualKeys.join(', ')}`,\n );\n }\n },\n\n\n assertExists<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to exist');\n }\n },\n\n assertType<T>(value: unknown, type: string, message?: string): asserts value is T {\n if (typeof value !== type) {\n throw new Error(message || `Expected value to be of type ${type}, got ${typeof value}`);\n }\n },\n\n validateObjectProperties<T extends Record<string, unknown>>(\n obj: unknown,\n expectedProps: (keyof T)[],\n ): obj is T {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n return expectedProps.every((prop) => prop in obj);\n },\n};\n\nexport interface RouterContext extends BaseContext {\n params: Record<string, string>;\n router?: unknown;\n _matchedRoute?: string;\n _matchedRouteName?: string;\n}\n\n\nexport type RouterMiddleware<TContext = BaseContext> = (\n ctx: TContext,\n next: () => Promise<void>\n) => Promise<void> | void;\n\n\nexport interface RouterLayer<TContext = BaseContext> {\n path: string | RegExp;\n methods: string[];\n stack: RouterMiddleware<TContext>[];\n name?: string | null;\n}\n\n\nexport interface RouterLike<TContext = BaseContext> {\n stack: RouterLayer<TContext>[];\n}\n\nexport async function executeRoute<TContext extends BaseContext = BaseContext>(\n router: { stack: { path: string | RegExp; methods: string[]; stack: unknown[] }[] },\n path: string,\n method: string,\n ctx: TContext,\n): Promise<void> {\n const route = router.stack.find(\n (layer) => layer.path === path && layer.methods.includes(method)\n );\n\n if (!route) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Cast context to include router properties\n // We add these properties dynamically, so TypeScript needs to trust us here\n const routerCtx = ctx as TContext & RouterContext;\n if (!routerCtx.params) {\n routerCtx.params = {};\n }\n if (!routerCtx.router) {\n routerCtx.router = router;\n }\n if (!routerCtx._matchedRoute) {\n routerCtx._matchedRoute = path;\n }\n\n // Execute all middlewares in the stack (validation, then handler)\n // Build the middleware chain from right to left\n let index = -1;\n\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n if (i >= route.stack.length) {\n return;\n }\n\n const middleware = route.stack[i] as (ctx: unknown, next: () => Promise<void>) => Promise<void>;\n return await middleware(routerCtx, () => dispatch(i + 1));\n };\n\n await dispatch(0);\n}\n"],"names":["createMockContext","overrides","ctx","request","body","headers","response","status","undefined","params","query","state","method","path","get","field","toLowerCase","set","value","createMockUser","userUuid","email","firstName","lastName","avatar","role","isSubscriptionActive","createAuthenticatedContext","userOverrides","contextOverrides","user","authorization","mockDatabase","mockModel","methods","findOne","findAll","findByPk","create","update","destroy","count","flushPromises","Promise","resolve","setImmediate","TEST_CONSTANTS","VALID_UUID","INVALID_UUID","VALID_TIMEZONE","INVALID_TIMEZONE","DEFAULT_TIMEZONE","TEST_DATE","WEEK_START","MAX_JSON_SIZE","createMockFile","fieldname","originalname","encoding","mimetype","buffer","Buffer","from","size","createMockFiles","Array","length","_","i","createMockTransaction","mockFn","globalThis","jest","fn","Error","commit","mockResolvedValue","rollback","setupDatabaseMocks","mocks","findOrCreate","upsert","bulkCreate","reset","Object","values","forEach","mock","mockReset","restore","mockRestore","setupTimeMocks","jestGlobal","beforeEachGlobal","beforeEach","afterEachGlobal","afterEach","useFakeTimers","useRealTimers","setTime","date","setSystemTime","Date","advanceTime","ms","advanceTimersByTime","MockValidationError","message","issues","name","MockNotFoundError","MockDatabaseError","createTypedMock","spyOnPrototype","prototype","spyOn","assertions","assertDefined","assertStatusCode","expected","JSON","stringify","assertResponseShape","expectedKeys","actualKeys","keys","missingKeys","filter","key","includes","join","assertExists","assertType","type","validateObjectProperties","obj","expectedProps","every","prop","executeRoute","router","route","stack","find","layer","routerCtx","_matchedRoute","index","dispatch","middleware"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/testing/testHelpers.ts"],"sourcesContent":["import type { UserTypes } from '../models/UserInterfaces.js';\n\n\nexport interface BaseContext {\n request: {\n body?: unknown;\n headers?: Record<string, string | string[] | undefined>;\n files?: unknown;\n };\n response: {\n status: number;\n body?: unknown;\n };\n params?: Record<string, string>;\n query?: Record<string, string | string[] | undefined>;\n state: Record<string, unknown>;\n status: number;\n body?: unknown;\n headers: Record<string, string | string[] | undefined>;\n method?: string;\n path?: string;\n get: (field: string) => string | string[] | undefined;\n set: (field: string, value: string) => void;\n}\n\n\nexport function createMockContext<T extends BaseContext = BaseContext>(\n overrides: Partial<T> = {},\n): T {\n const ctx: BaseContext = {\n request: {\n body: {},\n headers: {},\n ...overrides.request,\n },\n response: {\n status: 200,\n body: undefined,\n ...overrides.response,\n },\n params: overrides.params || {},\n query: overrides.query || {},\n state: overrides.state || {},\n status: overrides.status || 200,\n body: overrides.body,\n headers: overrides.headers || {},\n method: overrides.method || 'GET',\n path: overrides.path || '/',\n get: (field: string) => {\n return ctx.headers[field.toLowerCase()];\n },\n set: (field: string, value: string) => {\n ctx.headers[field.toLowerCase()] = value;\n },\n };\n\n return { ...ctx, ...overrides } as T;\n}\n\n\nexport function createMockUser(overrides: Partial<UserTypes> = {}): UserTypes {\n return {\n userUuid: overrides.userUuid || 'test-user-uuid',\n email: overrides.email || 'test@example.com',\n firstName: overrides.firstName || 'Test',\n lastName: overrides.lastName || 'User',\n avatar: overrides.avatar || '1',\n role: overrides.role || 'user',\n isSubscriptionActive: overrides.isSubscriptionActive ?? true,\n ...overrides,\n };\n}\n\n\nexport interface AuthenticatedContext extends BaseContext {\n state: {\n user: UserTypes;\n [key: string]: unknown;\n };\n}\n\n\nexport function createAuthenticatedContext<T extends BaseContext = AuthenticatedContext>(\n userOverrides: Partial<UserTypes> = {},\n contextOverrides: Partial<T> = {},\n): T {\n const user = createMockUser(userOverrides);\n\n return createMockContext<T>({\n ...contextOverrides,\n state: {\n user,\n ...(contextOverrides.state || {}),\n },\n headers: {\n authorization: 'Bearer mock-token',\n ...(contextOverrides.headers || {}),\n },\n } as Partial<T>);\n}\n\nexport interface SequelizeModelMethods<T = unknown> {\n findOne: ((options?: unknown) => Promise<T | null>) | undefined;\n findAll: ((options?: unknown) => Promise<T[]>) | undefined;\n findByPk: ((id: string | number, options?: unknown) => Promise<T | null>) | undefined;\n create: ((values: Partial<T>, options?: unknown) => Promise<T>) | undefined;\n update: ((values: Partial<T>, options?: unknown) => Promise<[number, T[]]>) | undefined;\n destroy: ((options?: unknown) => Promise<number>) | undefined;\n count: ((options?: unknown) => Promise<number>) | undefined;\n}\n\n\nexport const mockDatabase = {\n\n mockModel<T = unknown>(\n methods: Partial<SequelizeModelMethods<T>> = {},\n ): SequelizeModelMethods<T> {\n return {\n findOne: undefined,\n findAll: undefined,\n findByPk: undefined,\n create: undefined,\n update: undefined,\n destroy: undefined,\n count: undefined,\n ...methods,\n };\n },\n};\n\n\nexport async function flushPromises(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\n\nexport const assertions = {\n\n assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to be defined');\n }\n },\n\n\n assertStatusCode(ctx: BaseContext | { status: number; body?: unknown }, expected: number): void {\n if (ctx.status !== expected) {\n throw new Error(\n `Expected status ${expected} but got ${ctx.status}. Body: ${JSON.stringify(ctx.body)}`,\n );\n }\n },\n\n assertResponseShape(\n body: unknown,\n expectedKeys: string[],\n ): asserts body is Record<string, unknown> {\n if (typeof body !== 'object' || body === null) {\n throw new Error('Expected body to be an object');\n }\n const actualKeys = Object.keys(body);\n const missingKeys = expectedKeys.filter((key) => !actualKeys.includes(key));\n if (missingKeys.length > 0) {\n throw new Error(\n `Missing expected keys in response: ${missingKeys.join(', ')}. Got: ${actualKeys.join(', ')}`,\n );\n }\n },\n\n\n assertExists<T>(value: T | null | undefined, message?: string): asserts value is T {\n if (value === null || value === undefined) {\n throw new Error(message || 'Expected value to exist');\n }\n },\n\n assertType<T>(value: unknown, type: string, message?: string): asserts value is T {\n if (typeof value !== type) {\n throw new Error(message || `Expected value to be of type ${type}, got ${typeof value}`);\n }\n },\n\n validateObjectProperties<T extends Record<string, unknown>>(\n obj: unknown,\n expectedProps: (keyof T)[],\n ): obj is T {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n return expectedProps.every((prop) => prop in obj);\n },\n};\n\nexport interface RouterContext extends BaseContext {\n params: Record<string, string>;\n router?: unknown;\n _matchedRoute?: string;\n _matchedRouteName?: string;\n}\n\n\nexport type RouterMiddleware<TContext = BaseContext> = (\n ctx: TContext,\n next: () => Promise<void>\n) => Promise<void> | void;\n\n\nexport interface RouterLayer<TContext = BaseContext> {\n path: string | RegExp;\n methods: string[];\n stack: RouterMiddleware<TContext>[];\n name?: string | null;\n}\n\n\nexport interface RouterLike<TContext = BaseContext> {\n stack: RouterLayer<TContext>[];\n}\n\nexport async function executeRoute<TContext extends BaseContext = BaseContext>(\n router: { stack: { path: string | RegExp; methods: string[]; stack: unknown[] }[] },\n path: string,\n method: string,\n ctx: TContext,\n): Promise<void> {\n const route = router.stack.find(\n (layer) => layer.path === path && layer.methods.includes(method)\n );\n\n if (!route) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Cast context to include router properties\n // We add these properties dynamically, so TypeScript needs to trust us here\n const routerCtx = ctx as TContext & RouterContext;\n if (!routerCtx.params) {\n routerCtx.params = {};\n }\n if (!routerCtx.router) {\n routerCtx.router = router;\n }\n if (!routerCtx._matchedRoute) {\n routerCtx._matchedRoute = path;\n }\n\n // Execute all middlewares in the stack (validation, then handler)\n // Build the middleware chain from right to left\n let index = -1;\n\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n if (i >= route.stack.length) {\n return;\n }\n\n const middleware = route.stack[i] as (ctx: unknown, next: () => Promise<void>) => Promise<void>;\n return await middleware(routerCtx, () => dispatch(i + 1));\n };\n\n await dispatch(0);\n}\n"],"names":["createMockContext","overrides","ctx","request","body","headers","response","status","undefined","params","query","state","method","path","get","field","toLowerCase","set","value","createMockUser","userUuid","email","firstName","lastName","avatar","role","isSubscriptionActive","createAuthenticatedContext","userOverrides","contextOverrides","user","authorization","mockDatabase","mockModel","methods","findOne","findAll","findByPk","create","update","destroy","count","flushPromises","Promise","resolve","setImmediate","assertions","assertDefined","message","Error","assertStatusCode","expected","JSON","stringify","assertResponseShape","expectedKeys","actualKeys","Object","keys","missingKeys","filter","key","includes","length","join","assertExists","assertType","type","validateObjectProperties","obj","expectedProps","every","prop","executeRoute","router","route","stack","find","layer","routerCtx","_matchedRoute","index","dispatch","i","middleware"],"mappings":"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"}
|