Skip to content

Commit

Permalink
fix(component): axios-jest-test-fix
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Manny authored and Manny committed Jul 9, 2020
1 parent ca696cc commit d18b635
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 28 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
PORT=5000
NODE_ENV=development
VERSION=1.0.0
ENABLE_EMAIL=false
CORS_ALLOW=http://localhost:3000;https://localhost:5000;http://app.local
COOKIE_ALLOW=

JWT_SECRET=jwt_secret_key
JWT_ISSUER=api.localhost
Expand All @@ -16,7 +19,7 @@ JWT_RESET_MAX_AGE=300
CSRF_COOKIE_PREFIX=nodetscookie
CSRF_COOKIE_MAXAGE=900

MAILGUN_API_URL=
MAILGUN_API_URL=https://api.mailgun.net/v3
MAILGUN_SECRET_KEY=
MAILGUN_DOMAIN=

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "nodets-bootstrap",
"name": "nodets-rest-auth-bootstrap",
"version": "1.0.3",
"main": "src/index.js",
"repository": "https://github.com/codingwithmanny/nodets-base",
"repository": "https://github.com/codingwithmanny/nodets-rest-auth-bootstrap",
"author": "@codingwithmanny",
"license": "MIT",
"scripts": {
Expand All @@ -11,8 +11,8 @@
"dev": "ts-node-dev src/server.ts",
"start": "export NODE_ENV=production && tsc && node build/server.js",
"test": "yarn test:lint && yarn test:coverage",
"test:jest": "./node_modules/.bin/jest --watch",
"test:coverage": "./node_modules/.bin/jest --coverage",
"test:jest": "./node_modules/.bin/jest --watch src",
"test:coverage": "./node_modules/.bin/jest --coverage src",
"test:lint": "./node_modules/.bin/eslint '*/**/*.{js,ts}' --quiet --fix",
"db:save": "./node_modules/.bin/prisma migrate save --experimental",
"db:seed:gen": "cp ./prisma/seedings/TemplateSeeder.ts.example ./prisma/seedings/NEW.ts",
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/auth/forgot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ router.post(

// Send email
try {
await sendResetPasswordEmail(user.email, resetToken);
if (process.env.ENABLE_EMAIL === 'true') {
await sendResetPasswordEmail(user.email, resetToken);
}
} catch (error) {
return res.status(500).json(
buildErrorResponse({
Expand Down
8 changes: 7 additions & 1 deletion src/controllers/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const prisma = new PrismaClient();
// ========================================================
router.post(
'/',
[(check('email').isEmail(), check('password').isLength({ min: 8 }))],
[check('email').isString(), check('password').isLength({ min: 8 })],
validation,
async (req: Request, res: Response) => {
// Get body
Expand Down Expand Up @@ -78,12 +78,18 @@ router.post(
res.cookie('token', token, {
httpOnly: true,
maxAge: parseInt(process.env.JWT_MAX_AGE || '900') * 1000,
// domain: '.app.local',
path: '/',
secure: process.env.NODE_ENV === 'production' ? true : false,
});

// 6. Set refresh token cookie
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
maxAge: parseInt(process.env.JWT_REFRESH_MAX_AGE || '604800') * 1000,
// domain: '.app.local',
path: '/',
secure: process.env.NODE_ENV === 'production' ? true : false,
});

// 7. Send token data
Expand Down
3 changes: 3 additions & 0 deletions src/controllers/auth/refresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ router.get('/', async (req: Request, res: Response) => {
const token: string = req.cookies.refreshToken;

try {
if (!token) {
throw new Error(CONST.AUTH.REFRESH.ERRORS.INVALID);
}
const verify = verifyRefreshToken(token);

const users: User[] | null = await prisma.user.findMany({
Expand Down
8 changes: 6 additions & 2 deletions src/controllers/auth/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ router.post(
});

// Send email
await sendConfirmAccountEmail(body.email, confirmationToken);
if (process.env.ENABLE_EMAIL === 'true') {
await sendConfirmAccountEmail(body.email, confirmationToken);
}

return res.json(
buildSuccessResponse({
Expand All @@ -64,7 +66,9 @@ router.post(
);
} catch (error) {
// Fail if could not create user (ex: duplicate record)
return res.json(buildErrorResponse({ msg: ErrorDefinition(error) }));
return res
.status(400)
.json(buildErrorResponse({ msg: ErrorDefinition(error) }));
}
},
);
Expand Down
12 changes: 9 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ========================================================
import * as dotenv from 'dotenv';
import express from 'express';
import cors from 'express';
import cors from 'cors';
import helmet from 'helmet';
import csrf from 'csurf';
import cookieParser from 'cookie-parser';
Expand All @@ -22,19 +22,25 @@ const app = express();

// Middlewares
// ========================================================
app.use(cors());
app.use(
cors({
origin: `${process.env.CORS_ALLOW || 'http://localhost:5000'}`.split(';'),
}),
);

app.use(helmet());
app.use(cookieParser());
app.use(express.json());
app.use(
csrf({
cookie: {
key: process.env.CSRF_COOKIE_PREFIX || '',
key: process.env.CSRF_COOKIE_PREFIX || '_csrf',
maxAge: parseInt(process.env.CSRF_COOKIE_MAXAGE || '900'),
signed: NODE_ENV === 'production' ? true : false, // signature
secure: NODE_ENV === 'production' ? true : false, // https
httpOnly: true,
sameSite: NODE_ENV === 'production' ? true : false, // sets the same site policy for the cookie
domain: process.env.COOKIE_ALLOW || 'http://localhost:5000',
},
}),
);
Expand Down
38 changes: 22 additions & 16 deletions src/utils/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// ========================================================
import faker from 'faker';
import jwtDecode from 'jwt-decode';
import { User } from '@prisma/client';
import axios, { AxiosRequestConfig } from 'axios';
import axios from 'axios';
import formData from 'form-data';
import bcrypt from 'bcrypt';
import { User } from '@prisma/client';
import {
hashPassword,
getGeneratedToken,
Expand All @@ -25,11 +26,11 @@ import {

// Mocks
// ========================================================
const axiosPost = jest.fn();
jest.mock('axios');
(axios as jest.Mocked<typeof axios>).post.mockImplementation(
jest.fn().mockImplementation(axiosPost),
);
jest.mock('axios', () => {
return Object.assign(jest.fn(), {
post: jest.fn().mockReturnValue({ success: true }),
});
});

const formDataAppend = jest.fn();
const formDataGetHeaders = jest.fn();
Expand Down Expand Up @@ -361,14 +362,16 @@ test('test - sendEmail - hello@email.com, some@email.com, my subject, hello ther
const subject = 'my subject';
const body = 'hello there!';
const basicAuth = Buffer.from(`api:secret`).toString('base64');
const spyOnAxiosPost = jest.spyOn(axios, 'post');

process.env.ENABLE_EMAIL = 'true';
process.env.MAILGUN_API_URL = 'url';
process.env.MAILGUN_DOMAIN = 'domain';
process.env.MAILGUN_SECRET_KEY = 'secret';

// Pre Expectations
expect(formData).not.toHaveBeenCalled();
expect(axiosPost).not.toHaveBeenCalled();
expect(spyOnAxiosPost).not.toBeCalled();

// Init
const result = await sendEmail(from, to, subject, body);
Expand All @@ -388,7 +391,7 @@ test('test - sendEmail - hello@email.com, some@email.com, my subject, hello ther
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);

// Axios
expect(axiosPost).toHaveBeenCalledTimes(1);
expect(spyOnAxiosPost).toBeCalledTimes(1);
expect(axios.post).toHaveBeenCalledWith(
'url/domain/messages',
{ append: formDataAppend, getHeaders: formDataGetHeaders },
Expand All @@ -399,7 +402,7 @@ test('test - sendEmail - hello@email.com, some@email.com, my subject, hello ther
},
},
);
expect(result).toBe(undefined);
expect(result).toStrictEqual({ success: true });
});

/**
Expand All @@ -413,14 +416,16 @@ test('test - sendResetPasswordEmail - hello@email.com, some@email.com, my subjec
const body =
'<p>Here is the link to <a href="/asdf1234">reset your password</a>.</p><p><a href="/asdf1234">/asdf1234</a></p>.';
const basicAuth = Buffer.from(`api:secret`).toString('base64');
const spyOnAxiosPost = jest.spyOn(axios, 'post');

process.env.ENABLE_EMAIL = 'true';
process.env.MAILGUN_DOMAIN = 'domain';
process.env.MAILGUN_SECRET_KEY = 'secret';
process.env.EMAIL_SUBJECT_RESET = subject;

// Pre Expectations
expect(formData).not.toHaveBeenCalled();
expect(axiosPost).not.toHaveBeenCalled();
expect(spyOnAxiosPost).not.toBeCalled();

// Init
const result = await sendResetPasswordEmail(to, 'asdf1234');
Expand All @@ -440,7 +445,7 @@ test('test - sendResetPasswordEmail - hello@email.com, some@email.com, my subjec
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);

// Axios
expect(axiosPost).toHaveBeenCalledTimes(1);
expect(spyOnAxiosPost).toBeCalledTimes(1);
expect(axios.post).toHaveBeenCalledWith(
'url/domain/messages',
{ append: formDataAppend, getHeaders: formDataGetHeaders },
Expand All @@ -451,7 +456,7 @@ test('test - sendResetPasswordEmail - hello@email.com, some@email.com, my subjec
},
},
);
expect(result).toBe(undefined);
expect(result).toStrictEqual({ success: true });
});

/**
Expand All @@ -465,14 +470,15 @@ test('test - sendConfirmAccountEmail - hello@email.com, some@email.com, my subje
const body =
'<p>Here is the link to <a href="/asdf1234">confirm your account</a>.</p><p><a href="/asdf1234">/asdf1234</a></p>.';
const basicAuth = Buffer.from(`api:secret`).toString('base64');
const spyOnAxiosPost = jest.spyOn(axios, 'post');

process.env.MAILGUN_DOMAIN = 'domain';
process.env.MAILGUN_SECRET_KEY = 'secret';
process.env.EMAIL_SUBJECT_CONFIRM = subject;

// Pre Expectations
expect(formData).not.toHaveBeenCalled();
expect(axiosPost).not.toHaveBeenCalled();
expect(spyOnAxiosPost).not.toBeCalled();

// Init
const result = await sendConfirmAccountEmail(to, 'asdf1234');
Expand All @@ -492,7 +498,7 @@ test('test - sendConfirmAccountEmail - hello@email.com, some@email.com, my subje
expect(formDataGetHeaders).toHaveBeenCalledTimes(1);

// Axios
expect(axiosPost).toHaveBeenCalledTimes(1);
expect(spyOnAxiosPost).toBeCalledTimes(1);
expect(axios.post).toHaveBeenCalledWith(
'url/domain/messages',
{ append: formDataAppend, getHeaders: formDataGetHeaders },
Expand All @@ -503,5 +509,5 @@ test('test - sendConfirmAccountEmail - hello@email.com, some@email.com, my subje
},
},
);
expect(result).toBe(undefined);
expect(result).toStrictEqual({ success: true });
});

0 comments on commit d18b635

Please sign in to comment.