Skip to content

Commit

Permalink
Merge pull request #395 from SquirrelCorporation/test-add-integration…
Browse files Browse the repository at this point in the history
…-tests

[TEST] Add integration tests and mock strategy for Passport
  • Loading branch information
SquirrelDeveloper authored Oct 18, 2024
2 parents c21d16e + 6a8c2b2 commit 8df33a1
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 28 deletions.
64 changes: 64 additions & 0 deletions server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"start": "npm run build-shared && npm run build && cross-env NODE_ENV=production node dist/index.js",
"build": "tsc",
"test": "vitest --disable-console-intercept --reporter=basic ",
"test:python:install": "pip install -r ./src/ansible/requirements.txt --break-system-packages",
"test:python:install": "PIP_BREAK_SYSTEM_PACKAGES=1 pip install -r ./src/ansible/requirements.txt",
"test:python": "npm run test:python:install && npm run test:python:run",
"test:python:run": "cd ./src/ansible && python3 -m unittest discover -s . -p \"*.py\"",
"coverage": "vitest run --coverage"
Expand Down Expand Up @@ -102,6 +102,7 @@
"typescript": "^5.6.3",
"vitest": "^2.1.3",
"@types/js-yaml": "^4.0.9",
"@types/express": "^5.0.0"
"@types/express": "^5.0.0",
"passport-mock-strategy": "^2.0.0"
}
}
6 changes: 3 additions & 3 deletions server/src/middlewares/Passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Request } from 'express';
import passport from 'passport';
import passportJWT from 'passport-jwt';
import passportBearer from 'passport-http-bearer';
import MockStrategy from 'passport-mock-strategy';
import { SECRET } from '../config';
import UserRepo from '../data/database/repository/UserRepo';

const JWTStrategy = passportJWT.Strategy;
const BearerStrategy = passportBearer.Strategy;
const JWTStrategy = process.env.NODE_ENV === 'test' ? MockStrategy : passportJWT.Strategy;
const BearerStrategy = process.env.NODE_ENV === 'test' ? MockStrategy : passportBearer.Strategy;

export const cookieExtractor = (req: Request) => {
let jwt = null;
Expand All @@ -25,7 +26,6 @@ passport.use(
},
(jwtPayload, done) => {
const { expiration } = jwtPayload;

if (Date.now() > expiration) {
done('Unauthorized', false);
}
Expand Down
120 changes: 120 additions & 0 deletions server/src/tests/integration-tests/test/controllers/rest/login.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import bcrypt from 'bcrypt';
import mongoose from 'mongoose';
import request from 'supertest';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { SALT_ROUNDS, UsersModel } from '../../../../../data/database/model/User';
import UserRepo from '../../../../../data/database/repository/UserRepo';
import app from '../../server';

describe('Auth Integration Tests', () => {
vi.mock('../../../data/database/repository/UserRepo', () => ({
findByEmailAndPassword: vi.fn(),
}));

beforeAll(async () => {
await mongoose.connect(process.env['MONGO_URI'] as string);
});

afterAll(async () => {
await mongoose.disconnect();
});

afterEach(async () => {
await mongoose.connection.db?.dropDatabase();
vi.clearAllMocks();
});

beforeEach(async () => {
const user = new UsersModel({
email: 'test@example.com',
password: 'password',
role: 'admin',
avatar: 'test',
name: 'test',
});
await user.save();
});

describe('POST /login', () => {
it('should return 200 and set jwt cookie on successful login', async () => {
const response = await request(app)
.post('/users/login')
.send({ username: 'test@example.com', password: 'password' });

// Assertions
expect(response.status).toBe(200);
expect(response.body).toEqual(
expect.objectContaining({
message: 'Login success',
data: {
currentAuthority: 'admin',
},
}),
);
expect(response.headers['set-cookie']).toBeDefined();
});

it('should return 401 for invalid credentials', async () => {
const response = await request(app)
.post('/users/login')
.send({ username: 'invalid@example.com', password: 'wrongpassword' });

// Assertions
expect(response.status).toBe(401);
expect(response.body).toEqual(
expect.objectContaining({
message: 'Identification is incorrect!',
success: false,
}),
);
});

it('should return 400 when email is incorrect', async () => {
const response = await request(app)
.post('/users/login')
.send({ username: 'invalid_example.com', password: 'password' });

// Assertions
expect(response.status).toBe(400);
});

it('should return 400 when email is missing', async () => {
const response = await request(app).post('/users/login').send({ password: 'password' });

// Assertions
expect(response.status).toBe(400);
});

it('should return 400 when password is missing', async () => {
const response = await request(app)
.post('/users/login')
.send({ username: 'test@example.com' });

// Assertions
expect(response.status).toBe(400);
});
});

describe('POST /logout', () => {
it('should clear jwt cookie on successful logout', async () => {
const response = await request(app).post('/users/logout').set('Cookie', 'jwt=fake-jwt-token');

// Assertions
expect(response.status).toBe(200);
expect(response.body).toEqual(
expect.objectContaining({
message: 'Logout success',
}),
);
expect(response.headers['set-cookie']).toContainEqual(expect.stringContaining('jwt=;'));
});

it('should return 401 if no jwt token is found', async () => {
const response = await request(app).post('/users/logout');

// Assertions
expect(response.status).toBe(401);
expect(response.body).toEqual({ error: 'Invalid jwt' });
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import request from 'supertest';
import mongoose from 'mongoose';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import app from '../../server';
import UserRepo from '../../../../../data/database/repository/UserRepo';

describe('User Controllers Integration Tests', () => {
beforeAll(async () => {
await mongoose.connect(process.env['MONGO_URI'] as string);
});

afterAll(async () => {
await mongoose.disconnect();
});

beforeEach(() => {
vi.spyOn(UserRepo, 'findByEmail').mockResolvedValue({
email: 'test@example.com',
name: 'test',
avatar: 'test',
password: 'test',
role: 'test',
});
});

afterEach(async () => {
vi.restoreAllMocks(); // Reset mocks after each test
});

describe('resetUserApiKey', () => {
it('should reset the user API key', async () => {
const mockUuid = 'new-unique-uuid';
const resetApiKeySpy = vi.spyOn(UserRepo, 'resetApiKey').mockResolvedValue(mockUuid);

const response = await request(app)
.post('/users/settings/resetApiKey')
.set('content-type', 'application/json');

expect(response.status).toBe(200);
expect(response.body).toEqual({
success: true,
message: 'Reset Api Key',
data: {
uuid: mockUuid,
},
});

expect(resetApiKeySpy).toHaveBeenCalledWith('test@example.com');
});
});

describe('setUserLoglevel', () => {
it('should set the user log level', async () => {
const userLogsLevel = { terminal: 5 };
const updateLogsLevelSpy = vi.spyOn(UserRepo, 'updateLogsLevel').mockResolvedValue();

const response = await request(app)
.post('/users/settings/logs')
.send(userLogsLevel)
.set('content-type', 'application/json');

expect(response.status).toBe(200);
expect(response.body).toEqual({
message: 'Set user log level',
success: true,
});

expect(updateLogsLevelSpy).toHaveBeenCalledWith('test@example.com', userLogsLevel);
});
});
});
Loading

0 comments on commit 8df33a1

Please sign in to comment.