Last active
July 31, 2018 16:06
-
-
Save pyk/dd5b76e2c5fb53ebeae063841d9d6fbd to your computer and use it in GitHub Desktop.
app.js
This file contains hidden or 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
// Models is sequelize instance | |
app.use('/smartphones', smartphonesRouter(models)); |
This file contains hidden or 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
const http = require('http'); | |
const puppeteer = require('puppeteer'); | |
const models = require('../models'); | |
let server = null; | |
let browser = null; | |
beforeEach(async () => { | |
// eslint-disable-next-line | |
const app = require('../app')(models); | |
server = http.createServer(app); | |
await models.sequelize.sync(); | |
// Create new brand first | |
// brandId = models.Brand.create({name: 'Xiaomi'}).id; | |
await server.listen(0, 'localhost'); | |
browser = await puppeteer.launch(); | |
}); | |
afterEach(async () => { | |
// Close the server | |
await server.close(); | |
// Close the browser | |
await browser.close(); | |
}); | |
test( | |
'User access smartphone list', | |
async () => { | |
// Initialize browser and url | |
const page = await browser.newPage(); | |
const addr = server.address(); | |
const rootUrl = `http://${addr.address}:${addr.port}`; | |
const url = `${rootUrl}/smartphones`; | |
// User access /smartphones | |
await page.goto(url); | |
// It should display empty list | |
const emptySmartphones = await page.$('#emptySmartphones'); | |
expect(emptySmartphones).not.toBe(null); | |
const linkToNewSmartphone = await page.$('#linkToNewSmartphone'); | |
expect(linkToNewSmartphone).not.toBe(null); | |
const linkToHome = await page.$('#linkToHome'); | |
expect(linkToHome).not.toBe(null); | |
}, | |
100000 | |
); | |
test( | |
'User create unique smartphone', | |
async () => { | |
// Initialize browser and url | |
const page = await browser.newPage(); | |
const addr = server.address(); | |
const rootUrl = `http://${addr.address}:${addr.port}`; | |
const url = `${rootUrl}/smartphones/new`; | |
// Create new brand for this test | |
const brand = await models.Brand.create({ | |
name: 'Brand #1' | |
}); | |
// User access /smartphones/new | |
await page.goto(url); | |
// User filling the form | |
const inputSmartphoneName = await page.$('#inputSmartphoneName'); | |
await inputSmartphoneName.type('Redmi 2'); | |
await page.select('select#availableBrands', `${brand.id}`); | |
const buttonSave = await page.$('#buttonSave'); | |
await buttonSave.click(); | |
await page.waitForNavigation(); | |
// Make sure success message is displayed | |
const successMessage = await page.$('#successMessage'); | |
expect(successMessage).not.toBe(null); | |
// Make sure the brand list is displayed | |
const linkToSmartphoneIndex = await page.$('#linkToSmartphoneIndex'); | |
linkToSmartphoneIndex.click(); | |
await page.waitForNavigation(); | |
const emptySmartphones = await page.$('#emptySmartphones'); | |
const listOfSmartphones = await page.$('#listOfSmartphones'); | |
expect(emptySmartphones).toBe(null); | |
expect(listOfSmartphones).not.toBe(null); | |
}, | |
100000 | |
); | |
test( | |
'User create duplicate smartphone', | |
async () => { | |
// Initialize browser and url | |
let page = await browser.newPage(); | |
const addr = server.address(); | |
const rootUrl = `http://${addr.address}:${addr.port}`; | |
const url = `${rootUrl}/smartphones/new`; | |
// Create new brand for this test | |
const brand = await models.Brand.create({ | |
name: 'Brand #2' | |
}); | |
// User access /smartphones/new | |
await page.goto(url); | |
// User filling the form | |
let inputSmartphoneName = await page.$('#inputSmartphoneName'); | |
await inputSmartphoneName.type('Redmi 2'); | |
// Available brands should be displayed | |
// and select the brand | |
await page.select('select#availableBrands', `${brand.id}`); | |
let buttonSave = await page.$('#buttonSave'); | |
await buttonSave.click(); | |
// User reload the page | |
page = await browser.newPage(); | |
await page.goto(url); | |
// User fill the form again with the same data | |
inputSmartphoneName = await page.$('#inputSmartphoneName'); | |
await inputSmartphoneName.type('Redmi 2'); | |
// Available brands should be displayed | |
// and select the brand | |
await page.select('select#availableBrands', `${brand.id}`); | |
buttonSave = await page.$('#buttonSave'); | |
await buttonSave.click(); | |
await page.waitForNavigation(); | |
await page.screenshot({ path: 'debug.png' }); | |
// Make sure, error message are displayed | |
// await page.screenshot({path: 'debug.png'}) | |
const notUniqueMessage = await page.$('#notUniqueMessage'); | |
expect(notUniqueMessage).not.toBe(null); | |
}, | |
100000 | |
); |
This file contains hidden or 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
const express = require('express'); | |
/** | |
* Initialize a Smartphone router | |
* | |
* @param {Object} models - Model object from //models/index.js | |
*/ | |
module.exports = (models) => { | |
// Initialize new router | |
const router = express.Router(); | |
// Handle GET /smarphones | |
// eslint-disable-next-line | |
router.get('/', async (req, res, next) => { | |
// Get all smartphones from the database | |
const title = 'List of smartphones'; | |
const smartphones = await models.Smartphone.findAll(); | |
// Render the view | |
res.render('smartphones/index', { | |
title, | |
smartphones | |
}); | |
}); | |
// Handle GET /smartphones/new | |
// eslint-disable-next-line | |
router.get('/new', async (req, res, next) => { | |
// Get available brands from database | |
const title = 'Create new smartphone'; | |
const brands = await models.Brand.findAll(); | |
// Render the view | |
res.render('smartphones/new', { | |
title, | |
brands | |
}); | |
}); | |
// Handle POST /smartphones/new | |
// eslint-disable-next-line | |
router.post('/new', async (req, res, next) => { | |
// Start new transaction | |
const transaction = await models.sequelize.transaction(); | |
// Get all brands from the database | |
const brands = await models.Brand.findAll(); | |
try { | |
// Initialize model based on reqquest body object | |
const smartphone = await models.Smartphone.create(req.body, { | |
transaction | |
}); | |
await transaction.commit(); | |
// Render success message if everythins is OK | |
const message = `Smarphone ${smartphone.name} is created`; | |
res.render('smartphones/new', { | |
message, | |
brands, | |
isSuccess: true | |
}); | |
} catch (error) { | |
// Rollback transaction if shit happen | |
await transaction.rollback(); | |
if (error instanceof models.sequelize.UniqueConstraintError) { | |
// Notify that brand name is already exists | |
const message = `Smartphone ${req.body.name} is already exists`; | |
res.status(409).render('smartphones/new', { | |
message, | |
brands, | |
isNotUnique: true | |
}); | |
} else { | |
// Notify user that something bad happen on the server side | |
const message = '500 Internal server error'; | |
res.status(500).render('smartphones/new', { | |
message, | |
brands, | |
isServerEror: true | |
}); | |
} | |
} | |
}); | |
return router; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment