Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
asdf
  • Loading branch information
if22b088 committed Aug 27, 2024
2 parents fb2aaf3 + aa7c5af commit 206652c
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 56 deletions.
82 changes: 57 additions & 25 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,37 @@ on:
- main

jobs:
build:
name: Build and Test Backend
# Lint Job
lint:
name: Lint Backend
runs-on: ubuntu-latest

steps:
# Step 1: Checkout the code
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full-depth clone for SonarQube analysis

# Step 2: Run Snyk Security Scan
- name: Snyk Security Scan
uses: snyk/actions/node@master
with:
command: test --all-projects
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# Step 3: SonarQube Scan
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

# Test Job
test:
name: Test Backend
needs: lint
runs-on: ubuntu-latest

steps:
Expand All @@ -31,11 +60,7 @@ jobs:
- name: Install Dependencies
run: npm ci

# Step 4: Build the source code (if applicable)
- name: Build Source Code
run: npm run build --if-present

# Step 5: Run tests
# Step 4: Run tests
- name: Run Tests
env:
DB_HOST: ${{ secrets.DB_HOST }}
Expand All @@ -45,36 +70,36 @@ jobs:
DB_NAME: ${{ secrets.DB_NAME }}
run: npm test --if-present

lint:
name: Lint Backend
needs: build
# Build Job
build:
name: Build Backend
needs: test
runs-on: ubuntu-latest

steps:
# Step 1: Checkout the code
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full-depth clone for SonarQube analysis

# Step 2: Run Snyk Security Scan using Snyk's cloud service
- name: Snyk Security Scan
uses: snyk/actions/node@master
# Step 2: Set up Node.js environment (latest version)
- name: Set up Node.js
uses: actions/setup-node@v4
with:
command: test --all-projects
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
node-version: "22.x"
cache: npm

# Step 3: SonarQube Scan
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
# Step 3: Install dependencies
- name: Install Dependencies
run: npm ci

# Step 4: Build the source code
- name: Build Source Code
run: npm run build --if-present

# Deliver Job
deliver:
name: Deliver Backend
needs: lint
needs: build
runs-on: ubuntu-latest

steps:
Expand All @@ -94,11 +119,18 @@ jobs:
- name: Push Docker Image
run: docker push gregory789/contint-backend-repository:contint-backend-image

# Deploy Job
deploy:
name: Deploy Backend
needs: deliver
runs-on: ubuntu-22.04

steps:
# Step 1: Checkout the code
- name: Checkout Code
uses: actions/checkout@v4

# Step 2: Execute remote SSH commands using SSH key
- name: Executing remote SSH commands using SSH key
uses: appleboy/[email protected]
with:
Expand Down
166 changes: 135 additions & 31 deletions test/todos.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jest.mock('../db/db', () => {
create: jest.fn(),
findAll: jest.fn(),
findByPk: jest.fn(),
update: jest.fn(),
}
}
};
Expand All @@ -29,6 +30,13 @@ beforeAll(async () => {
db.models.todo.findByPk.mockImplementation(id => {
return Promise.resolve(mockTodos.find(todo => todo.id === id));
});
db.models.todo.update.mockImplementation((values, options) => {
const todo = mockTodos.find(todo => todo.id === options.where.id);
if (todo) {
return Promise.resolve([1, [{ ...todo, ...values }]]);
}
return Promise.resolve([0, []]);
});
});

