Skip to content
Merged
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
1 change: 1 addition & 0 deletions Deploy/Containerization/backend_dockerfile/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
JWT_SECRET=testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestte==
11 changes: 11 additions & 0 deletions Deploy/Containerization/backend_dockerfile/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install
COPY . .

EXPOSE 8000

CMD ["npm", "start"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import request from 'supertest';
import { httpServer } from '../src/index.js';
import {dbReset} from "../src/data/dataServices.js";

describe('Authentication API', () => {

afterAll((done) => {
httpServer.close(done);
});

describe('POST /api/auth/register', () => {
beforeEach(async() => {
await dbReset();

});

it('should register a new user successfully', async () => {
const response = await request(httpServer)
.post('/api/auth/register')
.send({
username: 'testuser',
password: 'password123'
})
.timeout(4000);

expect(response.status).toBe(201);
expect(response.body).toHaveProperty('username', 'testuser');
});

it('should not allow duplicate usernames', async () => {
// Register first user
await request(httpServer)
.post('/api/auth/register')
.send({
username: 'testuser',
password: 'password123'
})
.timeout(4000);

// Try to register the same username
const response = await request(httpServer)
.post('/api/auth/register')
.send({
username: 'testuser',
password: 'differentpassword'
})
.timeout(4000);

expect(response.status).toBe(409);
expect(response.body).toHaveProperty('message', 'Username already exists');
});
});

describe('POST /api/auth/login', () => {
beforeAll(async () => {
await dbReset();
// Create a test user before login test
await request(httpServer)
.post('/api/auth/register')
.send({
username: 'testuser',
password: 'password123'
})
.timeout(4000);
});

it('should log in successfully with correct credentials', async () => {
const response = await request(httpServer)
.post('/api/auth/login')
.send({
username: 'testuser',
password: 'password123'
})
.timeout(4000);

expect(response.status).toBe(200);
expect(response.body).toHaveProperty('username', 'testuser');
expect(response.body).toHaveProperty('token');
});

it('should fail with incorrect password', async () => {
const response = await request(httpServer)
.post('/api/auth/login')
.send({
username: 'testuser',
password: 'wrongpassword'
})
.timeout(4000);

expect(response.status).toBe(401);
expect(response.body).toHaveProperty('message', 'Invalid username or password');
});

it('should fail with non-existent username', async () => {
const response = await request(httpServer)
.post('/api/auth/login')
.send({
username: 'nonexistent',
password: 'password123'
})
.timeout(4000);

expect(response.status).toBe(401);
expect(response.body).toHaveProperty('message', 'Invalid username or password');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {dbReset, userService, messageService} from '../src/data/dataServices.js';

describe('Test database-backed data layer', () => {
beforeEach(async () => {
await dbReset();
});

describe('Test userService', () => {
it('Test new user creation', async () => {
const newUser = await userService.createUser('Tom', 'password123');
expect(newUser.username).toBe('Tom');
});

it('Test existing user creation', async () => {
await userService.createUser('John', '1234567890');

await expect(userService.createUser('John', 'newPassword'))
.rejects
.toThrow('Username already exists');
});

it('Test get existing user', async () => {
const existingUser = await userService.createUser('Alice', 'mypassword');
const fetchedUser = await userService.getUser('Alice');
expect(fetchedUser.username).toEqual(existingUser.username);
});

it('Test get non-existing user', async () => {
const nonExistentUser = await userService.getUser('NonExistentUser');
expect(nonExistentUser).toBeUndefined();
});
});

describe('Test messageService', () => {
it('Test add new message', async () => {
const message = await messageService.addMessage('Alice', 'Test message');
expect(message.username).toBe('Alice');
expect(message.content).toBe('Test message');
expect(message.id).toBeDefined();
});

it('Test get messages', async () => {
await messageService.addMessage('Tom', 'Message 1');
await messageService.addMessage('John', 'Message 2');

const messages = await messageService.getMessages();
expect(messages.length).toBe(2);
expect(messages[0].content).toBe('Message 1');
expect(messages[1].content).toBe('Message 2');
});

xit('Test delete the only message', async () => {
const newMessage = await messageService.addMessage('Alice', 'Single message');
const result = await messageService.deleteMessage(newMessage.id);
expect(result).toBe(true);

const messages = await messageService.getMessages();
expect(messages.length).toBe(0);
});

xit('Test delete message with others', async () => {
await messageService.addMessage('Alice', 'Message A');
const messageToDelete = await messageService.addMessage('Alice', 'Message B');
await messageService.addMessage('Alice', 'Message C');

const result = await messageService.deleteMessage(messageToDelete.id);
expect(result).toBe(true);

const messages = await messageService.getMessages();
expect(messages.length).toBe(2);
expect(messages[0].content).toBe('Message A');
expect(messages[1].content).toBe('Message C');
});

xit('Test delete non-existing message', async () => {
const result = await messageService.deleteMessage(999999);
expect(result).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import request from 'supertest';
import {httpServer} from '../src/index.js';
import {dbReset} from '../src/data/dataServices.js';

describe('Messages API', () => {
let authToken;
const testUser = {
username: 'User',
password: '1234'
};
beforeAll(() => {
});

afterAll((done) => {
httpServer.close(done);
});

beforeEach(async () => {
// Clear data
await dbReset();

// Register and login test user
const registerResponse = await request(httpServer)
.post('/api/auth/register')
.send(testUser);

authToken = registerResponse.body.token;
});

describe('Messages API - Unauthorized Access', () => {

it('should return 401 for POST /api/messages without a token', async () => {
const response = await request(httpServer)
.post('/api/messages')
.send({ content: 'Unauthorized message' });

expect(response.status).toBe(401);
expect(response.body).toHaveProperty('message');
});

it('should return 401 for GET /api/messages without a token', async () => {
const response = await request(httpServer)
.get('/api/messages');

expect(response.status).toBe(401);
expect(response.body).toHaveProperty('message');
});

it('should return 401 for DELETE /api/messages/:id without a token', async () => {
const response = await request(httpServer)
.delete('/api/messages/1');

expect(response.status).toBe(401);
expect(response.body).toHaveProperty('message');
});
});


describe('POST /api/messages', () => {
it('should create a new message with correct structure', async () => {
const response = await request(httpServer)
.post('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.send({ content: 'Hello, World!' })
.timeout(4000);

expect(response.status).toBe(201);
expect(response.body).toMatchObject({
content: 'Hello, World!',
username: 'User',
id: expect.any(Number),
});
});

it('should fail without content', async () => {
const response = await request(httpServer)
.post('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.send()
.timeout(4000);

expect(response.status).toBe(400);
expect(response.body).toHaveProperty('message', 'Message content is required');
});
});

describe('GET /api/messages', () => {
it('should get empty message list initially', async () => {
const response = await request(httpServer)
.get('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.timeout(4000);

expect(response.status).toBe(200);
expect(response.body).toEqual([]);
});

it('should get messages', async () => {
// Add test messages
for (let i = 0; i < 3; i++) {
await request(httpServer)
.post('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.send({ content: `Test message ${i}` })
.timeout(4000);
}

const response = await request(httpServer)
.get('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.timeout(4000);

expect(response.status).toBe(200);
expect(response.body).toHaveLength(3);
expect(response.body[2].content).toBe('Test message 2');
});
});

describe('DELETE /api/messages/:id', () => {
xit('should delete an existing message', async () => {
// Create a message
const createResponse = await request(httpServer)
.post('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.send({ content: 'Test message' })
.timeout(4000);

const messageId = createResponse.body.id;

// Delete the message
const deleteResponse = await request(httpServer)
.delete(`/api/messages/${messageId}`)
.set('Authorization', `Bearer ${authToken}`)
.timeout(4000);

expect(deleteResponse.status).toBe(204);

// Verify the message is deleted
const getResponse = await request(httpServer)
.get('/api/messages')
.set('Authorization', `Bearer ${authToken}`)
.timeout(4000);

expect(getResponse.body).toHaveLength(0);
});

xit('should return 404 for non-existent message', async () => {
const response = await request(httpServer)
.delete('/api/messages/999999')
.set('Authorization', `Bearer ${authToken}`)
.timeout(4000);

expect(response.status).toBe(404);
});

});
});
Loading