@nathapp/nestjs-csrf 4.0.0 → 4.0.1

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.
@@ -1,267 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-var-requires */
2
- import {
3
- Controller,
4
- Get,
5
- INestApplication,
6
- Post,
7
- } from '@nestjs/common';
8
- import { Test } from '@nestjs/testing';
9
- import { CsrfModule, SkipCsrf } from '../lib';
10
-
11
- @Controller()
12
- class AppController {
13
- @Get('page')
14
- getPage(): { ok: boolean } {
15
- return { ok: true };
16
- }
17
-
18
- @Post('action')
19
- postAction(): { ok: boolean } {
20
- return { ok: true };
21
- }
22
-
23
- @Post('skip')
24
- @SkipCsrf()
25
- skipAction(): { ok: boolean } {
26
- return { ok: true };
27
- }
28
- }
29
-
30
- function extractCsrfTokenFromSetCookie(
31
- setCookieHeader: string | string[] | undefined,
32
- ): string {
33
- const raw = Array.isArray(setCookieHeader)
34
- ? setCookieHeader[0]
35
- : setCookieHeader;
36
- if (!raw) return '';
37
- const part = raw.split(';')[0];
38
- const eqIdx = part.indexOf('=');
39
- return eqIdx >= 0 ? part.slice(eqIdx + 1) : '';
40
- }
41
-
42
- describe('CsrfModule assembly and exports', () => {
43
- describe('AC1: CsrfModule.register returns global dynamic module', () => {
44
- it('AC1: returned DynamicModule has global === true when secret is provided', () => {
45
- const dynamicModule = CsrfModule.register({ secret: 's' });
46
- expect(dynamicModule).toBeDefined();
47
- expect((dynamicModule as { global?: boolean }).global).toBe(true);
48
- });
49
- });
50
-
51
- describe('AC2: POST without CSRF tokens returns 403 from a globally wired app', () => {
52
- let app: INestApplication;
53
-
54
- beforeAll(async () => {
55
- const moduleRef = await Test.createTestingModule({
56
- imports: [CsrfModule.register({ secret: 's' })],
57
- controllers: [AppController],
58
- }).compile();
59
- app = moduleRef.createNestApplication();
60
- await app.init();
61
- });
62
-
63
- afterAll(async () => {
64
- await app?.close();
65
- });
66
-
67
- it('AC2: POST /action with no CSRF cookie or header returns 403', async () => {
68
- const supertest = require('supertest');
69
- const res = await supertest(app.getHttpServer()).post('/action');
70
- expect(res.statusCode).toBe(403);
71
- });
72
- });
73
-
74
- describe('AC3: GET returns 2xx and issues Set-Cookie header for the CSRF cookie', () => {
75
- let app: INestApplication;
76
-
77
- beforeAll(async () => {
78
- const moduleRef = await Test.createTestingModule({
79
- imports: [CsrfModule.register({ secret: 's' })],
80
- controllers: [AppController],
81
- }).compile();
82
- app = moduleRef.createNestApplication();
83
- await app.init();
84
- });
85
-
86
- afterAll(async () => {
87
- await app?.close();
88
- });
89
-
90
- it('AC3: GET /page returns 2xx and Set-Cookie header contains the configured CSRF cookie', async () => {
91
- const supertest = require('supertest');
92
- const res = await supertest(app.getHttpServer()).get('/page');
93
- expect(res.statusCode).toBeGreaterThanOrEqual(200);
94
- expect(res.statusCode).toBeLessThan(300);
95
- const setCookie: string | string[] | undefined = res.headers['set-cookie'];
96
- expect(setCookie).toBeDefined();
97
- const cookieStr = Array.isArray(setCookie)
98
- ? setCookie.join(', ')
99
- : setCookie ?? '';
100
- expect(cookieStr).toContain('csrf-token');
101
- const tokenValue = extractCsrfTokenFromSetCookie(setCookie);
102
- expect(tokenValue.length).toBeGreaterThan(0);
103
- });
104
- });
105
-
106
- describe('AC4: full double-submit round-trip returns 2xx', () => {
107
- let app: INestApplication;
108
-
109
- beforeAll(async () => {
110
- const moduleRef = await Test.createTestingModule({
111
- imports: [CsrfModule.register({ secret: 's' })],
112
- controllers: [AppController],
113
- }).compile();
114
- app = moduleRef.createNestApplication();
115
- const cookieParser = require('cookie-parser');
116
- app.use(cookieParser());
117
- await app.init();
118
- });
119
-
120
- afterAll(async () => {
121
- await app?.close();
122
- });
123
-
124
- it('AC4: GET-obtained CSRF cookie echoed in cookie + x-csrf-token header lets POST return 2xx', async () => {
125
- const supertest = require('supertest');
126
- const getRes = await supertest(app.getHttpServer()).get('/page');
127
- expect(getRes.statusCode).toBeGreaterThanOrEqual(200);
128
- const tokenValue = extractCsrfTokenFromSetCookie(getRes.headers['set-cookie']);
129
- expect(tokenValue.length).toBeGreaterThan(0);
130
-
131
- const postRes = await supertest(app.getHttpServer())
132
- .post('/action')
133
- .set('Cookie', `csrf-token=${tokenValue}`)
134
- .set('x-csrf-token', tokenValue);
135
- expect(postRes.statusCode).toBeGreaterThanOrEqual(200);
136
- expect(postRes.statusCode).toBeLessThan(300);
137
- });
138
- });
139
-
140
- describe('AC5: enabled: false short-circuits CSRF protection', () => {
141
- let app: INestApplication;
142
-
143
- beforeAll(async () => {
144
- const moduleRef = await Test.createTestingModule({
145
- imports: [CsrfModule.register({ secret: 's', enabled: false })],
146
- controllers: [AppController],
147
- }).compile();
148
- app = moduleRef.createNestApplication();
149
- await app.init();
150
- });
151
-
152
- afterAll(async () => {
153
- await app?.close();
154
- });
155
-
156
- it('AC5: POST /action without CSRF tokens returns 2xx when enabled is false', async () => {
157
- const supertest = require('supertest');
158
- const res = await supertest(app.getHttpServer()).post('/action');
159
- expect(res.statusCode).toBeGreaterThanOrEqual(200);
160
- expect(res.statusCode).toBeLessThan(300);
161
- });
162
- });
163
-
164
- describe('AC6: @SkipCsrf() handler bypasses CSRF protection', () => {
165
- let app: INestApplication;
166
-
167
- beforeAll(async () => {
168
- const moduleRef = await Test.createTestingModule({
169
- imports: [CsrfModule.register({ secret: 's' })],
170
- controllers: [AppController],
171
- }).compile();
172
- app = moduleRef.createNestApplication();
173
- await app.init();
174
- });
175
-
176
- afterAll(async () => {
177
- await app?.close();
178
- });
179
-
180
- it('AC6: POST /skip with no CSRF tokens returns 2xx because the handler is decorated with @SkipCsrf()', async () => {
181
- const supertest = require('supertest');
182
- const res = await supertest(app.getHttpServer()).post('/skip');
183
- expect(res.statusCode).toBeGreaterThanOrEqual(200);
184
- expect(res.statusCode).toBeLessThan(300);
185
- });
186
- });
187
-
188
- describe('AC7: registerAsync applies the guard and rejects tokenless POST', () => {
189
- let app: INestApplication;
190
-
191
- beforeAll(async () => {
192
- const moduleRef = await Test.createTestingModule({
193
- imports: [
194
- CsrfModule.registerAsync({ useFactory: () => ({ secret: 's' }) }),
195
- ],
196
- controllers: [AppController],
197
- }).compile();
198
- app = moduleRef.createNestApplication();
199
- await app.init();
200
- });
201
-
202
- afterAll(async () => {
203
- await app?.close();
204
- });
205
-
206
- it('AC7: POST /action without CSRF tokens returns 403 when registered via registerAsync', async () => {
207
- const supertest = require('supertest');
208
- const res = await supertest(app.getHttpServer()).post('/action');
209
- expect(res.statusCode).toBe(403);
210
- });
211
- });
212
-
213
- describe('AC7 (boundary): registerAsync validates resolved options and fails fast on empty/missing secret', () => {
214
- it('AC7 (boundary): registerAsync throws an Error mentioning "secret" when the factory resolves an empty secret at module compile time', async () => {
215
- let thrownError: Error | undefined;
216
- try {
217
- // Validation happens when Nest resolves the async provider during compile
218
- await Test.createTestingModule({
219
- imports: [
220
- CsrfModule.registerAsync({
221
- useFactory: () => ({ secret: '' }) as never,
222
- }),
223
- ],
224
- controllers: [AppController],
225
- }).compile();
226
- } catch (err) {
227
- thrownError = err as Error;
228
- }
229
- expect(thrownError).toBeDefined();
230
- expect(thrownError).toBeInstanceOf(Error);
231
- expect(thrownError!.message).toMatch(/secret/i);
232
- });
233
-
234
- it('AC7 (boundary): registerAsync throws an Error mentioning "secret" when the factory resolves without a secret key at module compile time', async () => {
235
- let thrownError: Error | undefined;
236
- try {
237
- await Test.createTestingModule({
238
- imports: [
239
- CsrfModule.registerAsync({
240
- useFactory: () => ({}) as never,
241
- }),
242
- ],
243
- controllers: [AppController],
244
- }).compile();
245
- } catch (err) {
246
- thrownError = err as Error;
247
- }
248
- expect(thrownError).toBeDefined();
249
- expect(thrownError).toBeInstanceOf(Error);
250
- expect(thrownError!.message).toMatch(/secret/i);
251
- });
252
- });
253
-
254
- describe('AC8: register without secret throws at registration time', () => {
255
- it('AC8: throws an Error whose message mentions "secret"', () => {
256
- let thrownError: Error | undefined;
257
- try {
258
- CsrfModule.register({} as never);
259
- } catch (err) {
260
- thrownError = err as Error;
261
- }
262
- expect(thrownError).toBeDefined();
263
- expect(thrownError).toBeInstanceOf(Error);
264
- expect(thrownError!.message).toMatch(/secret/i);
265
- });
266
- });
267
- });
@@ -1,347 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-var-requires */
2
- describe('DefaultCsrfGuard', () => {
3
- const SECRET = 'super-secret';
4
-
5
- const loadDeps = () => {
6
- const mod = require('../../lib');
7
- const errors = require('@nathapp/nestjs-common');
8
- const core = require('@nestjs/core');
9
- return {
10
- DefaultCsrfGuard: mod.DefaultCsrfGuard,
11
- CsrfTokenService: mod.CsrfTokenService,
12
- SKIP_CSRF_METADATA_KEY: mod.SKIP_CSRF_METADATA_KEY,
13
- CSRF_MODULE_OPTIONS: mod.CSRF_MODULE_OPTIONS,
14
- ForbiddenAppException: errors.ForbiddenAppException,
15
- Reflector: core.Reflector,
16
- Test: require('@nestjs/testing').Test,
17
- };
18
- };
19
-
20
- function assertGuardAvailable(deps) {
21
- expect(typeof deps.DefaultCsrfGuard).toBe('function');
22
- }
23
-
24
- function buildContext(req, res, handler) {
25
- return {
26
- switchToHttp: () => ({
27
- getRequest: () => req,
28
- getResponse: () => res,
29
- }),
30
- getHandler: () => handler,
31
- getClass: () => undefined,
32
- };
33
- }
34
-
35
- function buildSkipCsrfReflector(reflector, metadataKey) {
36
- reflector.getAllAndOverride = jest.fn().mockImplementation((key) => {
37
- if (key === metadataKey) return true;
38
- return undefined;
39
- });
40
- return reflector;
41
- }
42
-
43
- describe('AC1: provider resolution', () => {
44
- it('AC1: resolves from a compiled Nest testing module and exposes canActivate', async () => {
45
- const deps = loadDeps();
46
- expect(typeof deps.DefaultCsrfGuard).toBe('function');
47
-
48
- const moduleRef = await deps.Test.createTestingModule({
49
- providers: [
50
- deps.CsrfTokenService,
51
- {
52
- provide: deps.CSRF_MODULE_OPTIONS,
53
- useValue: { secret: SECRET },
54
- },
55
- {
56
- provide: deps.DefaultCsrfGuard,
57
- useFactory: (options, tokens, reflector) =>
58
- new deps.DefaultCsrfGuard(options, tokens, reflector),
59
- inject: [deps.CSRF_MODULE_OPTIONS, deps.CsrfTokenService, deps.Reflector],
60
- },
61
- ],
62
- }).compile();
63
-
64
- const guard = moduleRef.get(deps.DefaultCsrfGuard);
65
- expect(guard).toBeDefined();
66
- expect(typeof guard.canActivate).toBe('function');
67
- });
68
- });
69
-
70
- describe('AC2: Express GET auto-issues via res.cookie', () => {
71
- it('AC2: returns true and calls res.cookie with the configured cookie name and a minted token', () => {
72
- const deps = loadDeps();
73
- assertGuardAvailable(deps);
74
-
75
- const tokens = new deps.CsrfTokenService();
76
- const reflector = new deps.Reflector();
77
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
78
-
79
- const cookieFn = jest.fn();
80
- const req = { method: 'GET', headers: {}, cookies: {} };
81
- const res = { cookie: cookieFn };
82
- const context = buildContext(req, res, undefined);
83
-
84
- const result = guard.canActivate(context);
85
-
86
- expect(result).toBe(true);
87
- expect(cookieFn).toHaveBeenCalledTimes(1);
88
- const [name, tokenValue] = cookieFn.mock.calls[0];
89
- expect(name).toBe('csrf-token');
90
- expect(typeof tokenValue).toBe('string');
91
- expect(tokenValue).toMatch(/^[0-9a-f]{64}\.[0-9a-f]{64}$/);
92
- });
93
- });
94
-
95
- describe('AC3: Fastify GET auto-issues via res.setCookie', () => {
96
- it('AC3: returns true and calls res.setCookie (not res.cookie) with the configured cookie name', () => {
97
- const deps = loadDeps();
98
- assertGuardAvailable(deps);
99
-
100
- const tokens = new deps.CsrfTokenService();
101
- const reflector = new deps.Reflector();
102
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
103
-
104
- const setCookieFn = jest.fn();
105
- const cookieFn = jest.fn();
106
- const fastifyRaw = { id: 'fastify-raw' };
107
- const req = {
108
- method: 'GET',
109
- headers: {},
110
- cookies: {},
111
- raw: fastifyRaw,
112
- };
113
- const res = { setCookie: setCookieFn, cookie: cookieFn };
114
- const context = buildContext(req, res, undefined);
115
-
116
- const result = guard.canActivate(context);
117
-
118
- expect(result).toBe(true);
119
- expect(setCookieFn).toHaveBeenCalledTimes(1);
120
- expect(cookieFn).not.toHaveBeenCalled();
121
- const [name, tokenValue] = setCookieFn.mock.calls[0];
122
- expect(name).toBe('csrf-token');
123
- expect(typeof tokenValue).toBe('string');
124
- expect(tokenValue).toMatch(/^[0-9a-f]{64}\.[0-9a-f]{64}$/);
125
- });
126
- });
127
-
128
- describe('AC4: @SkipCsrf() handler bypass', () => {
129
- it('AC4: returns true on a POST with no token when the handler is decorated with @SkipCsrf()', () => {
130
- const deps = loadDeps();
131
- assertGuardAvailable(deps);
132
-
133
- const tokens = new deps.CsrfTokenService();
134
- const reflector = new deps.Reflector();
135
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
136
- buildSkipCsrfReflector(reflector, deps.SKIP_CSRF_METADATA_KEY);
137
-
138
- const verifySpy = jest.spyOn(tokens, 'verify');
139
-
140
- const req = { method: 'POST', headers: {}, cookies: {} };
141
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
142
- const handler = {};
143
- const context = buildContext(req, res, handler);
144
-
145
- const result = guard.canActivate(context);
146
-
147
- expect(result).toBe(true);
148
- expect(verifySpy).not.toHaveBeenCalled();
149
- });
150
- });
151
-
152
- describe('AC5: Bearer authorization bypass', () => {
153
- it('AC5: returns true when authorization header is Bearer and skipWhenBearer is true', () => {
154
- const deps = loadDeps();
155
- assertGuardAvailable(deps);
156
-
157
- const tokens = new deps.CsrfTokenService();
158
- const reflector = new deps.Reflector();
159
- const guard = new deps.DefaultCsrfGuard(
160
- { secret: SECRET, skipWhenBearer: true },
161
- tokens,
162
- reflector,
163
- );
164
-
165
- const verifySpy = jest.spyOn(tokens, 'verify');
166
-
167
- const req = {
168
- method: 'POST',
169
- headers: { authorization: 'Bearer abc' },
170
- cookies: {},
171
- };
172
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
173
- const context = buildContext(req, res, undefined);
174
-
175
- const result = guard.canActivate(context);
176
-
177
- expect(result).toBe(true);
178
- expect(verifySpy).not.toHaveBeenCalled();
179
- });
180
- });
181
-
182
- describe('AC6 + AC7: valid double-submit verification', () => {
183
- it('AC6: returns true when cookie and x-csrf-token header both equal a valid minted token', () => {
184
- const deps = loadDeps();
185
- assertGuardAvailable(deps);
186
-
187
- const tokens = new deps.CsrfTokenService();
188
- const reflector = new deps.Reflector();
189
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
190
-
191
- const token = tokens.mint(SECRET);
192
- const req = {
193
- method: 'POST',
194
- headers: { 'x-csrf-token': token },
195
- cookies: { 'csrf-token': token },
196
- };
197
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
198
- const context = buildContext(req, res, undefined);
199
-
200
- const result = guard.canActivate(context);
201
-
202
- expect(result).toBe(true);
203
- });
204
-
205
- it('AC7: invokes CsrfTokenService.verify with the cookie and header values', () => {
206
- const deps = loadDeps();
207
- assertGuardAvailable(deps);
208
-
209
- const tokens = new deps.CsrfTokenService();
210
- const reflector = new deps.Reflector();
211
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
212
-
213
- const token = tokens.mint(SECRET);
214
- const verifySpy = jest.spyOn(tokens, 'verify');
215
-
216
- const req = {
217
- method: 'POST',
218
- headers: { 'x-csrf-token': token },
219
- cookies: { 'csrf-token': token },
220
- };
221
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
222
- const context = buildContext(req, res, undefined);
223
-
224
- guard.canActivate(context);
225
-
226
- expect(verifySpy).toHaveBeenCalledTimes(1);
227
- const [secretArg, cookieArg, headerArg] = verifySpy.mock.calls[0];
228
- expect(secretArg).toBe(SECRET);
229
- expect(cookieArg).toBe(token);
230
- expect(headerArg).toBe(token);
231
- });
232
- });
233
-
234
- describe('AC8: cookie present, header missing', () => {
235
- it('AC8: throws ForbiddenAppException with HTTP status 403 when x-csrf-token header is absent', () => {
236
- const deps = loadDeps();
237
- assertGuardAvailable(deps);
238
-
239
- const tokens = new deps.CsrfTokenService();
240
- const reflector = new deps.Reflector();
241
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
242
-
243
- const token = tokens.mint(SECRET);
244
- const req = {
245
- method: 'POST',
246
- headers: {},
247
- cookies: { 'csrf-token': token },
248
- };
249
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
250
- const context = buildContext(req, res, undefined);
251
-
252
- try {
253
- guard.canActivate(context);
254
- throw new Error('Expected canActivate to throw ForbiddenAppException');
255
- } catch (err) {
256
- expect(err).toBeInstanceOf(deps.ForbiddenAppException);
257
- expect(err.getStatus()).toBe(403);
258
- }
259
- });
260
- });
261
-
262
- describe('AC9: cookie and header differ', () => {
263
- it('AC9: throws ForbiddenAppException with HTTP status 403 when cookie and header hold different values', () => {
264
- const deps = loadDeps();
265
- assertGuardAvailable(deps);
266
-
267
- const tokens = new deps.CsrfTokenService();
268
- const reflector = new deps.Reflector();
269
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
270
-
271
- const cookieToken = tokens.mint(SECRET);
272
- const headerToken = tokens.mint(SECRET);
273
- expect(cookieToken).not.toBe(headerToken);
274
-
275
- const req = {
276
- method: 'POST',
277
- headers: { 'x-csrf-token': headerToken },
278
- cookies: { 'csrf-token': cookieToken },
279
- };
280
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
281
- const context = buildContext(req, res, undefined);
282
-
283
- try {
284
- guard.canActivate(context);
285
- throw new Error('Expected canActivate to throw ForbiddenAppException');
286
- } catch (err) {
287
- expect(err).toBeInstanceOf(deps.ForbiddenAppException);
288
- expect(err.getStatus()).toBe(403);
289
- }
290
- });
291
- });
292
-
293
- describe('AC10: header present, cookie missing', () => {
294
- it('AC10: throws ForbiddenAppException with HTTP status 403 when CSRF cookie is absent', () => {
295
- const deps = loadDeps();
296
- assertGuardAvailable(deps);
297
-
298
- const tokens = new deps.CsrfTokenService();
299
- const reflector = new deps.Reflector();
300
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
301
-
302
- const token = tokens.mint(SECRET);
303
- const req = {
304
- method: 'POST',
305
- headers: { 'x-csrf-token': token },
306
- cookies: {},
307
- };
308
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
309
- const context = buildContext(req, res, undefined);
310
-
311
- try {
312
- guard.canActivate(context);
313
- throw new Error('Expected canActivate to throw ForbiddenAppException');
314
- } catch (err) {
315
- expect(err).toBeInstanceOf(deps.ForbiddenAppException);
316
- expect(err.getStatus()).toBe(403);
317
- }
318
- });
319
- });
320
-
321
- describe('AC11: cookie parser not enabled', () => {
322
- it('AC11: throws ForbiddenAppException with HTTP status 403 when req.cookies is undefined', () => {
323
- const deps = loadDeps();
324
- assertGuardAvailable(deps);
325
-
326
- const tokens = new deps.CsrfTokenService();
327
- const reflector = new deps.Reflector();
328
- const guard = new deps.DefaultCsrfGuard({ secret: SECRET }, tokens, reflector);
329
-
330
- const req = {
331
- method: 'POST',
332
- headers: { 'x-csrf-token': 'irrelevant' },
333
- cookies: undefined,
334
- };
335
- const res = { cookie: jest.fn(), setCookie: jest.fn() };
336
- const context = buildContext(req, res, undefined);
337
-
338
- try {
339
- guard.canActivate(context);
340
- throw new Error('Expected canActivate to throw ForbiddenAppException');
341
- } catch (err) {
342
- expect(err).toBeInstanceOf(deps.ForbiddenAppException);
343
- expect(err.getStatus()).toBe(403);
344
- }
345
- });
346
- });
347
- });
@@ -1,27 +0,0 @@
1
- {
2
- "moduleFileExtensions": ["js", "json", "ts", "d.ts"],
3
- "rootDir": "../",
4
- "testEnvironment": "node",
5
- "testMatch": ["**/.nax/**/*.test.ts"],
6
- "transform": {
7
- "^.+\\.(t)s$": [
8
- "ts-jest",
9
- {
10
- "diagnostics": true,
11
- "tsconfig": {
12
- "esModuleInterop": true,
13
- "emitDecoratorMetadata": true,
14
- "experimentalDecorators": true
15
- }
16
- }
17
- ]
18
- },
19
- "collectCoverageFrom": [
20
- "lib/**/*.ts",
21
- "!lib/**/*.spec.ts",
22
- "!lib/**/*.d.ts",
23
- "!**/node_modules/**"
24
- ],
25
- "forceExit": true,
26
- "maxWorkers": 1
27
- }
@@ -1,28 +0,0 @@
1
- {
2
- "moduleFileExtensions": [
3
- "js",
4
- "json",
5
- "ts",
6
- "d.ts"
7
- ],
8
- "rootDir": "../",
9
- "testEnvironment": "node",
10
- "testRegex": ".spec.ts$",
11
- "transform": {
12
- "^.+\\.(t)s$": [
13
- "ts-jest",
14
- {
15
- "diagnostics": true
16
- }
17
- ]
18
- },
19
- "collectCoverageFrom": [
20
- "lib/**/*.ts",
21
- "!lib/**/*.spec.ts",
22
- "!lib/**/*.d.ts",
23
- "!lib/**/index.ts",
24
- "!lib/**/*.interface.ts",
25
- "!**/node_modules/**"
26
- ],
27
- "coverageProvider": "v8"
28
- }