afterAll(async () => {
Expand All @@ -37,12 +45,37 @@ afterAll(async () => {

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

///////////////////////////////////////////////////////////////////
//////////// GET Tests /////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

test('GET /todos should return all todos', async () => {
const res = await request(app).get('/todos');
expect(res.statusCode).toEqual(200);
expect(res.body.length).toBe(2); // Should have 2 initial tasks
});

test('GET /todos should return an empty array if no todos exist', async () => {
db.models.todo.findAll.mockResolvedValueOnce([]);
const res = await request(app).get('/todos');
expect(res.statusCode).toEqual(200);
expect(res.body.length).toBe(0);
});

test('GET /todos should return todos with the correct properties', async () => {
const res = await request(app).get('/todos');
expect(res.statusCode).toEqual(200);
res.body.forEach(todo => {
expect(todo).toHaveProperty('id');
expect(todo).toHaveProperty('name');
expect(todo).toHaveProperty('done');
});
});

///////////////////////////////////////////////////////////////////
//////////// POST Tests ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

test('POST /todos should create a new todo', async () => {
const newTodo = { id: 3, name: 'New Task', done: false };
db.models.todo.create.mockResolvedValue(newTodo);
Expand All @@ -62,62 +95,88 @@ describe('Todos API', () => {
expect(res.body.errors[0].msg).toBe('Invalid value');
});

test('POST /todos should trim whitespace from name', async () => {
const newTodo = { id: 3, name: 'Trimmed Task', done: false };
db.models.todo.create.mockResolvedValue(newTodo);
const res = await request(app)
.post('/todos')
.send({ name: ' Trimmed Task ' });
expect(res.statusCode).toEqual(201);
expect(res.body.name).toBe('Trimmed Task');
});

test('POST /todos should allow a todo with "done" status set to true initially', async () => {
const newTodo = { id: 4, name: 'New Task', done: true };
db.models.todo.create.mockResolvedValue(newTodo);
const res = await request(app)
.post('/todos')
.send({ name: 'New Task', done: true });
expect(res.statusCode).toEqual(201);
expect(res.body.done).toBe(true);
});

////////////////////////////////////////////////////////////////////////
//////////// bad TODO naming ///////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

test('POST /todos should return 400 for a name exceeding max length', async () => {
const longName = 'A'.repeat(256); // 256 characters long
const res = await request(app).post('/todos').send({ name: longName });
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toBe('Invalid value');
});

test('POST /todos should return 400 if name is missing', async () => {
const res = await request(app).post('/todos').send({});
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toBe('Invalid value');
});

////////////////////////////////////////////////////////////////////////
//////////// PUT Tests /////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

/*
test('PUT /todos/:id/done should mark a todo as done', async () => {
const todo = { id: 1, name: 'Initial Task 1', done: false };
db.models.todo.findByPk.mockResolvedValueOnce(todo);
todo.done = true;
const res = await request(app)
.put('/todos/1/done');
const res = await request(app).put('/todos/1/done');
expect(res.statusCode).toEqual(200);
expect(res.body.done).toBe(true);
});
*/

test('PUT /todos/:id/done should return 404 for a non-existent todo', async () => {
test('PUT /todos/:id/done should return 404 if todo is not found', async () => {
db.models.todo.findByPk.mockResolvedValueOnce(null);
const res = await request(app)
.put('/todos/999/done');
const res = await request(app).put('/todos/999/done');
expect(res.statusCode).toEqual(404);
expect(res.text).toBe('Todo not found');
});

////////////////////////////////////////////////////////////////////////
//////////// DELETE Tests //////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

/*
test('DELETE /todos/:id/done should mark a todo as not done', async () => {
const todo = { id: 1, name: 'Initial Task 1', done: true };
const todo = { id: 2, name: 'Initial Task 2', done: true };
db.models.todo.findByPk.mockResolvedValueOnce(todo);
todo.done = false;
const res = await request(app)
.delete('/todos/1/done');
const res = await request(app).delete('/todos/2/done');
expect(res.statusCode).toEqual(200);
expect(res.body.done).toBe(false);
});
*/

test('PUT /todos/:id/done should return 404 for an invalid ID', async () => {
const res = await request(app).put('/todos/invalid/done');
expect(res.statusCode).toEqual(404);
expect(res.text).toBe('Todo not found');
});

test('DELETE /todos/:id/done should return 404 for an invalid ID', async () => {
const res = await request(app).delete('/todos/invalid/done');
test('DELETE /todos/:id/done should return 404 if todo is not found', async () => {
db.models.todo.findByPk.mockResolvedValueOnce(null);
const res = await request(app).delete('/todos/999/done');
expect(res.statusCode).toEqual(404);
expect(res.text).toBe('Todo not found');
});

test('POST /todos should return 400 for a name exceeding max length', async () => {
const longName = 'A'.repeat(256); // 256 characters long
const res = await request(app).post('/todos').send({ name: longName });
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toBe('Invalid value');
});

test('POST /todos should return 400 if name is missing', async () => {
const res = await request(app).post('/todos').send({});
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toBe('Invalid value');
});

////////////////////////////////////////////////////////////////////////
//////////// DB connection /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

test('Database connection should be established', async () => {
await expect(db.authenticate()).resolves.not.toThrow();
Expand All @@ -127,4 +186,49 @@ describe('Todos API', () => {
expect(db.models.todo).toBeDefined();
});

/////////////////////////////////////////////////////////////////////
//////////// CORS tests /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

test('should use CORS middleware with correct origin settings', async () => {
const res = await request(app)
.options('/todos')
.set('Origin', 'http://44.219.67.143')
.send();

expect(res.headers['access-control-allow-origin']).toBe('http://44.219.67.143');
expect(res.headers['access-control-allow-credentials']).toBe('true');
});

test('should not allow requests from unauthorized origins', async () => {
const res = await request(app)
.options('/todos')
.set('Origin', 'http://unauthorized-origin.com')
.send();

expect(res.headers['access-control-allow-origin']).toBeUndefined();
});

////////////////////////////////////////////////////////////////////////
//////////// undefined routes //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

test('should return 404 for undefined routes', async () => {
const res = await request(app).get('/undefined-route');
expect(res.statusCode).toEqual(404);
});

////////////////////////////////////////////////////////////////////////
//////////// cookie parser /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

test('should parse cookies correctly', async () => {
const res = await request(app)
.get('/todos')
.set('Cookie', 'test_cookie=test_value');

expect(res.statusCode).toEqual(200);
expect(res.headers['set-cookie']).toBeUndefined(); // Assuming no new cookies are set in this route
});

});

0 comments on commit 206652c

Please sign in to comment.