Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/evolution-backend/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
lib/
node_modules/
**/__tests__
node_modules/
12 changes: 11 additions & 1 deletion packages/evolution-backend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
{
"extends": "../../configs/base.eslintrc.json"
"extends": "../../configs/base.eslintrc.json",
"overrides": [
{
"files": ["**/__tests__/**/*.{ts,tsx}"],
"rules": {
"@typescript-eslint/no-unused-vars": ["warn", { "vars": "all", "args": "after-used", "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "ignoreRestSiblings": false }],
// Some imports for testing purposes are devDependencies and not published
"n/no-unpublished-import": "off"
}
}
]
}
13 changes: 12 additions & 1 deletion packages/evolution-backend/.prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,16 @@
* License text available at https://opensource.org/licenses/MIT
*/
module.exports = {
...require('../../configs/base.prettierrc')
...require('../../configs/base.prettierrc'),
// FIXME Move to the base config when we agree on it.
overrides: [
{
files: ['**/__tests__/*.{ts,tsx}', '**/*.{test,spec}.{ts,tsx}'],
options: {
// For test files, we allow longer lines and do not break objects (e.g. expected values) into multiple lines
printWidth: 150,
objectWrap: 'collapse'
}
}
]
}
69 changes: 17 additions & 52 deletions packages/evolution-backend/src/api/__tests__/auth.routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import express, { RequestHandler } from 'express';
import request from 'supertest';
import session from 'supertest-session';

Check failure on line 9 in packages/evolution-backend/src/api/__tests__/auth.routes.test.ts

View workflow job for this annotation

GitHub Actions / code-lint

"supertest-session" is extraneous
import passport from 'passport';

import authRoutes from '../auth.routes';
Expand All @@ -18,14 +18,7 @@
return jest.fn();
});

let authResponse: {
error: any,
user: any,
statusCode?: number
} = {
error: null,
user: false
}
let authResponse: { error: any; user: any; statusCode?: number } = { error: null, user: false };

const authMockImplementation = (req, res, next) => {
const response = authResponse;
Expand All @@ -38,9 +31,7 @@
next(response.error, response.user);
};

const authMockFunctions = {
'auth-by-field': jest.fn().mockImplementation(authMockImplementation)
}
const authMockFunctions = { 'auth-by-field': jest.fn().mockImplementation(authMockImplementation) };

jest.mock('passport', () => {
return {
Expand All @@ -51,7 +42,7 @@
mockImplementation(req, res, (error, user) => {
callback(error, user);
});
}
};
}
return mockImplementation;
}),
Expand All @@ -60,7 +51,7 @@
deserializeUser: jest.fn(),
initialize: jest.fn().mockReturnValue((req, res, next) => next()),
session: jest.fn().mockReturnValue((req, res, next) => next())
}
};
});

// Mock the captcha validation
Expand All @@ -72,22 +63,12 @@
});

const validFieldValue = 'test-value';
const validUser = {
id: 5,
uuid: 'arbitrary',
username: 'test',
email: 'test@test.org',
is_confirmed: true,
is_valid: true
};
const validUser = { id: 5, uuid: 'arbitrary', username: 'test', email: 'test@test.org', is_confirmed: true, is_valid: true };

beforeEach(() => {
authResponse = {
error: null,
user: false
}
Object.keys(authMockFunctions).forEach(authType => authMockFunctions[authType].mockClear());
})
authResponse = { error: null, user: false };
Object.keys(authMockFunctions).forEach((authType) => authMockFunctions[authType].mockClear());
});

describe('Auth by field route', () => {
// Setup the app with byField enabled
Expand All @@ -108,20 +89,17 @@
callback(null);
});
next();
})
});
authRoutes(router, userAuthModel, passport);
app.use(router);

beforeEach(() => {
failedAttempts = undefined;
jest.clearAllMocks();
})
});

test('Auth by field, valid credentials', async () => {
authResponse = {
error: null,
user: validUser
};
authResponse = { error: null, user: validUser };
const res = await session(app)
.post('/auth-by-field')
.send({ field: validFieldValue })
Expand All @@ -136,10 +114,7 @@

test('Auth by field, valid credentials after first attempt, valid catpcha', async () => {
failedAttempts = 1; // Simulate one failed attempt, should validate captcha
authResponse = {
error: null,
user: validUser
};
authResponse = { error: null, user: validUser };
const res = await session(app)
.post('/auth-by-field')
.send({ field: validFieldValue })
Expand All @@ -156,11 +131,8 @@
failedAttempts = 1; // Simulate one failed attempt, should validate captcha
mockedValidateCaptchaToken.mockImplementationOnce((req, res, next) => {
return res.status(403).json({ status: 'InvalidCaptcha' });
})
authResponse = {
error: null,
user: validUser
};
});
authResponse = { error: null, user: validUser };
const res = await session(app)
.post('/auth-by-field')
.send({ field: validFieldValue })
Expand All @@ -174,10 +146,7 @@
});

test('Auth by field, invalid credentials', async () => {
authResponse = {
error: 'InvalidData',
user: false
};
authResponse = { error: 'InvalidData', user: false };
const res = await session(app)
.post('/auth-by-field')
.send({ field: 'invalid-value' })
Expand All @@ -191,11 +160,7 @@
});

