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
37 changes: 24 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,41 @@ In this challenge use `Test Driven Development` to build a RESTful API using Nod
Demonstrate your understanding of this week's concepts by answering the following free-form questions. Edit this document to include your answers after each question. Make sure to leave a blank line above and below your answer so it is clear and easy to read by your project manager.

1. In Jest, what are the differences between `describe()` and `it()` globals, and what are good uses for them?

'describe()' - This code block describes the overall component and nests the 'it() blocks.
'it()' - This code block contains the test for each dynamic of a component as described by the 'describe()' block.

1. What is the point of `Test Driven Development`? What do you think about this approach?

The point of TDD is to write code by first building tests which serve as a checkpoints for each component in the project. This is approach, I believe, leads to more thought out code and ascertains success, however, can be a hindrance to simpler builds that are time sensitive.


1. Mention three types of automated tests.

Three types of automated tests are unit tests, which tests small units of code like funcions and methods, integration tests, which tests several units altogether to assure proper functionality of a large section of code, and regression tests, which are tests designed to confirm that add-ons and changes in code have not adversely affected the code.


## Project Set Up

- [ ] Fork and clone this repository.
- [ ] **CD into the folder** where you downloaded the repository.
- [ ] Run `yarn` or `npm i` to download all dependencies.
- [ ] Type `yarn test` or `npm test` to run the tests. The `test` script is already configured.
- [x] Fork and clone this repository.
- [x] **CD into the folder** where you downloaded the repository.
- [x] Run `yarn` or `npm i` to download all dependencies.
- [x] Type `yarn test` or `npm test` to run the tests. The `test` script is already configured.

## Minimum Viable Product

Your finished project must include all of the following requirements:

- [ ] Use `jest` and `supertest` to write the tests.
- [ ] Write the **tests BEFORE** writing the route handlers.
- [ ] Your API must have both `POST` and `GET` endpoints for `/games`.
- [ ] Write a **minimum** of three tests per endpoint.
- [x] Use `jest` and `supertest` to write the tests.
- [x] Write the **tests BEFORE** writing the route handlers.
- [x] Your API must have both `POST` and `GET` endpoints for `/games`.
- [x] Write a **minimum** of three tests per endpoint.

Below is a product specification covering the requirements for your endpoints.

### POST /games

- [ ] The `POST /games` endpoint should take in an object that looks like this
- [x] The `POST /games` endpoint should take in an object that looks like this

```js
{
Expand All @@ -58,13 +69,13 @@ Below is a product specification covering the requirements for your endpoints.
}
```

- [ ] In the route handler, validate that the required fields are included inside the body. If the information is incomplete, return a `422` status code.
- [ ] Write tests to verify that the endpoint returns the correct HTTP status code when receiving correct and incorrect game data.
- [x] In the route handler, validate that the required fields are included inside the body. If the information is incomplete, return a `422` status code.
- [x] Write tests to verify that the endpoint returns the correct HTTP status code when receiving correct and incorrect game data.

### GET /games

- [ ] The `GET /games` endpoint should return the list of games and HTTP status code 200.
- [ ] Write a test to make sure this endpoint always returns an array, even if there are no games stored. If there are no games to return, the endpoint should return an empty array.
- [x] The `GET /games` endpoint should return the list of games and HTTP status code 200.
- [x] Write a test to make sure this endpoint always returns an array, even if there are no games stored. If there are no games to return, the endpoint should return an empty array.

## Stretch Problems

Expand Down
24 changes: 24 additions & 0 deletions api/helpers/models/gamesModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// intialize knex & database
const knex = require('knex');
const db = require('../../../dbConfig'); // intialize database

/* Functions for database searching, to be exported. */

// CREATE
const add = (newGame) => {
return db('games')
.insert(newGame)
.into('games');
}

// READ
const find = () => {
return db('games');
}

/* Module exports for use in routers */
module.exports = {
// CRUD operation exports
add, // [x] logic for CREATE/post
find, // [x] logic for READ/get
}
58 changes: 58 additions & 0 deletions api/routers/games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// intialize route
const express = require('express');
const router = express.Router();
const db = require('../helpers/models/gamesModel.js');

// CRUD logic

// Create/Post logic
router.post('/', (req, res) => {
const game = req.body;
const { genre, title } = game;

if (title && genre) {
db
.add(game)
.then(newGame => {
res
.status(201)
.json(newGame)
})
.catch(err => {
res
.status(500)
.json({ err: 'Failed to insert game!'})
});
} else if (!title) {
res
.status(422)
.json({ err: 'Bad request (check title)'});
} else if (!genre) {
res
.status(422)
.json({ err: 'Bad request (check genre)'});
} else {
res
.status(500)
.json({ err: 'Failed to add game'})
}
});

// Read/get logic

router.get('/', (req, res) => {
db
.find()
.then(games => {
res
.status(200)
.json(games);
})
.catch(err => {
res
.status(500)
.json({ err: 'Could not retrieve games from database' });
});
});

module.exports = router;
26 changes: 26 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// initialize server and routes
const express = require('express');
const server = express();
const games = require('./routers/games');

