-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
done user and movie integration test
- Loading branch information
Iván García Laverde
committed
Aug 11, 2023
1 parent
093aafe
commit 4a946a4
Showing
11 changed files
with
277 additions
and
34 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import * as Chance from 'chance'; | ||
import { EntityManager } from 'typeorm'; | ||
import { Movie } from '../entities/Movie'; | ||
|
||
export class MovieFactory { | ||
private static chance = new Chance(); | ||
|
||
/** | ||
* Creates a test movie | ||
* @param {Partial<Movie>} movie | ||
* @param {EntityManager} manager | ||
* @returns {Promise<Movie>} | ||
*/ | ||
public static async createMovie(movie: Partial<Movie>, manager?: EntityManager): Promise<Movie> { | ||
let newMovie = new Movie({ | ||
tmdbId: movie.tmdbId ?? this.chance.integer({ min: 1, max: 1000000 }), | ||
title: movie.title ?? this.chance.name(), | ||
overview: movie.overview ?? this.chance.string(), | ||
posterPath: movie.posterPath ?? `https://image.tmdb.org/t/p/w500/${this.chance.string({ length: 10 })}.jpg`, | ||
releaseDate: | ||
movie.releaseDate ?? | ||
new Date(this.chance.date({ year: this.chance.integer({ min: 1998, max: 2023 }) })), | ||
}); | ||
|
||
Object.assign(newMovie, movie); | ||
if (manager) newMovie = await manager.save(Movie, newMovie); | ||
|
||
return newMovie; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import * as Chance from 'chance'; | ||
import { EntityManager } from 'typeorm'; | ||
import { Movie } from '../entities/Movie'; | ||
import { Review } from '../entities/Review'; | ||
import { User } from '../entities/User'; | ||
|
||
export class ReviewFactory { | ||
private static chance = new Chance(); | ||
|
||
/** | ||
* Creates a test review | ||
* @param {Partial<Review>} review | ||
* @param {EntityManager} manager | ||
* @param {User} user | ||
* @param {Movie} movie | ||
* @param {EntityManager} manager | ||
* @returns {Promise<Review>} | ||
*/ | ||
public static async createReview( | ||
review: Partial<Review>, | ||
user: User, | ||
movie: Movie, | ||
manager?: EntityManager, | ||
): Promise<Review> { | ||
let newReview = new Review({ | ||
rating: review.rating ?? this.chance.integer({ min: 1, max: 10 }), | ||
comment: review.comment ?? this.chance.string(), | ||
movieTMDBId: movie.tmdbId, | ||
username: user.username, | ||
userId: user.id, | ||
}); | ||
|
||
Object.assign(newReview, review); | ||
if (manager) newReview = await manager.save(Review, newReview); | ||
|
||
return newReview; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import * as Chance from 'chance'; | ||
import * as _ from 'lodash'; | ||
import { DateTime } from 'luxon'; | ||
import * as request from 'supertest'; | ||
import { EntityManager } from 'typeorm'; | ||
import App from '../../../app'; | ||
import { Movie } from '../../../entities/Movie'; | ||
import { User, UserRoles } from '../../../entities/User'; | ||
import { MovieFactory } from '../../../factories/MovieFactory'; | ||
import { ReviewFactory } from '../../../factories/ReviewFactory'; | ||
import { UserFactory } from '../../../factories/UserFactory'; | ||
import * as Encryption from '../../../utils/encryption'; | ||
import { ReviewResponse } from '../../review/reviewTypes'; | ||
import { MovieController } from '../movieController'; | ||
|
||
const app = new App([new MovieController()]); | ||
const chance = new Chance(); | ||
const server = app.getServer(); | ||
let manager: EntityManager; | ||
|
||
beforeAll(async () => { | ||
await app.listen(); | ||
await app.databaseConnection.resetConnections(); | ||
manager = app.getDatabaseManager(); | ||
}); | ||
|
||
beforeEach(async () => { | ||
await app.databaseConnection.resetConnections(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await app.databaseConnection.resetConnections(); | ||
await app.databaseConnection.closeConnection(); | ||
}); | ||
|
||
describe('When sending a request', () => { | ||
let user: User; | ||
beforeEach(async () => { | ||
user = await UserFactory.createUser( | ||
{ | ||
email: '[email protected]', | ||
role: UserRoles.USER, | ||
password: await Encryption.getHashedPassword('very-secret-password'), | ||
}, | ||
manager, | ||
); | ||
|
||
jest.spyOn(Encryption, 'decodeToken').mockReturnValue({ | ||
userId: user.id, | ||
role: UserRoles.USER, | ||
email: user.email, | ||
exp: DateTime.local().plus({ hours: 1 }).toJSDate(), | ||
}); | ||
}); | ||
describe('GET /movies, then', () => { | ||
test('it should return a list of movies', async () => { | ||
const movies = await Promise.all( | ||
_.range(100).map(async () => { | ||
return await MovieFactory.createMovie({}, manager); | ||
}), | ||
); | ||
|
||
const response = await request(server).get('/movies'); | ||
|
||
expect(response.error).toBeFalsy(); | ||
expect(response.status).toBe(200); | ||
|
||
expect(response.body).toHaveProperty('movies'); | ||
expect(response.body.movies).toHaveLength(10); | ||
expect(response.body.pages).toBe(10); | ||
response.body.movies.forEach((movie: Movie) => { | ||
const dbMovie = movies.find((m) => m.id === movie.id); | ||
expect(dbMovie).toBeDefined(); | ||
}); | ||
}); | ||
}); | ||
describe('GET /movies/:tmdbId/reviews, then', () => { | ||
test('it should return all reviews from a movie', async () => { | ||
const movie = await MovieFactory.createMovie( | ||
{ | ||
tmdbId: 888, | ||
title: 'Batman: The Dark Knight', | ||
overview: | ||
'The Dark Knight of Gotham City begins his war on crime with his first major enemy being the clownishly homicidal Joker.', | ||
releaseDate: DateTime.fromISO('2008-07-16').toJSDate(), | ||
}, | ||
manager, | ||
); | ||
|
||
const reviews = await Promise.all( | ||
_.range(50).map(async () => { | ||
const user = await UserFactory.createUser( | ||
{ | ||
email: chance.email(), | ||
role: UserRoles.USER, | ||
password: await Encryption.getHashedPassword('very-secret-password'), | ||
}, | ||
manager, | ||
); | ||
|
||
return await ReviewFactory.createReview({}, user, movie, manager); | ||
}), | ||
); | ||
|
||
const response = await request(server).get(`/movies/${movie.tmdbId}/reviews`); | ||
|
||
expect(response.error).toBeFalsy(); | ||
expect(response.status).toBe(200); | ||
|
||
expect(response.body).toHaveProperty('reviews'); | ||
expect(response.body.reviews).toHaveLength(10); | ||
expect(response.body.pages).toBe(5); | ||
response.body.reviews.forEach((review: ReviewResponse) => { | ||
const dbReview = reviews.find((r) => r.id === review.id); | ||
expect(dbReview).toBeDefined(); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,20 @@ | ||
/** | ||
* Review object sent in the response body | ||
*/ | ||
export interface ReviewResponse { | ||
id: string; | ||
tmdbId?: number; | ||
username?: string; | ||
rating: number; | ||
comment: string; | ||
createdAt: Date; | ||
updatedAt: Date; | ||
} | ||
|
||
/** | ||
* Response for the POST /reviews endpoint | ||
*/ | ||
export interface SubmitReviewResponse { | ||
message: string; | ||
review: { | ||
id: string; | ||
tmdbId: number; | ||
username: string; | ||
rating: number; | ||
comment: string; | ||
createdAt: Date; | ||
updatedAt: Date; | ||
}; | ||
review: ReviewResponse; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,18 @@ | ||
import * as _ from 'lodash'; | ||
import { DateTime } from 'luxon'; | ||
import * as request from 'supertest'; | ||
import { EntityManager } from 'typeorm'; | ||
import App from '../../../app'; | ||
import { UserController } from '../userController'; | ||
import { User, UserRoles } from '../../../entities/User'; | ||
import * as Encryption from '../../../utils/encryption'; | ||
import { MovieFactory } from '../../../factories/MovieFactory'; | ||
import { ReviewFactory } from '../../../factories/ReviewFactory'; | ||
import { UserFactory } from '../../../factories/UserFactory'; | ||
import * as Encryption from '../../../utils/encryption'; | ||
import { ReviewResponse } from '../../review/reviewTypes'; | ||
import { UserController } from '../userController'; | ||
|
||
const app = new App([new UserController()]); | ||
const server = app.getServer(); | ||
let manager: EntityManager; | ||
|
||
beforeAll(async () => { | ||
|
@@ -27,7 +32,7 @@ afterAll(async () => { | |
|
||
describe('When sending a POST request to /users/register, then', () => { | ||
test('it should create a new user', async () => { | ||
const response = await request(app.getServer()).post('/users/register').send({ | ||
const response = await request(server).post('/users/register').send({ | ||
username: 'ivangarl', | ||
email: '[email protected]', | ||
password: 'very-secret-password', | ||
|
@@ -66,16 +71,68 @@ describe('When sending a POST request to /users/login, then', () => { | |
jest.spyOn(Encryption, 'decodeToken').mockReturnValue({ | ||
userId: user.id, | ||
role: UserRoles.USER, | ||
email: '[email protected]', | ||
email: user.email, | ||
exp: DateTime.local().plus({ hours: 1 }).toJSDate(), | ||
}); | ||
|
||
const response = await request(app.getServer()).post('/users/login').send({ | ||
const response = await request(server).post('/users/login').send({ | ||
email: user.email, | ||
password, | ||
}); | ||
|
||
expect(response.error).toBeFalsy(); | ||
expect(response.status).toBe(200); | ||
|
||
expect(response.body).toHaveProperty('token'); | ||
expect(response.body).toHaveProperty('email'); | ||
}); | ||
}); | ||
|
||
describe('When sending a GET request to /users/:username/reviews, then', () => { | ||
test('it should return all reviews from a user', async () => { | ||
const password = 'very-secret-password'; | ||
const user = await UserFactory.createUser( | ||
{ | ||
email: '[email protected]', | ||
role: UserRoles.USER, | ||
password: await Encryption.getHashedPassword(password), | ||
}, | ||
manager, | ||
); | ||
|
||
// create movies and reviews | ||
const reviews = await Promise.all( | ||
_.range(50).map(async () => { | ||
const movie = await MovieFactory.createMovie({}, manager); | ||
return await ReviewFactory.createReview({}, user, movie, manager); | ||
}), | ||
); | ||
|
||
jest.spyOn(Encryption, 'decodeToken').mockReturnValue({ | ||
userId: user.id, | ||
role: UserRoles.USER, | ||
email: user.email, | ||
exp: DateTime.local().plus({ hours: 1 }).toJSDate(), | ||
}); | ||
|
||
const response = await request(server).get(`/users/${user.username}/reviews`); | ||
|
||
expect(response.error).toBeFalsy(); | ||
expect(response.status).toBe(200); | ||
|
||
expect(response.body.reviews).toHaveLength(10); | ||
expect(response.body.id).toBe(user.id); | ||
expect(response.body.username).toBe(user.username); | ||
expect(response.body.email).toBe(user.email); | ||
expect(response.body.role).toBe(user.role); | ||
expect(response.body.pages).toBe(5); | ||
response.body.reviews.forEach((review: ReviewResponse) => { | ||
const dbReview = reviews.find((r) => r.id === review.id); | ||
expect(dbReview).toBeDefined(); | ||
expect(review.id).toBe(dbReview.id); | ||
expect(review.rating).toBe(dbReview.rating); | ||
expect(review.comment).toBe(dbReview.comment); | ||
expect(review.tmdbId).toBe(dbReview.movieTmdbId); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.