Skip to content
Open
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
243 changes: 243 additions & 0 deletions agency/server/controllers/__tests__/blogController.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
const {
getBlogs,
getBlogById,
createBlog,
updateBlog,
deleteBlog,
} = require('../blogController');

const Blog = require('../../models/Blog');

jest.mock('../../models/Blog');

describe('Blog Controller Tests', () => {
let req, res;

beforeEach(() => {
req = {
body: {},
params: {},
user: {}
};

res = {
json: jest.fn(),
status: jest.fn().mockReturnThis(),
};

jest.clearAllMocks();
});

describe('getBlogs', () => {
it('should retrieve published blogs for a regular user', async () => {
const blogs = [{ title: 'Published Blog', status: 'published' }];
const mockSort = jest.fn().mockResolvedValue(blogs);
Blog.find.mockReturnValue({ sort: mockSort });

await getBlogs(req, res);

expect(Blog.find).toHaveBeenCalledWith({ status: 'published' });
expect(mockSort).toHaveBeenCalledWith({ createdAt: -1 });
expect(res.json).toHaveBeenCalledWith(blogs);
});

it('should retrieve all blogs for an admin', async () => {
req.user = { isAdmin: true };
const blogs = [{ title: 'Published Blog' }, { title: 'Draft Blog' }];
const mockSort = jest.fn().mockResolvedValue(blogs);
Blog.find.mockReturnValue({ sort: mockSort });

await getBlogs(req, res);

expect(Blog.find).toHaveBeenCalledWith({});
expect(mockSort).toHaveBeenCalledWith({ createdAt: -1 });
expect(res.json).toHaveBeenCalledWith(blogs);
});

it('should handle 500 error', async () => {
const error = new Error('Database error');
Blog.find.mockImplementation(() => { throw error; });

await getBlogs(req, res);

expect(res.status).toHaveBeenCalledWith(500);
expect(res.json).toHaveBeenCalledWith({ message: error.message });
});
});

describe('getBlogById', () => {
it('should find blog by slug', async () => {
req.params.id = 'my-slug';
const blog = { title: 'Slug Blog', slug: 'my-slug', status: 'published' };
Blog.findOne.mockResolvedValue(blog);

await getBlogById(req, res);

expect(Blog.findOne).toHaveBeenCalledWith({ slug: 'my-slug' });
expect(res.json).toHaveBeenCalledWith(blog);
});

it('should find blog by ID if slug not found and ID matches regex', async () => {
req.params.id = '507f1f77bcf86cd799439011';
const blog = { title: 'ID Blog', _id: '507f1f77bcf86cd799439011', status: 'published' };
Blog.findOne.mockResolvedValue(null);
Blog.findById.mockResolvedValue(blog);

await getBlogById(req, res);

expect(Blog.findOne).toHaveBeenCalledWith({ slug: req.params.id });
expect(Blog.findById).toHaveBeenCalledWith(req.params.id);
expect(res.json).toHaveBeenCalledWith(blog);
});

it('should return 404 when blog not found', async () => {
req.params.id = 'non-existent-slug';
Blog.findOne.mockResolvedValue(null);

await getBlogById(req, res);

expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Blog post not found' });
});

it('should handle 500 error', async () => {
req.params.id = 'some-id';
const error = new Error('Find error');
Blog.findOne.mockRejectedValue(error);

await getBlogById(req, res);

expect(res.status).toHaveBeenCalledWith(500);
expect(res.json).toHaveBeenCalledWith({ message: error.message });
});
});

describe('createBlog', () => {
it('should create a blog successfully', async () => {
req.body = {
title: 'New Blog',
author: 'John Doe',
category: 'Tech',
status: 'published'
};

const createdBlog = { ...req.body, _id: 'some-id' };

// Mock the constructor and save
Blog.mockImplementation(() => ({
save: jest.fn().mockResolvedValue(createdBlog)
}));

await createBlog(req, res);

expect(Blog).toHaveBeenCalledWith({
title: 'New Blog',
author: 'John Doe',
category: 'Tech',
image: undefined,
excerpt: undefined,
content: undefined,
readTime: undefined,
tags: undefined,
slug: undefined,
status: 'published'
});
expect(res.status).toHaveBeenCalledWith(201);
expect(res.json).toHaveBeenCalledWith(createdBlog);
});

it('should handle 400 error on save', async () => {
const error = new Error('Validation failed');
Blog.mockImplementation(() => ({
save: jest.fn().mockRejectedValue(error)
}));

await createBlog(req, res);

expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith({ message: error.message });
});
});

describe('updateBlog', () => {
it('should update a blog successfully', async () => {
req.params.id = 'some-id';
req.body = { title: 'Updated Title' };

const mockBlog = {
title: 'Old Title',
save: jest.fn().mockImplementation(function() {
return Promise.resolve(this);
})
};

Blog.findById.mockResolvedValue(mockBlog);

await updateBlog(req, res);

expect(Blog.findById).toHaveBeenCalledWith('some-id');
expect(mockBlog.title).toBe('Updated Title');
expect(mockBlog.save).toHaveBeenCalled();
expect(res.json).toHaveBeenCalledWith(mockBlog);
});

it('should return 404 when blog not found', async () => {
req.params.id = 'non-existent-id';
Blog.findById.mockResolvedValue(null);

await updateBlog(req, res);

expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Blog post not found' });
});

it('should handle 400 error', async () => {
req.params.id = 'some-id';
const error = new Error('Update error');
Blog.findById.mockRejectedValue(error);

await updateBlog(req, res);

expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith({ message: error.message });
});
});

describe('deleteBlog', () => {
it('should delete a blog successfully', async () => {
req.params.id = 'some-id';
const mockBlog = {
deleteOne: jest.fn().mockResolvedValue({})
};

Blog.findById.mockResolvedValue(mockBlog);

await deleteBlog(req, res);

expect(Blog.findById).toHaveBeenCalledWith('some-id');
expect(mockBlog.deleteOne).toHaveBeenCalled();
expect(res.json).toHaveBeenCalledWith({ message: 'Blog post removed' });
});

it('should return 404 when blog not found', async () => {
req.params.id = 'non-existent-id';
Blog.findById.mockResolvedValue(null);

await deleteBlog(req, res);

expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Blog post not found' });
});

it('should handle 500 error', async () => {
req.params.id = 'some-id';
const error = new Error('Delete error');
Blog.findById.mockRejectedValue(error);

await deleteBlog(req, res);

expect(res.status).toHaveBeenCalledWith(500);
expect(res.json).toHaveBeenCalledWith({ message: error.message });
});
});
});
9 changes: 7 additions & 2 deletions agency/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
"dev": "nodemon index.js",
"test": "jest"
},
"dependencies": {
"bcryptjs": "^3.0.3",
Expand All @@ -23,6 +24,10 @@
"nodemailer": "^8.0.2"
},
"devDependencies": {
"nodemon": "^3.1.0"
"jest": "^30.4.0",
"mongodb-memory-server": "^11.1.0",
"mpath": "^0.9.0",
"nodemon": "^3.1.0",
"supertest": "^7.2.2"
Comment thread
Adityavanjre marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useState, useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import {
Cpu,
Plus,
Expand Down
1 change: 1 addition & 0 deletions nexus/frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ api.interceptors.response.use(
const contentType = response.headers["content-type"];
if (
contentType &&
typeof contentType === "string" &&
contentType.includes("text/html") &&
typeof response.data === "string"
) {
Expand Down
Loading