diff --git a/README.md b/README.md index a11ea7f..771b761 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ "SWAPI races" is a game based on the characters and environment of Star Wars. User will choose a character which will determine his alliance. He will be assigned a starter ship, based on his alliance, that he will use to race. The user will race against a non-alliance Bounty Hunter (computer) and/or another user. # MOTIVATION -This project is being created to demonstrate a relational database. +This project is being created to demonstrate a ~~relational~~ NoSQL database. # API REFERENCE We are using the Star Wars API SWAPI for our characters, vehicles, planets, and more. @@ -16,8 +16,14 @@ https://swapi.co/ - Post-race, the user will either receive money/credit for his win or nothing for his loss. - Lastly, if the user wins the race, he can take his winnings and purchase an upgraded vehicle. +# API + +List out api calls with more technical style documentation + # STYLE We are using Promises to handle our asynchronous code, creating modules for repeated code, and using whitespace for paragraph separation only. # GROUP MEMBERS -Our group is called Ctr8 and we are Robin, Andrew, Eli and Kate. \ No newline at end of file +Our group is called Ctr8 and we are Robin, Andrew, Eli and Kate. + +// initial grading/feedback commit \ No newline at end of file diff --git a/lib/models/planet.js b/lib/models/planet.js index 87e14ed..b99c60d 100644 --- a/lib/models/planet.js +++ b/lib/models/planet.js @@ -6,4 +6,10 @@ const planetSchema = new Schema ({ name: RequiredString }); +planetSchema.statics.getRandomPlanetId = function () { + return this.aggregate([{ + $sample: { size: 1 } + }]).then(([ planet ]) => planet._id); +}; + module.exports = mongoose.model('Planet', planetSchema); \ No newline at end of file diff --git a/lib/models/race.js b/lib/models/race.js index 3865996..cd0009d 100644 --- a/lib/models/race.js +++ b/lib/models/race.js @@ -1,5 +1,6 @@ const mongoose = require('mongoose'); const Schema = mongoose.Schema; +const User = require('./user'); const raceSchema = new Schema({ planet: { @@ -27,4 +28,37 @@ const raceSchema = new Schema({ } }); +raceSchema.statics.getExpiredRaces = function() { + // shouldn't these be "less than" current date? + return this.find({active: true, endTime: {$lt: new Date()}}); +}; + +raceSchema.statics.getAvailableRaces = function() { + // Don't they need to be active too? + return this.find({active: true, endTime: {$gt: new Date()}}); +}; + +raceSchema.statics.findByIdAndAddUser = function(userId) { + // can't register twice, use $addToSet + return this.findByIdAndUpdate(this.id, { $addToSet: { users: userId } }, { new : true } ) + .lean() + .then(race => { + if(!race) throw { code: 404, message: 'Incorrect id' }; + return race; + }); +}; + +raceSchema.methods.cancel = function() { + return Promise.all([ + this.remove(), + User.findByIdAndRemove(this.users[0]) + ]); +}; + +raceSchema.methods.complete = function(winner) { + this.active = false; + this.winner = winner; + return this.save(); +}; + module.exports = mongoose.model('Race', raceSchema); \ No newline at end of file diff --git a/lib/models/user.js b/lib/models/user.js index 235c71f..e5a7726 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -26,4 +26,12 @@ userSchema.methods.comparePassword = function(pass) { return bcrypt.compareSync(pass, this.hash); }; +userSchema.statics.findByIdAndWinPrize = function(userId, prize) { + // Retrieve, adjust, and save same user object + this.findById(userId).then(user => { + user.bankroll += prize; + return user.save(); + }); +}; + module.exports = mongoose.model('User', userSchema); \ No newline at end of file diff --git a/lib/models/vehicle.js b/lib/models/vehicle.js index 0d3673d..b801bbe 100644 --- a/lib/models/vehicle.js +++ b/lib/models/vehicle.js @@ -8,6 +8,7 @@ const vehicleSchema = new Schema ({ type: Number, required: true }, + // shouldn't this be a number??? max_atmosphering_speed: RequiredString }); diff --git a/lib/routes/characters.js b/lib/routes/characters.js index a71afe2..9dce536 100644 --- a/lib/routes/characters.js +++ b/lib/routes/characters.js @@ -5,7 +5,7 @@ const Character = require('../models/character'); router .get('/', validateAuth, (req, res, next) => { Character.find().lean() - .then(found => res.json(found)) + .then(characters => res.json(characters)) .catch(next); }); diff --git a/lib/routes/planets.js b/lib/routes/planets.js index 739fcb3..643635a 100644 --- a/lib/routes/planets.js +++ b/lib/routes/planets.js @@ -4,7 +4,7 @@ const validateAuth = require('../utils/validateAuth')(); router .get('/', validateAuth, (req, res, next) => { - return Planet.find() + return Planet.find().lean() .then( found => { return res.json(found); }) diff --git a/lib/routes/races.js b/lib/routes/races.js index 01e65ae..730edd0 100644 --- a/lib/routes/races.js +++ b/lib/routes/races.js @@ -8,14 +8,22 @@ router .then(race => res.json(race)) .catch(next); }) + .get('/', (req, res, next) => { - Race.find() + // nice job on query, select, populate for this find. + // I moved get race login into Race model + Race.getAvailableRaces() .select('name _id endTime') - .where('endTime').gt(Date.parse(new Date)) .populate({path: 'planet', select: 'name'}) .lean() .then(race => res.json(race)) .catch(next); + }) + + .put('/:id/users', validateAuth, (req, res, next) => { + return Race.findByIdAndAddUser(req.params.id, req.user.id) + .then(race => res.json(race)) + .catch(next); }); module.exports = router; \ No newline at end of file diff --git a/lib/routes/users.js b/lib/routes/users.js index 0200e1f..e3e9534 100644 --- a/lib/routes/users.js +++ b/lib/routes/users.js @@ -13,7 +13,9 @@ module.exports = router if (!password) { throw { code: 401, error: 'password required' }; } - + // because you're not enforcing name uniqueness, + // once second user chooses same name, one of the two accounts + // will be forever broken :( const user = new User(req.body); user.bankroll = 50000; user.generateHash(password); @@ -40,81 +42,59 @@ module.exports = router .catch(next); }) - .put('/getchar/:id', validateAuth, (req, res, next) => { - let userId = null; - const token = req.get('Authorization'); - return tokenService.verify(token) - .then( payload => { - userId = payload.id; - return User.findById(userId).lean(); - }) - .then( found => { - if (found.character) throw {code: 400, error: 'you already have a character'}; - return User.findByIdAndUpdate(userId, { character: req.params.id }, {new: true}).select('name email character vehicle bankroll'); - }) - .then( updated => { - res.json(updated); - }) - .catch(next); - }) + // not sure why you are re-authenticating user when validateAuth + // has already done this work. The middleware puts the payload on req.user - .put('/clearchar/:id', validateAuth, (req, res, next) => { - let userId = null; - const token = req.get('Authorization'); - return tokenService.verify(token) - .then( payload => { - userId = payload.id; - return User.findByIdAndUpdate(userId, {character: null}, {new: true}); - }) - .then( updated => { - res.json(updated); - }) + // REST paths are resources, meaning nouns. + // "getchar" is neither a noun, nor does it match a PUT + // A user has a subresource of a character. + .put('/character/:id', validateAuth, (req, res, next) => { + // "PUT" means put this resource in this place. So doesn't make sense + // to throw an error if they already have a character, just replace + return User + .findByIdAndUpdate(req.user.id, { character: req.params.id }, { new: true }) + .select('name email character vehicle bankroll') + .then(updated => res.json(updated)) .catch(next); }) - .put('/getvehicle/:id', validateAuth, (req, res, next) => { - let userId = null; - let userBankroll = null; - let savedVehicle = null; - const token = req.get('Authorization'); - return tokenService.verify(token) - .then( payload => { - userId = payload.id; - return User.findById(userId).lean(); - }) - .then( found => { - userBankroll = found.bankroll; - return Vehicle.findById(req.params.id); - }) - .then( found => { - savedVehicle = found; - if(savedVehicle.cost_in_credits > userBankroll) throw {code: 400, error: 'insufficient funds'}; - userBankroll -= savedVehicle.cost_in_credits; - let updated = { - vehicle: savedVehicle.id, - bankroll: userBankroll - }; - return User.findByIdAndUpdate(userId, updated, {new: true}) - .select('name email character vehicle bankroll'); - }) - .then( updated => { - res.json(updated); - }) - .catch(next); - }) + // Doesn't make sense to clear a character, wouldn't you just replace? - .put('/joinRace/:id', validateAuth, (req, res, next) => { - let userId = null; - const token = req.get('Authorization'); - const id = req.params.id; - return tokenService.verify(token) - .then( payload => { - userId = payload.id; - return Race.findByIdAndUpdate(id, {$push: {users: userId}}, {new : true} ).lean(); + .put('/vehicle/:id', validateAuth, (req, res, next) => { + Promise.all([ + User.findById(req.user.id), + Vehicle.findById(req.params.id) + ]) + .then(([user, vehicle]) => { + // TODO: throw error if no vehicle + const cost = vehicle.cost_in_credits; + if(cost > user.bankroll) throw {code: 400, error: 'insufficient funds'}; + + user.bankroll -= cost; + user.vehicle = vehicle._id; + return user.save(); }) - .then( race => { - if(!race) next ({ code: 404, message: 'Incorrect id' }); - else res.json(race); + .then(({ _id, name, email, character, vehicle, bankroll }) => { + // bit of a hack, but avoids second trip to database + return { _id, name, email, character, vehicle, bankroll }; }) + .then(updated => res.json(updated)) .catch(next); - }); \ No newline at end of file + }); + +// this needs to live on race route, not user +// .put('/joinRace/:id', validateAuth, (req, res, next) => { +// let userId = null; +// const token = req.get('Authorization'); +// const id = req.params.id; +// return tokenService.verify(token) +// .then( payload => { +// userId = payload.id; +// return Race.findByIdAndUpdate(id, {$push: {users: userId}}, {new : true} ).lean(); +// }) +// .then( race => { +// if(!race) next ({ code: 404, message: 'Incorrect id' }); +// else res.json(race); +// }) +// .catch(next); +// }); \ No newline at end of file diff --git a/lib/routes/vehicles.js b/lib/routes/vehicles.js index d6848fb..cd2c022 100644 --- a/lib/routes/vehicles.js +++ b/lib/routes/vehicles.js @@ -5,7 +5,7 @@ const Vehicle = require('../models/vehicle'); router .get('/', validateAuth, (req, res, next) => { Vehicle.find().lean() - .then(found => res.json(found)) + .then(vehicles => res.json(vehicles)) .catch(next); }); diff --git a/lib/scripts/create-race.js b/lib/scripts/create-race.js index c66528d..b829dfe 100644 --- a/lib/scripts/create-race.js +++ b/lib/scripts/create-race.js @@ -2,33 +2,43 @@ const Race = require('../models/race'); const Planet = require('../models/planet'); const User = require('../models/user'); +// My making this explicit, next developer doesn't have to reverse engineer how it works +const DISTANCE_MULTIPLIER = 12; +const MIN = 100; +const MAX = 10000; +const getRandomDistance = () => { + return (Math.floor(Math.random() * (MAX - MIN + 1)) + MIN) * DISTANCE_MULTIPLIER; +}; + module.exports = function () { console.log('Creating new race...');// eslint-disable-line - let enemy = { + + // Why not pull from Character using $sample as well? + const enemy = { name: 'Your rival', email: 'finalboss@aol.com', bankroll: 0 }; - let date = new Date(); - date.setSeconds(date.getSeconds() + (process.env.CREATETIMER || 1000)); + + // these are parallel actions! + return Promise.all([ + new User(enemy).save(), + Planet.getRandomPlanetId() + ]) + .then(([enemy, planet]) => { + // move date to where it is used + let date = new Date(); + date.setSeconds(date.getSeconds() + (process.env.CREATETIMER || 1000)); - return new User(enemy).save() - .then((got) => { - enemy = got; - return Planet.aggregate([{ - $sample: { - size: 1 - } - }]); - }) - .then(myPlanet => { - const randomNumber = (Math.floor(Math.random() * (10000 - 100 + 1)) + 100) * 12; + // I made this a function to better explain what is going on here + const distance = getRandomDistance(); const newRace = { - planet: myPlanet[0]._id, + // handle pruning in actual find if possible + planet, endTime: date, active: true, - distance: randomNumber, - prize: randomNumber / 6, + distance, + prize: distance / 6, users: [enemy] }; return new Race(newRace).save(); diff --git a/lib/scripts/finish-races.js b/lib/scripts/finish-races.js index 800fe40..e5325d1 100644 --- a/lib/scripts/finish-races.js +++ b/lib/scripts/finish-races.js @@ -4,34 +4,40 @@ const User = require('../models/user'); module.exports = function () { console.log('Processing completed races...'); - return Race.find({active: true, endTime: {$gt: new Date()}}) - .then( found =>{ - Promise.all( - found.map(race => { - if(race.users.length < 2){ - console.log('Removing expired race, id =', race.id); - return Race.findByIdAndRemove(race.id) - .then( () => { - console.log('Removing user id =', race.users[0].toString()); - return User.findByIdAndRemove(race.users[0].toString()); - }); - } else { - const raceWinner = Math.floor(Math.random() * race.users.length); - const winnerId = race.users[raceWinner].toString(); - let winnerBankroll = null; - return User.findById(winnerId).select('bankroll') - .then( found => { - winnerBankroll = found.bankroll; - }) - .then( () => { - winnerBankroll += race.prize; - return User.findByIdAndUpdate(winnerId, {'bankroll': winnerBankroll }, {new: true}); - }) - .then( () => { - return Race.findByIdAndUpdate(race.id, {active: false, winner: winnerId}); - }); - } - }) - ); + // look at level of nesting, usually indicates you're not chaining promises correctly + + return Race.getExpiredRaces().then(races =>{ + // Two techniques that help here: + // Separate two primary conditions (delete vs run) using filter + // Use functions to name logic and break things up + return Promise.all([runValidRaces(races), cancelEmptyRaces(races)]); + }); +}; + +function runValidRaces(races) { + const runRaces = races + .filter(race => race.users.length > 1) + .map(race => { + // what about vehicle speed, etc., etc.??? + const raceWinner = Math.floor(Math.random() * race.users.length); + // You shouldn't need to use `toString`, but I'm not 100% sure + const winnerId = race.users[raceWinner]; + + // Parallel actions! + return Promise.all([ + // define model methods to keep this clean + User.findByIdAndWinPrize(winnerId, race.prize), + race.complete() + ]); }); -}; \ No newline at end of file + + return Promise.all(runRaces); +} + +function cancelEmptyRaces(races) { + return Promise.all( + races + .filter(race => race.users.length <= 1) + .map(race => race.cancel()) + ); +} \ No newline at end of file diff --git a/lib/scripts/seed-characters.js b/lib/scripts/seed-characters.js deleted file mode 100644 index 6ff26ec..0000000 --- a/lib/scripts/seed-characters.js +++ /dev/null @@ -1,35 +0,0 @@ -const superagent = require('superagent'); -const Character = require('../models/character'); - -module.exports = function () { - return Character.find().count() - .then(count => { - if (count === 0) { - return importCharacters(); - } - }); -}; - -function importCharacters() { - const catalogArr = Array(9).fill(); - - return Promise.all( - catalogArr.map((item, i) => { - const charactersUrl = `https://swapi.co/api/people/?page=${i + 1}`; - return superagent.get(charactersUrl) - .then(characterRes => characterRes.body.results); - }) - ) - .then(pages => { - return pages.reduce((acc, page) => { - return acc.concat(page); - }, []); - }) - .then(characters => { - return Promise.all( - characters.map((character) => { - return new Character(character).save(); - }) - ); - }); -} \ No newline at end of file diff --git a/lib/scripts/seed-data.js b/lib/scripts/seed-data.js new file mode 100644 index 0000000..2b70a2a --- /dev/null +++ b/lib/scripts/seed-data.js @@ -0,0 +1,52 @@ +const superagent = require('superagent'); +const Character = require('../models/character'); +const Planet = require('../models/planet'); +const Vehicle = require('../models/vehicle'); + +const characters = seed(Character, 'people', 9); +const planets = seed(Planet, 'planets', 7); +const vehicles = seed(Vehicle, 'vehicles', 4); + +// for testing, exporting these separately... +module.exports = { + characters, + planets, + vehicles, + data() { + return Promise.all( + characters(), + planets(), + vehicles() + ); + } +}; + +function seed(Model, resource, pages) { + + return () => { + Model.find().count() + .then(count => { + if (count === 0) { + return importData(); + } + }); + }; + + function importData() { + return Promise.all( + Array(pages).fill().map((item, i) => { + const url = `https://swapi.co/api/${resource}/?page=${i + 1}`; + return superagent.get(url) + .then(({ body }) => body.results); + }) + ) + .then((pages) => { + return pages.reduce((acc, page) => acc.concat(page), []); + }) + .then(results => { + return Promise.all ( + results.map(data => new Model(data).save()) + ); + }); + } +} diff --git a/lib/scripts/seed-planets.js b/lib/scripts/seed-planets.js deleted file mode 100644 index 61098a4..0000000 --- a/lib/scripts/seed-planets.js +++ /dev/null @@ -1,35 +0,0 @@ -const superagent = require('superagent'); -const Planet = require('../models/planet'); - -module.exports = function () { - return Planet.find().count() - .then(count => { - if (count === 0) { - return importPlanets(); - } - }); -}; - -function importPlanets() { - const catalogArr = Array(7).fill(); - - return Promise.all( - catalogArr.map((item, i) => { - const planetsUrl = `https://swapi.co/api/planets/?page=${i + 1}`; - return superagent.get(planetsUrl) - .then(planetRes => planetRes.body.results); - }) - ) - .then((pages) => { - return pages.reduce((acc, page) => { - return acc.concat(page); - }, []); - }) - .then(planets => { - return Promise.all ( - planets.map((planet) => { - return new Planet(planet).save(); - }) - ); - }); -} \ No newline at end of file diff --git a/lib/scripts/seed-vehicles.js b/lib/scripts/seed-vehicles.js deleted file mode 100644 index ce40d3e..0000000 --- a/lib/scripts/seed-vehicles.js +++ /dev/null @@ -1,36 +0,0 @@ -const superagent = require('superagent'); -const Vehicle = require('../models/vehicle'); - -module.exports = function () { - return Vehicle.find().count() - .then(count => { - if (count === 0) { - return importVehicles(); - } - }); -}; - -function importVehicles() { - const catalogArr = Array(4).fill(); - - return Promise.all( - catalogArr.map((item, i) => { - const vehiclesUrl = `https://swapi.co/api/vehicles/?page=${i+1}`; - return superagent.get(vehiclesUrl) - .then(vehicleRes => vehicleRes.body.results); - }) - ) - .then(pages => { - return pages.reduce((acc, page) => { - return acc.concat(page); - }, []); - }) - .then(vehicles => { - return Promise.all( - vehicles.map((vehicles) => { - if(vehicles.cost_in_credits === 'unknown') {vehicles.cost_in_credits = 22000;} - return new Vehicle(vehicles).save(); - }) - ); - }); -} \ No newline at end of file diff --git a/lib/utils/respond.js b/lib/utils/respond.js deleted file mode 100644 index 8d805bf..0000000 --- a/lib/utils/respond.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = function (handler) { - return (req, res, next) => { - return handler(req) - .then(result => res.json(result)) - .catch(next); - }; -}; \ No newline at end of file diff --git a/lib/utils/timer.js b/lib/utils/timer.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/utils/token.js b/lib/utils/token.js index ddb1d25..ca94347 100644 --- a/lib/utils/token.js +++ b/lib/utils/token.js @@ -4,10 +4,10 @@ const appSecret = process.env.APP_SECRET || 'temporary Secret'; module.exports = { - sign(reviewer) { + sign(user) { return new Promise( (resolve, reject) => { const payload = { - id: reviewer.id + id: user.id }; jwt.sign(payload, appSecret, (err, token) => { diff --git a/server.js b/server.js index 168433f..12f3220 100644 --- a/server.js +++ b/server.js @@ -5,20 +5,17 @@ const server = http.createServer(app); const connect = require('./lib/connect'); const raceScheduler = require('./lib/scripts/race-scheduler'); -const seedPlanets = require('./lib/scripts/seed-planets'); -const seedVehicles = require('./lib/scripts/seed-vehicles'); -const seedCharacters = require('./lib/scripts/seed-characters'); +// I combined these, see seed-data.js +const { seedData } = require('./lib/scripts/seed-data'); connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/starwars'); const port = process.env.PORT || 3000; -seedPlanets(); -seedVehicles(); -seedCharacters(); - -server.listen(port, () => { - console.log('server is running', server.address().port);//eslint-disable-line +// If the intent is to wait until seed data is created before starting server, you need to handle async: +seedData().then(() => { + server.listen(port, () => { + console.log('server is running', server.address().port);//eslint-disable-line + }); + raceScheduler(); }); - -raceScheduler(); \ No newline at end of file diff --git a/test/e2e/characters.test.js b/test/e2e/characters.test.js index 7e65cb1..c5dcfc2 100644 --- a/test/e2e/characters.test.js +++ b/test/e2e/characters.test.js @@ -1,36 +1,38 @@ const { assert } = require('chai'); const request = require('./request'); const db = require('./db'); -const seedCharacters = require('../../lib/scripts/seed-characters'); +const seed = require('../../lib/scripts/seed-data'); describe('Characters test', () => { - let newUser = null; - let userToken = null; - - beforeEach(function () { + // make the test suite work for you. + // before makes more sense here... + + before(db.drop); + + before(function () { this.timeout(10000); - db.drop(); - - newUser = { - name: 'xXcYbEr_GoKu_666Xx', - email: '10_yr_old_hacker@gmail.com', - password: '123hello' - }; - + return seed.characters(); + }); + + let userToken = null; + before(() => { return request .post('/api/users/signup') - .send(newUser) - .then( ({body}) => { + .send({ + name: 'xXcYbEr_GoKu_666Xx', + email: '10_yr_old_hacker@gmail.com', + password: '123hello' + }) + .then(({body}) => { userToken = body.token; - return seedCharacters(); }); }); it('should retrieve all characters from api when requested from authorized user', function() { - this.timeout(15000); + // now that these are stored in your db, don't need length timeout return request.get('/api/characters') .set('Authorization', userToken) - .then( ({body}) => { + .then(({body}) => { assert.equal(body.length, 87); }); }); diff --git a/test/e2e/planets.test.js b/test/e2e/planets.test.js index 051b73a..f3b6245 100644 --- a/test/e2e/planets.test.js +++ b/test/e2e/planets.test.js @@ -3,6 +3,8 @@ const request = require('./request'); const db = require('./db'); const planetSeed = require('../../lib/scripts/seed-planets'); +// see characters.test.js, same applies here... + describe('Planets test', () => { let userToken = null; let newUser = null; diff --git a/test/e2e/race-functions.test.js b/test/e2e/race-functions.test.js index e92ee99..d134364 100644 --- a/test/e2e/race-functions.test.js +++ b/test/e2e/race-functions.test.js @@ -1,6 +1,6 @@ const { assert } = require('chai'); const db = require('./db'); -const seedPlanets = require('../../lib/scripts/seed-planets'); +const seed = require('../../lib/scripts/seed-data'); const request = require('./request'); const createRace = require('../../lib/scripts/create-race'); const finishRaces = require('../../lib/scripts/finish-races'); @@ -16,7 +16,7 @@ describe('Race Functions test', () => { beforeEach( function () { this.timeout(10000); - return seedPlanets(); + return seed.planets(); }); it('should create a new race', () => { @@ -39,16 +39,19 @@ describe('Race Functions test', () => { }); it('should finish all completed races', () => { - return createExpiredRace() - .then( () => createExpiredRace()) - .then( () => createRace()) - .then( () => createRace()) - .then( () => createSingleUserRace()) - .then( () => finishRaces()) - .then( () => Race.find()) - .then( got => { - assert.isArray(got); - assert.isAtLeast(got.length, 2); + + return Promise.all([ + createExpiredRace(), + createExpiredRace(), + createRace(), + createRace(), + createSingleUserRace() + ]) + .then(() => finishRaces()) + .then(() => Race.find()) + .then(races => { + assert.isArray(races); + assert.isAtLeast(races.length, 2); }); }); }); \ No newline at end of file diff --git a/test/e2e/scripts/create-expired-race.js b/test/e2e/scripts/create-expired-race.js index e9834a9..32a9dca 100644 --- a/test/e2e/scripts/create-expired-race.js +++ b/test/e2e/scripts/create-expired-race.js @@ -2,6 +2,10 @@ const Race = require('../../../lib/models/race'); const Planet = require('../../../lib/models/planet'); const User = require('../../../lib/models/user'); +// You're doing too much here that is identical to code. +// Either 1) simply and just save some dummy data, +// 2) use the existing model functions, then modify the data you need. + module.exports = function () { let enemy = { name: 'Your rival', email: 'finalboss@aol.com', bankroll: 0 }; let hero = { name: 'gyro', email: 'goodboy111@aol.com', bankroll: 1000 }; diff --git a/test/e2e/scripts/create-single-user-race.js b/test/e2e/scripts/create-single-user-race.js index 68ca286..894dc3e 100644 --- a/test/e2e/scripts/create-single-user-race.js +++ b/test/e2e/scripts/create-single-user-race.js @@ -2,6 +2,8 @@ const Race = require('../../../lib/models/race'); const Planet = require('../../../lib/models/planet'); const User = require('../../../lib/models/user'); +// near identical to other create race test file. + module.exports = function () { let enemy = { name: 'Your rival', email: 'finalboss@aol.com', bankroll: 0 }; @@ -16,6 +18,7 @@ module.exports = function () { ]); }) .then( myPlanet => { + // Don't repeat your code logic in the test. This does not need to be random as a dummy race const randomNumber = (Math.floor(Math.random() * (10000 - 100 +1)) +100)*12; const newRace = { planet: myPlanet[0]._id, diff --git a/test/e2e/seed-characters.test.js b/test/e2e/seed-characters.test.js deleted file mode 100644 index 9899517..0000000 --- a/test/e2e/seed-characters.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const { assert } = require('chai'); -const seedCharacters = require('../../lib/scripts/seed-characters'); -const db = require('./db'); -const Character = require('../../lib/models/character'); - -describe('Seed Characters test', () => { - before(()=> { - db.drop(); - }); - - let characterCount = 0; - - it('should seed characters', function() { - this.timeout(15000); - return seedCharacters() - .then(() => { - return Character.find().count(); - }) - .then(count => { - characterCount = count; - assert.isOk(count > 0); - }); - }); - - it('should not seed characters if already exist', function() { - this.timeout(15000); - return seedCharacters() - .then(() => { - return Character.find().count(); - }) - .then(count => { - assert.equal(count, characterCount); - }); - }); -}); \ No newline at end of file diff --git a/test/e2e/seed-data.test.js b/test/e2e/seed-data.test.js new file mode 100644 index 0000000..98616f0 --- /dev/null +++ b/test/e2e/seed-data.test.js @@ -0,0 +1,47 @@ +const { assert } = require('chai'); +const seed = require('../../lib/scripts/seed-data'); +const db = require('./db'); +const Character = require('../../lib/models/character'); +const Planet = require('../../lib/models/planet'); +const Vehicle = require('../../lib/models/vehicle'); + +describe('Seed Data', () => { + before(()=> { + db.drop(); + }); + + testSeedData(Character, seed.characters); + testSeedData(Planet, seed.planets); + testSeedData(Vehicle, seed.vehicles); + + function testSeedData(Model, seedFn) { + describe(Model.modelName, () => { + + let seedCount = 0; + + it('should seed data', function() { + this.timeout(15000); + return seedFn() + .then(() => { + return Model.find().count(); + }) + .then(count => { + seedCount = count; + assert.isOk(count > 0); + }); + }); + + it('should not seed data if already exist', function() { + return seedFn() + .then(() => { + return Model.find().count(); + }) + .then(count => { + assert.equal(count, seedCount); + }); + }); + }); + + } + +}); \ No newline at end of file diff --git a/test/e2e/seed-planets.test.js b/test/e2e/seed-planets.test.js deleted file mode 100644 index 33de2f9..0000000 --- a/test/e2e/seed-planets.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const { assert } = require('chai'); -const seedPlanets = require('../../lib/scripts/seed-planets'); -const db = require('./db'); -const Planet = require('../../lib/models/planet'); - -describe('Seed Planets test', () => { - before(() => { - db.drop(); - }); - - let planetCount = 0; - - it('should seed planets', function() { - this.timeout(15000); - return seedPlanets() - .then(() => { - return Planet.find().count(); - }) - .then(count => { - planetCount = count; - assert.isOk(count > 0); - }); - }); - - it('should not seed planets if already exist', function () { - this.timeout(15000); - return seedPlanets() - .then(() => { - return Planet.find().count(); - }) - .then(count => { - assert.equal(count, planetCount); - }); - }); -}); \ No newline at end of file diff --git a/test/e2e/seed-vehicles.test.js b/test/e2e/seed-vehicles.test.js deleted file mode 100644 index a9aad0d..0000000 --- a/test/e2e/seed-vehicles.test.js +++ /dev/null @@ -1,35 +0,0 @@ -const {assert} = require('chai'); -const seedVehicles = require('../../lib/scripts/seed-vehicles'); -const db = require('./db'); -const Vehicle = require('../../lib/models/vehicle'); - -describe('Seed Vehicles test', () => { - before(() => { - db.drop(); - }); - - let vehicleCount = 0; - - it('should see vehicles', function () { - this.timeout(15000); - return seedVehicles() - .then(() => { - return Vehicle.find().count(); - }) - .then(count => { - vehicleCount = count; - assert.isOk(count > 0); - }); - }); - - it('should not seed vehicles if already exist', function() { - this.timeout(15000); - return seedVehicles() - .then(() => { - return Vehicle.find().count(); - }) - .then(count => { - assert.equal(count, vehicleCount); - }); - }); -}); \ No newline at end of file diff --git a/test/e2e/vehicles.test.js b/test/e2e/vehicles.test.js index 23bdd25..d0112e5 100644 --- a/test/e2e/vehicles.test.js +++ b/test/e2e/vehicles.test.js @@ -27,7 +27,6 @@ describe('Vehicles test', () => { }); it('should retrieve all vehicles from API', function() { - this.timeout(15000); return request .get('/api/vehicles/') .set('Authorization', userToken)