Skip to content

Commit d18b635

Browse files
MannyManny
Manny
authored and
Manny
committed
fix(component): axios-jest-test-fix
- Added axios jest test fix BREAKING CHANGE: Cookies are now restricted based the env vars and there are new env vars that prevent emails being sent for local development fix #1
1 parent ca696cc commit d18b635

File tree

8 files changed

+58
-28
lines changed

8 files changed

+58
-28
lines changed

.env.example

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
PORT=5000
22
NODE_ENV=development
33
VERSION=1.0.0
4+
ENABLE_EMAIL=false
5+
CORS_ALLOW=http://localhost:3000;https://localhost:5000;http://app.local
6+
COOKIE_ALLOW=
47

58
JWT_SECRET=jwt_secret_key
69
JWT_ISSUER=api.localhost
@@ -16,7 +19,7 @@ JWT_RESET_MAX_AGE=300
1619
CSRF_COOKIE_PREFIX=nodetscookie
1720
CSRF_COOKIE_MAXAGE=900
1821

19-
MAILGUN_API_URL=
22+
MAILGUN_API_URL=https://api.mailgun.net/v3
2023
MAILGUN_SECRET_KEY=
2124
MAILGUN_DOMAIN=
2225

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"name": "nodets-bootstrap",
2+
"name": "nodets-rest-auth-bootstrap",
33
"version": "1.0.3",
44
"main": "src/index.js",
5-
"repository": "https://github.com/codingwithmanny/nodets-base",
5+
"repository": "https://github.com/codingwithmanny/nodets-rest-auth-bootstrap",
66
"author": "@codingwithmanny",
77
"license": "MIT",
88
"scripts": {
@@ -11,8 +11,8 @@
1111
"dev": "ts-node-dev src/server.ts",
1212
"start": "export NODE_ENV=production && tsc && node build/server.js",
1313
"test": "yarn test:lint && yarn test:coverage",
14-
"test:jest": "./node_modules/.bin/jest --watch",
15-
"test:coverage": "./node_modules/.bin/jest --coverage",
14+
"test:jest": "./node_modules/.bin/jest --watch src",
15+
"test:coverage": "./node_modules/.bin/jest --coverage src",
1616
"test:lint": "./node_modules/.bin/eslint '*/**/*.{js,ts}' --quiet --fix",
1717
"db:save": "./node_modules/.bin/prisma migrate save --experimental",
1818
"db:seed:gen": "cp ./prisma/seedings/TemplateSeeder.ts.example ./prisma/seedings/NEW.ts",

src/controllers/auth/forgot.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ router.post(
5656

5757
// Send email
5858
try {
59-
await sendResetPasswordEmail(user.email, resetToken);
59+
if (process.env.ENABLE_EMAIL === 'true') {
60+
await sendResetPasswordEmail(user.email, resetToken);
61+
}
6062
} catch (error) {
6163
return res.status(500).json(
6264
buildErrorResponse({

src/controllers/auth/login.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const prisma = new PrismaClient();
2525
// ========================================================
2626
router.post(
2727
'/',
28-
[(check('email').isEmail(), check('password').isLength({ min: 8 }))],
28+
[check('email').isString(), check('password').isLength({ min: 8 })],
2929
validation,
3030
async (req: Request, res: Response) => {
3131
// Get body
@@ -78,12 +78,18 @@ router.post(
7878
res.cookie('token', token, {
7979
httpOnly: true,
8080
maxAge: parseInt(process.env.JWT_MAX_AGE || '900') * 1000,
81+
// domain: '.app.local',
82+
path: '/',
83+
secure: process.env.NODE_ENV === 'production' ? true : false,
8184
});
8285

8386
// 6. Set refresh token cookie
8487
res.cookie('refreshToken', refreshToken, {
8588
httpOnly: true,
8689
maxAge: parseInt(process.env.JWT_REFRESH_MAX_AGE || '604800') * 1000,
90+
// domain: '.app.local',
91+
path: '/',
92+
secure: process.env.NODE_ENV === 'production' ? true : false,
8793
});
8894

8995
// 7. Send token data

src/controllers/auth/refresh.ts

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ router.get('/', async (req: Request, res: Response) => {
2222
const token: string = req.cookies.refreshToken;
2323

2424
try {
25+
if (!token) {
26+
throw new Error(CONST.AUTH.REFRESH.ERRORS.INVALID);
27+
}
2528
const verify = verifyRefreshToken(token);
2629

2730
const users: User[] | null = await prisma.user.findMany({

src/controllers/auth/register.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ router.post(
5555
});
5656

5757
// Send email
58-
await sendConfirmAccountEmail(body.email, confirmationToken);
58+
if (process.env.ENABLE_EMAIL === 'true') {
59+
await sendConfirmAccountEmail(body.email, confirmationToken);
60+
}
5961

6062
return res.json(
6163
buildSuccessResponse({
@@ -64,7 +66,9 @@ router.post(
6466
);
6567
} catch (error) {
6668
// Fail if could not create user (ex: duplicate record)
67-
return res.json(buildErrorResponse({ msg: ErrorDefinition(error) }));
69+
return res
70+
.status(400)
71+
.json(buildErrorResponse({ msg: ErrorDefinition(error) }));
6872
}
6973
},
7074
);

src/index.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// ========================================================
33
import * as dotenv from 'dotenv';
44
import express from 'express';
5-
import cors from 'express';
5+
import cors from 'cors';
66
import helmet from 'helmet';
77
import csrf from 'csurf';
88
import cookieParser from 'cookie-parser';
@@ -22,19 +22,25 @@ const app = express();
2222

2323
// Middlewares
2424
// ========================================================
25-
app.use(cors());
25+
app.use(
26+
cors({
27+
origin: `${process.env.CORS_ALLOW || 'http://localhost:5000'}`.split(';'),
28+
}),
29+
);
30+
2631
app.use(helmet());
2732
app.use(cookieParser());
2833
app.use(express.json());
2934
app.use(
3035
csrf({
3136
cookie: {
32-
key: process.env.CSRF_COOKIE_PREFIX || '',
37+
key: process.env.CSRF_COOKIE_PREFIX || '_csrf',
3338
maxAge: parseInt(process.env.CSRF_COOKIE_MAXAGE || '900'),
3439
signed: NODE_ENV === 'production' ? true : false, // signature
3540
secure: NODE_ENV === 'production' ? true : false, // https
3641
httpOnly: true,
3742
sameSite: NODE_ENV === 'production' ? true : false, // sets the same site policy for the cookie
43+
domain: process.env.COOKIE_ALLOW || 'http://localhost:5000',
3844
},
3945
}),
4046
);

src/utils/__tests__/index.ts

+22-16
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
// ========================================================
33
import faker from 'faker';
44
import jwtDecode from 'jwt-decode';
5-
import { User } from '@prisma/client';
6-
import axios, { AxiosRequestConfig } from 'axios';
5+
import axios from 'axios';
76
import formData from 'form-data';
7+
import bcrypt from 'bcrypt';
8+
import { User } from '@prisma/client';
89
import {
910
hashPassword,
1011
getGeneratedToken,
@@ -25,11 +26,11 @@ import {
2526

2627
// Mocks
2728
// ========================================================
28-
const axiosPost = jest.fn();
29-
jest.mock('axios');
30-
(axios as jest.Mocked<typeof axios>).post.mockImplementation(
31-
jest.fn().mockImplementation(axiosPost),
32-
);
29+
jest.mock('axios', () => {
30+
return Object.assign(jest.fn(), {
31+
post: jest.fn().mockReturnValue({ success: true }),
32+
});
33+
});
3334

3435
const formDataAppend = jest.fn();
3536
const formDataGetHeaders = jest.fn();
@@ -361,14 +362,16 @@ test('test - sendEmail - [email protected], [email protected], my subject, hello ther
361362
const subject = 'my subject';
362363
const body = 'hello there!';
363364
const basicAuth = Buffer.from(`api:secret`).toString('base64');
365+
const spyOnAxiosPost = jest.spyOn(axios, 'post');
364366

367+
process.env.ENABLE_EMAIL = 'true';
365368
process.env.MAILGUN_API_URL = 'url';
366369
process.env.MAILGUN_DOMAIN = 'domain';
367370
process.env.MAILGUN_SECRET_KEY = 'secret';
368371

369372
// Pre Expectations
370373
expect(formData).not.toHaveBeenCalled();
371-
expect(axiosPost).not.toHaveBeenCalled();
374+
expect(spyOnAxiosPost).not.toBeCalled();
372375

373376
// Init
374377
const result = await sendEmail(from, to, subject, body);
@@ -388,7 +391,7 @@ test('test - sendEmail - [email protected], [email protected], my subject, hello ther
388391
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);
389392

390393
// Axios
391-
expect(axiosPost).toHaveBeenCalledTimes(1);
394+
expect(spyOnAxiosPost).toBeCalledTimes(1);
392395
expect(axios.post).toHaveBeenCalledWith(
393396
'url/domain/messages',
394397
{ append: formDataAppend, getHeaders: formDataGetHeaders },
@@ -399,7 +402,7 @@ test('test - sendEmail - [email protected], [email protected], my subject, hello ther
399402
},
400403
},
401404
);
402-
expect(result).toBe(undefined);
405+
expect(result).toStrictEqual({ success: true });
403406
});
404407

405408
/**
@@ -413,14 +416,16 @@ test('test - sendResetPasswordEmail - [email protected], [email protected], my subjec
413416
const body =
414417
'<p>Here is the link to <a href="/asdf1234">reset your password</a>.</p><p><a href="/asdf1234">/asdf1234</a></p>.';
415418
const basicAuth = Buffer.from(`api:secret`).toString('base64');
419+
const spyOnAxiosPost = jest.spyOn(axios, 'post');
416420

421+
process.env.ENABLE_EMAIL = 'true';
417422
process.env.MAILGUN_DOMAIN = 'domain';
418423
process.env.MAILGUN_SECRET_KEY = 'secret';
419424
process.env.EMAIL_SUBJECT_RESET = subject;
420425

421426
// Pre Expectations
422427
expect(formData).not.toHaveBeenCalled();
423-
expect(axiosPost).not.toHaveBeenCalled();
428+
expect(spyOnAxiosPost).not.toBeCalled();
424429

425430
// Init
426431
const result = await sendResetPasswordEmail(to, 'asdf1234');
@@ -440,7 +445,7 @@ test('test - sendResetPasswordEmail - [email protected], [email protected], my subjec
440445
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);
441446

442447
// Axios
443-
expect(axiosPost).toHaveBeenCalledTimes(1);
448+
expect(spyOnAxiosPost).toBeCalledTimes(1);
444449
expect(axios.post).toHaveBeenCalledWith(
445450
'url/domain/messages',
446451
{ append: formDataAppend, getHeaders: formDataGetHeaders },
@@ -451,7 +456,7 @@ test('test - sendResetPasswordEmail - [email protected], [email protected], my subjec
451456
},
452457
},
453458
);
454-
expect(result).toBe(undefined);
459+
expect(result).toStrictEqual({ success: true });
455460
});
456461

457462
/**
@@ -465,14 +470,15 @@ test('test - sendConfirmAccountEmail - [email protected], [email protected], my subje
465470
const body =
466471
'<p>Here is the link to <a href="/asdf1234">confirm your account</a>.</p><p><a href="/asdf1234">/asdf1234</a></p>.';
467472
const basicAuth = Buffer.from(`api:secret`).toString('base64');
473+
const spyOnAxiosPost = jest.spyOn(axios, 'post');
468474

469475
process.env.MAILGUN_DOMAIN = 'domain';
470476
process.env.MAILGUN_SECRET_KEY = 'secret';
471477
process.env.EMAIL_SUBJECT_CONFIRM = subject;
472478

473479
// Pre Expectations
474480
expect(formData).not.toHaveBeenCalled();
475-
expect(axiosPost).not.toHaveBeenCalled();
481+
expect(spyOnAxiosPost).not.toBeCalled();
476482

477483
// Init
478484
const result = await sendConfirmAccountEmail(to, 'asdf1234');
@@ -492,7 +498,7 @@ test('test - sendConfirmAccountEmail - [email protected], [email protected], my subje
492498
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);
493499

494500
// Axios
495-
expect(axiosPost).toHaveBeenCalledTimes(1);
501+
expect(spyOnAxiosPost).toBeCalledTimes(1);
496502
expect(axios.post).toHaveBeenCalledWith(
497503
'url/domain/messages',
498504
{ append: formDataAppend, getHeaders: formDataGetHeaders },
@@ -503,5 +509,5 @@ test('test - sendConfirmAccountEmail - [email protected], [email protected], my subje
503509
},
504510
},
505511
);
506-
expect(result).toBe(undefined);
512+
expect(result).toStrictEqual({ success: true });
507513
});

0 commit comments

Comments
 (0)