Skip to content

api node group 2019-05-16 #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
69 changes: 69 additions & 0 deletions 2019/2019-05-16/api-node-imbd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
This is a Kata which aims at developing a Node API for creating a personal Movie Database using Test Driven Development[TDD] approach

## Requirements

- good understanding of JavaScript
- basic knowledge of server/client request/response
- basic understanding of HTTP
- basic understanding of GIT

## Development using

- Node.js
- MongoDB
- TDD approach
- [Postman](https://www.getpostman.com/) - API development environment
- [Robo 3T](https://robomongo.org/) - a free lightweight GUI for MongoDB enthusiasts

## User Story 1

1. As a User I want to insert movie information to create my own movie database.

### Acceptance Criteria

- The movie to be inserted must have title and description
- User cannot enter the same movie name again i.e duplicates must be tracked based on the title of the movie
- The user must send the data to the API in JSON format

## User Story 2

Coming soon...

### Step 01 - Core

- Set up your project by initiate NPM
- Install Jest
- Create your first test without any implementation.
- Test your code and see if you get back the correct response

```
input (title, description)
output
movie: {
id,
title,
description
}
status: 'successfully added movie'
```

### Step 02 - Core

- Create a mock / fake DB.
- Use Dependency Injection to integrate the DB into your implementation.
- Test for duplicated movie
- Use `jest.spyOn` to test the save and getAll method of your DB
- Created a index file in the core to export all the controllers

### Step 03 - DB

- Create tests for the DB
- Install Mongo and Mongoose
- Connect to a DB
- Create the movie schema
- Async / Await
- Add the DB methods (save and getAll)

Some hints:
OverwriteModelError: Cannot overwrite `Movie` model once compiled.
const movieDatabaseSchema = mongoose.models.Movie || mongoose.model('Movie', movieSchema);
69 changes: 69 additions & 0 deletions 2019/2019-05-16/api-node-imbd/core/create-movie-spy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const sinon = require('sinon');
const assert = require('assert');
const createMovie = require('./create-movie');

// usually you would use spy to spy on real functions

const fakeDB = {
getAllMovies: () => {
return [{ title: 'Star Wars II', description: 'Description' }, { title: 'Star Wars', description: 'Description' }];
},
saveMovie: (title, description) => {
return `${title} is saved into the database!`;
}
};

describe('CreateMovie', () => {
let spyGetAllMovies;
let spySaveMovie;

beforeEach(function() {
spyGetAllMovies = sinon.spy(fakeDB, 'getAllMovies');
spySaveMovie = sinon.spy(fakeDB, 'saveMovie');
});

afterEach(function() {
fakeDB.getAllMovies.restore();
fakeDB.saveMovie.restore();
});

it('if the movie has no title return an error', () => {
const actual = createMovie(fakeDB)('', 'description');
const expected = 'Enter a title';
assert.equal(actual, expected);
assert(spyGetAllMovies.notCalled);
assert(spySaveMovie.notCalled);
});

it('if the movie has no Description return an error', () => {
const actual = createMovie(fakeDB)('Star Wars', '');
const expected = 'Enter a Description';
assert.equal(actual, expected);
assert(spyGetAllMovies.notCalled);
assert(spySaveMovie.notCalled);
});

it('if the movie has no Title and no Description return an error', () => {
const actual = createMovie(fakeDB)('', '');
const expected = 'Enter a Title and Description';
assert.equal(actual, expected);
assert(spyGetAllMovies.notCalled);
assert(spySaveMovie.notCalled);
});

it('if the movie has both Title and Description, movie is saved', () => {
const actual = createMovie(fakeDB)('Star Wars III', 'Description');
const expected = 'Star Wars III is saved into the database!';
assert.equal(actual, expected);
assert(spyGetAllMovies.calledOnce);
assert(spySaveMovie.withArgs('Star Wars III', 'Description').called);
});

it('if the movie already exists in the DB, return an error', () => {
const actual = createMovie(fakeDB)('Star Wars II', 'Description');
const expected = 'Movie already exists.';
assert.equal(actual, expected);
assert(spyGetAllMovies.calledOnce);
assert(spySaveMovie.notCalled);
});
});
80 changes: 80 additions & 0 deletions 2019/2019-05-16/api-node-imbd/core/create-movie-stub.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const sinon = require('sinon');
const assert = require('assert');
const createMovie = require('./create-movie');

// using stub instead of spy

const fakeDB = {
getAllMovies: () => {},
saveMovie: (title, description) => {}
};

describe('CreateMovie', () => {
let stubGetAllMovies;
let stubSaveMovie;

afterEach(function() {
fakeDB.getAllMovies.restore();
fakeDB.saveMovie.restore();
});

it('if the movie has no title return an error', () => {
stubGetAllMovies = sinon.stub(fakeDB, 'getAllMovies');
stubSaveMovie = sinon.stub(fakeDB, 'saveMovie');
const actual = createMovie(fakeDB)('', 'description');
const expected = 'Enter a title';
assert.equal(actual, expected);
assert(stubGetAllMovies.notCalled);
assert(stubSaveMovie.notCalled);
});

it('if the movie has no Description return an error', () => {
stubGetAllMovies = sinon.stub(fakeDB, 'getAllMovies');
stubSaveMovie = sinon.stub(fakeDB, 'saveMovie');
const actual = createMovie(fakeDB)('Star Wars', '');
const expected = 'Enter a Description';
assert.equal(actual, expected);
assert(stubGetAllMovies.notCalled);
assert(stubSaveMovie.notCalled);
});

it('if the movie has no Title and no Description return an error', () => {
stubGetAllMovies = sinon.stub(fakeDB, 'getAllMovies');
stubSaveMovie = sinon.stub(fakeDB, 'saveMovie');
const actual = createMovie(fakeDB)('', '');
const expected = 'Enter a Title and Description';
assert.equal(actual, expected);
assert(stubGetAllMovies.notCalled);
assert(stubSaveMovie.notCalled);
});

it('if the movie has both Title and Description, movie is saved', () => {
stubGetAllMovies = sinon
.stub(fakeDB, 'getAllMovies')
.returns([
{ title: 'Star Wars II', description: 'Description' },
{ title: 'Star Wars', description: 'Description' }
]);
stubSaveMovie = sinon.stub(fakeDB, 'saveMovie').returns('Star Wars III is saved into the database!');
const actual = createMovie(fakeDB)('Star Wars III', 'Description');
const expected = 'Star Wars III is saved into the database!';
assert.equal(actual, expected);
assert(stubGetAllMovies.calledOnce);
assert(stubSaveMovie.withArgs('Star Wars III', 'Description').called);
});

it('if the movie already exists in the DB, return an error', () => {
stubGetAllMovies = sinon
.stub(fakeDB, 'getAllMovies')
.returns([
{ title: 'Star Wars II', description: 'Description' },
{ title: 'Star Wars', description: 'Description' }
]);
stubSaveMovie = sinon.stub(fakeDB, 'saveMovie');
const actual = createMovie(fakeDB)('Star Wars II', 'Description');
const expected = 'Movie already exists.';
assert.equal(actual, expected);
assert(stubGetAllMovies.calledOnce);
assert(stubSaveMovie.notCalled);
});
});
22 changes: 22 additions & 0 deletions 2019/2019-05-16/api-node-imbd/core/create-movie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const createMovie = database => {
return (title, description) => {
if (!title && !description) {
return 'Enter a Title and Description';
}
if (!title) {
return 'Enter a title';
}
if (!description) {
return 'Enter a Description';
}
const movies = database.getAllMovies();
const movieExist = movies.some(movie => movie.title == title);
if (movieExist) {
return 'Movie already exists.';
}

return database.saveMovie(title, description);
};
};

module.exports = createMovie;
Empty file.
45 changes: 45 additions & 0 deletions 2019/2019-05-16/api-node-imbd/database/database.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const assert = require('assert');
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/MovieDB', { useNewUrlParser: true });
const schema = new mongoose.Schema({ title: 'string', description: 'string' });
const Movie = mongoose.models.Movie || mongoose.model('Movie', schema);

const DB = {
getAllMovies: async () => {
return await Movie.find().map(movies => {
return movies.map(movie => {
return {
title: movie.title,
description: movie.description
};
});
});
},
saveMovie: async (title, description) => {
const result = await Movie.create({ title, description });
return `${result.title} is saved into the database!`;
}
};

describe('Database', () => {
beforeEach(done => mongoose.connection.collections['movies'].drop(() => done()));

it('Should save a movie to database', async () => {
const actual = await DB.saveMovie('Star Wars VI', 'Description');
const expected = 'Star Wars VI is saved into the database!';
assert.equal(actual, expected);
});
it('Should get all movies in the database', async () => {
await Movie.create({ title: 'title1', description: 'ggggg1' });
await Movie.create({ title: 'title2', description: 'ggggg2' });
await Movie.create({ title: 'title3', description: 'ggggg3' });
const actual = await DB.getAllMovies();
const expect = [
{ title: 'title1', description: 'ggggg1' },
{ title: 'title2', description: 'ggggg2' },
{ title: 'title3', description: 'ggggg3' }
];
assert.deepEqual(actual, expect);
});
});
Loading