chore: ingest source code
58 files from https://github.com/gothinkster/node-express-realworld-example-app
This commit is contained in:
17
src/tests/prisma-mock.ts
Normal file
17
src/tests/prisma-mock.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended';
|
||||
|
||||
import prisma from '../prisma/prisma-client';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
jest.mock('../prisma/prisma-client', () => ({
|
||||
__esModule: true,
|
||||
default: mockDeep<PrismaClient>(),
|
||||
}));
|
||||
|
||||
const prismaMock = prisma as unknown as DeepMockProxy<PrismaClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockReset(prismaMock);
|
||||
});
|
||||
|
||||
export default prismaMock;
|
||||
144
src/tests/services/article.service.test.ts
Normal file
144
src/tests/services/article.service.test.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import prismaMock from '../prisma-mock';
|
||||
import {
|
||||
deleteComment,
|
||||
favoriteArticle,
|
||||
unfavoriteArticle,
|
||||
} from '../../app/routes/article/article.service';
|
||||
|
||||
describe('ArticleService', () => {
|
||||
describe('deleteComment', () => {
|
||||
test('should throw an error ', () => {
|
||||
// Given
|
||||
const id = 123;
|
||||
const idUser = 456;
|
||||
|
||||
// When
|
||||
// @ts-ignore
|
||||
prismaMock.comment.findFirst.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
expect(deleteComment(id, idUser)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('favoriteArticle', () => {
|
||||
test('should return the favorited article', async () => {
|
||||
// Given
|
||||
const slug = 'How-to-train-your-dragon';
|
||||
const username = 'RealWorld';
|
||||
|
||||
const mockedUserResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
const mockedArticleResponse = {
|
||||
id: 123,
|
||||
slug: 'How-to-train-your-dragon',
|
||||
title: 'How to train your dragon',
|
||||
description: '',
|
||||
body: '',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
authorId: 456,
|
||||
tagList: [],
|
||||
favoritedBy: [],
|
||||
author: {
|
||||
username: 'RealWorld',
|
||||
bio: null,
|
||||
image: null,
|
||||
followedBy: [],
|
||||
},
|
||||
};
|
||||
|
||||
// When
|
||||
// @ts-ignore
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedUserResponse);
|
||||
// @ts-ignore
|
||||
prismaMock.article.update.mockResolvedValue(mockedArticleResponse);
|
||||
|
||||
// Then
|
||||
await expect(favoriteArticle(slug, mockedUserResponse.id)).resolves.toHaveProperty(
|
||||
'favoritesCount',
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if no user is found', async () => {
|
||||
// Given
|
||||
const id = 123;
|
||||
const slug = 'how-to-train-your-dragon';
|
||||
const username = 'RealWorld';
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
await expect(favoriteArticle(slug, id)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
describe('unfavoriteArticle', () => {
|
||||
test('should return the unfavorited article', async () => {
|
||||
// Given
|
||||
const slug = 'How-to-train-your-dragon';
|
||||
const username = 'RealWorld';
|
||||
|
||||
const mockedUserResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
const mockedArticleResponse = {
|
||||
id: 123,
|
||||
slug: 'How-to-train-your-dragon',
|
||||
title: 'How to train your dragon',
|
||||
description: '',
|
||||
body: '',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
authorId: 456,
|
||||
tagList: [],
|
||||
favoritedBy: [],
|
||||
author: {
|
||||
username: 'RealWorld',
|
||||
bio: null,
|
||||
image: null,
|
||||
followedBy: [],
|
||||
},
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedUserResponse);
|
||||
prismaMock.article.update.mockResolvedValue(mockedArticleResponse);
|
||||
|
||||
// Then
|
||||
await expect(unfavoriteArticle(slug, mockedUserResponse.id)).resolves.toHaveProperty(
|
||||
'favoritesCount',
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if no user is found', async () => {
|
||||
// Given
|
||||
const id = 123;
|
||||
const slug = 'how-to-train-your-dragon';
|
||||
const username = 'RealWorld';
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
await expect(unfavoriteArticle(slug, id)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
254
src/tests/services/auth.service.test.ts
Normal file
254
src/tests/services/auth.service.test.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { createUser, getCurrentUser, login, updateUser } from '../../app/routes/auth/auth.service';
|
||||
import prismaMock from '../prisma-mock';
|
||||
|
||||
describe('AuthService', () => {
|
||||
describe('createUser', () => {
|
||||
test('should create new user ', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
// @ts-ignore
|
||||
prismaMock.user.create.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(createUser(user)).resolves.toHaveProperty('token');
|
||||
});
|
||||
|
||||
test('should throw an error when creating new user with empty username ', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: ' ',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { username: ["can't be blank"] } });
|
||||
await expect(createUser(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an error when creating new user with empty email ', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: ' ',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { email: ["can't be blank"] } });
|
||||
await expect(createUser(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an error when creating new user with empty password ', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: ' ',
|
||||
};
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { password: ["can't be blank"] } });
|
||||
await expect(createUser(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an exception when creating a new user with already existing user on same username ', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
const mockedExistingUser = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedExistingUser);
|
||||
|
||||
// Then
|
||||
const error = { email: ['has already been taken'] }.toString();
|
||||
await expect(createUser(user)).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
test('should return a token', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
const hashedPassword = await bcrypt.hash(user.password, 10);
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: hashedPassword,
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(login(user)).resolves.toHaveProperty('token');
|
||||
});
|
||||
|
||||
test('should throw an error when the email is empty', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
email: ' ',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { email: ["can't be blank"] } });
|
||||
await expect(login(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an error when the password is empty', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
email: 'realworld@me',
|
||||
password: ' ',
|
||||
};
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { password: ["can't be blank"] } });
|
||||
await expect(login(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an error when no user is found', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { 'email or password': ['is invalid'] } });
|
||||
await expect(login(user)).rejects.toThrow(error);
|
||||
});
|
||||
|
||||
test('should throw an error if the password is wrong', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
const hashedPassword = await bcrypt.hash('4321', 10);
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'Gerome',
|
||||
email: 'realworld@me',
|
||||
password: hashedPassword,
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
const error = String({ errors: { 'email or password': ['is invalid'] } });
|
||||
await expect(login(user)).rejects.toThrow(error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentUser', () => {
|
||||
test('should return a token', async () => {
|
||||
// Given
|
||||
const id = 123;
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(getCurrentUser(id)).resolves.toHaveProperty('token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateUser', () => {
|
||||
test('should return a token', async () => {
|
||||
// Given
|
||||
const user = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
};
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.update.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(updateUser(user, user.id)).resolves.toHaveProperty('token');
|
||||
});
|
||||
});
|
||||
});
|
||||
145
src/tests/services/profile.service.test.ts
Normal file
145
src/tests/services/profile.service.test.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import prismaMock from '../prisma-mock';
|
||||
import { followUser, getProfile, unfollowUser } from '../../app/routes/profile/profile.service';
|
||||
|
||||
describe('ProfileService', () => {
|
||||
describe('getProfile', () => {
|
||||
test('should return a following property', async () => {
|
||||
// Given
|
||||
const username = 'RealWorld';
|
||||
const id = 123;
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
followedBy: [],
|
||||
};
|
||||
|
||||
// When
|
||||
// @ts-ignore
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(getProfile(username, id)).resolves.toHaveProperty('following');
|
||||
});
|
||||
|
||||
test('should throw an error if no user is found', async () => {
|
||||
// Given
|
||||
const username = 'RealWorld';
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
await expect(getProfile(username, id)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('followUser', () => {
|
||||
test('shoud return a following property', async () => {
|
||||
// Given
|
||||
const usernamePayload = 'AnotherUser';
|
||||
const id = 123;
|
||||
|
||||
const mockedAuthUser = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
followedBy: [],
|
||||
};
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'AnotherUser',
|
||||
email: 'another@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
followedBy: [],
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedAuthUser);
|
||||
prismaMock.user.update.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(followUser(usernamePayload, id)).resolves.toHaveProperty('following');
|
||||
});
|
||||
|
||||
test('shoud throw an error if no user is found', async () => {
|
||||
// Given
|
||||
const usernamePayload = 'AnotherUser';
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
await expect(followUser(usernamePayload, id)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('unfollowUser', () => {
|
||||
test('shoud return a following property', async () => {
|
||||
// Given
|
||||
const usernamePayload = 'AnotherUser';
|
||||
const id = 123;
|
||||
|
||||
const mockedAuthUser = {
|
||||
id: 123,
|
||||
username: 'RealWorld',
|
||||
email: 'realworld@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
followedBy: [],
|
||||
};
|
||||
|
||||
const mockedResponse = {
|
||||
id: 123,
|
||||
username: 'AnotherUser',
|
||||
email: 'another@me',
|
||||
password: '1234',
|
||||
bio: null,
|
||||
image: null,
|
||||
token: '',
|
||||
demo: false,
|
||||
followedBy: [],
|
||||
};
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(mockedAuthUser);
|
||||
prismaMock.user.update.mockResolvedValue(mockedResponse);
|
||||
|
||||
// Then
|
||||
await expect(unfollowUser(usernamePayload, id)).resolves.toHaveProperty('following');
|
||||
});
|
||||
|
||||
test('shoud throw an error if no user is found', async () => {
|
||||
// Given
|
||||
const usernamePayload = 'AnotherUser';
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
prismaMock.user.findUnique.mockResolvedValue(null);
|
||||
|
||||
// Then
|
||||
await expect(unfollowUser(usernamePayload, id)).rejects.toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
6
src/tests/services/tag.service.test.ts
Normal file
6
src/tests/services/tag.service.test.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
describe('TagService', () => {
|
||||
describe('getTags', () => {
|
||||
// TODO : prismaMock.tag.groupBy.mockResolvedValue(mockedResponse) doesn't work
|
||||
test.todo('should return a list of strings');
|
||||
});
|
||||
});
|
||||
79
src/tests/utils/profile.utils.test.ts
Normal file
79
src/tests/utils/profile.utils.test.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import profileMapper from '../../app/routes/profile/profile.utils';
|
||||
|
||||
describe('ProfileUtils', () => {
|
||||
describe('profileMapper', () => {
|
||||
test('should return a profile', () => {
|
||||
// Given
|
||||
const user = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
followedBy: [],
|
||||
};
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
const expected = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
following: false,
|
||||
};
|
||||
|
||||
// Then
|
||||
expect(profileMapper(user, id)).toEqual(expected);
|
||||
});
|
||||
|
||||
test('should return a profile followed by the user', () => {
|
||||
// Given
|
||||
const user = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
followedBy: [
|
||||
{
|
||||
id: 123,
|
||||
},
|
||||
],
|
||||
};
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
const expected = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
following: true,
|
||||
};
|
||||
|
||||
// Then
|
||||
expect(profileMapper(user, id)).toEqual(expected);
|
||||
});
|
||||
|
||||
test('should return a profile not followed by the user', () => {
|
||||
// Given
|
||||
const user = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
followedBy: [
|
||||
{
|
||||
username: 'NotRealWorld',
|
||||
},
|
||||
],
|
||||
};
|
||||
const id = 123;
|
||||
|
||||
// When
|
||||
const expected = {
|
||||
username: 'RealWorld',
|
||||
bio: 'My happy life',
|
||||
image: null,
|
||||
following: false,
|
||||
};
|
||||
|
||||
// Then
|
||||
expect(profileMapper(user, id)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user