// server variables and middleware
const port = 5511;
const parser = express.json();

const helmet = require('helmet');
const logger = require('morgan');

server.use(
parser,
logger('tiny'),
helmet(),
);

// define routes and activate server
server.get('/', (req, res) => {
res.status(200).json({message: 'Hello World'})
});

server.use('/api/games', games); // route

module.exports = server;
77 changes: 77 additions & 0 deletions api/server.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const request = require('supertest'); // initialize supertest for endpoints
const server = require('./server'); // bring in the server
const db = require('../dbConfig'); // bring in the database

/* Home endpoint testing*/
// Returns code 200
describe('GET ("/") ', () => {
it('returns status code 200', async () => {
let res = await request(server).get('/');
expect(res.status).toBe(200);
});

// Returns JSON data
it('returns JSON data', async () => {
const res = await request(server).get('/');
expect(res.type).toBe('application/json'); // or .toMatch(/json/i)
});

// Functional (returns a 'Hello world' object)
it('is functional', async () => {
const res = await request(server).get('/');
expect(res.body).toEqual({ message: 'Hello World'});
});
});

/* Games GET testing */

describe('GET ("/games")', () => {
it('returns status code 200', async () => {
let res = await request(server).get('/api/games');
expect(res.status).toBe(200);
});

it('returns an array', async () => {
let res = await request(server).get('/api/games');
expect(Array.isArray(res.body)).toBeTruthy();
});

it('returns an object array', async () => {
let res = await request(server).get('/api/games');
for (i = 0; i < res.body.length; i++) { // iterate through each item in the response body
expect(typeof res.body[i]).toEqual('object');
};
});
});

/* Games POST testing */
describe('POST ("/games")', () =>{
it('returns 201 with correct data', async () => {
const body = {
title: 'The most dangerous game',
genre: 'Bad editing',
releaseYear: 2133
};
let res = await request(server).post('/api/games').send(body);
expect(res.status).toBe(201);
});

it('returns an object', async () => {
const body = {
title: 'Pacman',
genre: 'Arcade',
releaseYear: 1980
};
let res = await request(server).post('/api/games').send(body);
expect(typeof res.body).toEqual('object');
});

it('returns 422 with incorrect data', async () => {
const body = {
title: 'Pacman',
releaseYear: 1980
};
let res = await request(server).post('/api/games').send(body);
expect(res.status).toBe(422);
});
});
Binary file added data/games.sqlite3
Binary file not shown.
12 changes: 12 additions & 0 deletions data/migrations/20190507231900_games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
exports.up = function(knex, Promise) {
return knex.schema.createTable('games', function(tbl) {
tbl.increments();
tbl.string('title', 128).notNullable();
tbl.string('genre', 25).notNullable();
tbl.integer('releaseYear');
});
};

exports.down = function(knex, Promise) {
return knex.schema.dropTableIfExists('games');
};
20 changes: 20 additions & 0 deletions data/seeds/001-games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

exports.seed = function(knex, Promise) {
// Deletes ALL existing entries
return knex('games').del()
.then(function () {
// Inserts seed entries
return knex('games').insert([
{
title: 'Pacman', // required
genre: 'Arcade', // required
releaseYear: 1980 // not required
},
{
title: 'Street Fighter', // required
genre: 'Arcade', // required
releaseYear: 1987 // not required
}
]);
});
};
4 changes: 4 additions & 0 deletions dbConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const knex = require('knex');
const knexConfig = require('./knexfile.js');

module.exports = knex(knexConfig.development);
Empty file added index.js
Empty file.
51 changes: 51 additions & 0 deletions knexfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Update with your config settings.

module.exports = {

development: {
client: 'sqlite3',
connection: {
filename: './data/games.sqlite3'
},
useNullAsDefault: true,
migrations: {
directory: './data/migrations'
},
seeds: {
directory: './data/seeds'
}
},

staging: {
client: 'postgresql',
connection: {
database: 'my_db',
user: 'username',
password: 'password'
},
pool: {
min: 2,
max: 10
},
migrations: {
tableName: 'knex_migrations'
}
},

production: {
client: 'postgresql',
connection: {
database: 'my_db',
user: 'username',
password: 'password'
},
pool: {
min: 2,
max: 10
},
migrations: {
tableName: 'knex_migrations'
}
}

};
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Testing Sprint Challenge",
"main": "index.js",
"scripts": {
"test": "jest --watch --verbose",
"test": "jest --watchAll --verbose",
"start": "nodemon index.js"
},
"repository": {
Expand All @@ -19,10 +19,15 @@
},
"homepage": "https://github.com/LambdaSchool/Sprint-Challenge--Testing#readme",
"dependencies": {
"express": "^4.16.4"
"express": "^4.16.4",
"helmet": "^3.18.0",
"knex": "^0.16.5",
"sqlite3": "^4.0.6"
},
"devDependencies": {
"jest": "^23.6.0",
"jest": "^24.8.0",
"morgan": "^1.9.1",
"nodemon": "^1.19.0",
"supertest": "^3.3.0"
}
}
Loading