test('Auth by field, unauthorized access', async () => {
authResponse = {
error: 'Unauthorized',
user: false,
statusCode: 401
};
authResponse = { error: 'Unauthorized', user: false, statusCode: 401 };
const res = await session(app)
.post('/auth-by-field')
.send({ field: validFieldValue })
Expand Down Expand Up @@ -229,4 +194,4 @@
.expect('Content-Type', 'text/html; charset=utf-8')
.expect(404);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
jest.mock('../../services/interviews/interviews');
jest.mock('../../services/logging/queryLoggingMiddleware');
jest.mock('../../services/logging/supportRequest');
jest.mock('evolution-common/lib/config/project.config', () => ({
surveySupportForm: true
}));
jest.mock('evolution-common/lib/config/project.config', () => ({ surveySupportForm: true }));

const mockUserId = 3;
const mockAuthorizationMiddleware = jest.fn(() => (req, res, next) => next());
Expand Down Expand Up @@ -53,14 +51,7 @@
});

test('should return active interview for user', async () => {
const mockInterview = {
id: 1,
uuid: 'mockUuid',
is_valid: true,
is_completed: false,
response: {},
participant_id: 1
};
const mockInterview = { id: 1, uuid: 'mockUuid', is_valid: true, is_completed: false, response: {}, participant_id: 1 };
(Interviews.getUserInterview as jest.Mock).mockResolvedValue(mockInterview);

const response = await request(app).get('/survey/activeInterview');
Expand All @@ -71,14 +62,7 @@
});

test('should create interview if none exists', async () => {
const mockCreatedInterview = {
id: 1,
uuid: 'mockUuid',
is_valid: true,
is_completed: false,
response: {},
participant_id: 1
};
const mockCreatedInterview = { id: 1, uuid: 'mockUuid', is_valid: true, is_completed: false, response: {}, participant_id: 1 };
(Interviews.getUserInterview as jest.Mock).mockResolvedValue(undefined);
(Interviews.createInterviewForUser as jest.Mock).mockResolvedValue(mockCreatedInterview);

Expand Down Expand Up @@ -116,11 +100,7 @@
const response = await request(app).get('/survey/activeInterview');

expect(response.status).toBe(500);
expect(response.body).toEqual({
status: 'failed',
interview: null,
error: 'cannot fetch interview'
});
expect(response.body).toEqual({ status: 'failed', interview: null, error: 'cannot fetch interview' });
expect(Interviews.getUserInterview).toHaveBeenCalledWith(mockUserId);
});

Expand Down Expand Up @@ -155,11 +135,7 @@
});

test('should handle support request successfully when user is not logged in', async () => {
const requestData = {
email: 'test@example.com',
message: 'Help me please',
currentUrl: 'http://test.com/page'
};
const requestData = { email: 'test@example.com', message: 'Help me please', currentUrl: 'http://test.com/page' };

(sendSupportRequestEmail as jest.Mock).mockResolvedValue(undefined);

Expand Down Expand Up @@ -191,11 +167,7 @@
(Interviews.getUserInterview as jest.Mock).mockResolvedValue(mockInterview);
(sendSupportRequestEmail as jest.Mock).mockResolvedValue(undefined);

const requestData = {
email: 'test@example.com',
message: 'Help me please',
currentUrl: 'http://test.com/page'
};
const requestData = { email: 'test@example.com', message: 'Help me please', currentUrl: 'http://test.com/page' };

const response = await request(loggedInApp).post('/supportRequest/').send(requestData);

Expand All @@ -212,10 +184,7 @@
});

test('should handle missing message in request', async () => {
const requestData = {
email: 'test@example.com',
currentUrl: 'http://test.com/page'
};
const requestData = { email: 'test@example.com', currentUrl: 'http://test.com/page' };

(sendSupportRequestEmail as jest.Mock).mockResolvedValue(undefined);

Expand All @@ -235,10 +204,7 @@
test('should handle errors in support request processing', async () => {
(sendSupportRequestEmail as jest.Mock).mockRejectedValue(new Error('Email sending failed'));

const requestData = {
email: 'test@example.com',
message: 'Help me please'
};
const requestData = { email: 'test@example.com', message: 'Help me please' };

const response = await request(publicApp).post('/supportRequest/').send(requestData);

Expand All @@ -253,11 +219,7 @@
return res.status(403).json({ status: 'InvalidCaptcha' });
});

const requestData = {
email: 'test@example.com',
message: 'Help me please',
currentUrl: 'http://test.com/page'
};
const requestData = { email: 'test@example.com', message: 'Help me please', currentUrl: 'http://test.com/page' };

(sendSupportRequestEmail as jest.Mock).mockResolvedValue(undefined);

Expand All @@ -272,12 +234,10 @@
test('should not register route when supportForm is disabled', async () => {
// Override the project config mock to disable support form
jest.resetModules();
jest.mock('evolution-common/lib/config/project.config', () => ({
surveySupportForm: false
}));
jest.mock('evolution-common/lib/config/project.config', () => ({ surveySupportForm: false }));

// Re-import to get updated config, otherwise it still uses the previous config mock and the result is a 500 error
const { getPublicParticipantRoutes: getUpdatedRoutes } = require('../survey.participant.routes');

Check failure on line 240 in packages/evolution-backend/src/api/__tests__/survey.participant.routes.test.ts

View workflow job for this annotation

GitHub Actions / code-lint

A `require()` style import is forbidden

Check failure on line 240 in packages/evolution-backend/src/api/__tests__/survey.participant.routes.test.ts

View workflow job for this annotation

GitHub Actions / code-lint

Require statement not part of import statement

const disabledApp = express();
disabledApp.use(express.json());
Expand Down
Loading
Loading