Sinon fake timer. Интеграционные тесты. Supertest. Тестирование в браузере
Жигалов Сергей
... Сделать из твитов бегущую строку. Для этого нужно выводить на консоль по одному символу раз в 100ms.
setTimeout
setTimeout(() => {
console.log('Прошла секунда');
}, 1000);
console.log
console.log('Несколько');
console.log('строк');
Несколько
строк
process.stdout.write
process.stdout.write('Одна');
process.stdout.write('строка');
Однастрока
// crawline.js
function crawline(text, cb) {
const letters = text.split('');
function print() {
if (!letters.length) return cb();
process.stdout.write(letters.shift());
setTimeout(print, 100);
}
print();
}
// tests/crawline-test.js
const crawline = require('../crawline');
describe('Crawline', () => {
it('shoult ptint text', done => {
crawline('I don’t always bend time and ' +
'space in unit tests, but when I do, ' +
'I use Buster.JS + Sinon.JS', done);
});
});
npm test
npm test -- --timeout=30000
beforeEach(() => clock = sinon.useFakeTimers());
afterEach(() => {
clock.restore();
process.stdout.write.restore();
});
it('shoult ptint text', done => {
const write = sinon.spy(process.stdout, 'write');
crawline('I don’t always bend time and ' +
'space in unit tests, but when I do, ' +
'I use Buster.JS + Sinon.JS', () => {
assert.equal(write.callCount, 91);
done();
});
clock.tick(10000);
});
Crawline
I don’t always bend time and space in unit tests,
but when I do, I use Buster.JS + Sinon.JS
✓ shoult ptint text
1 passing (32ms)
// tests/formatDate-test.js
const sinon = require('sinon');
describe('Format date', () => {
let clock;
before(function () {
const startDate = new Date(2017, 3, 25).getTime();
clock = sinon.useFakeTimers(startDate);
});
after(() => clock.restore());
/* ... */
});
it('should return only time', function () {
var actual = formatDate(new Date(2017, 3, 25, 6, 17, 6));
expect(actual).to.equal('06:17');
});
it('should return `вчера` with time', function () {
var actual = formatDate(new Date(2017, 3, 24, 8, 17, 6));
expect(actual).to.equal('вчера в 08:17');
});
тестирование группы взаимодействующих модулей.
// poker.js
const playPoker = require('./playPoker');
function poker(firstDice, secondDice) {
try {
const result = playPoker(firstDice, secondDice);
console.log(result);
} catch(error) {
console.error(error.message);
}
}
// tests/poker-test.js
it('should print success result', () => {
const log = sinon.stub(console, 'log');
const error = sinon.stub(console, 'error');
const playPoker = sinon.stub();
playPoker.withArgs([1, 2, 3, 4, 5], [1, 2, 3, 4, 6]).returns('Ничья');
const poker = proxyquire('../poker', { './playPoker': playPoker });
poker([1, 2, 3, 4, 5], [1, 2, 3, 4, 6]);
assert(log.calledOnce);
assert(log.calledWith('Ничья'));
assert(!error.called);
});
function weather(cb) {
request(url, (requestError, res, body) => {
if (requestError || res.statusCode !== 200) {
return cb('Request error');
}
try {
const data = JSON.parse(body);
cb(null, data.fact.temp);
} catch (parseError) {
cb(parseError.message);
}
});
}
// tests/weather-test.js
it('should print temperature', done => {
nock('https://api.weather.yandex.ru')
.get('/v1/forecast')
.reply(200, '{"fact":{"temp":25}}');
weather((error, actual) => {
assert.equal(actual, 25);
done(error);
});
});
// tests/weather-test.js
it('should print temperature', done => {
weather((error, actual) => {
assert(Number.isInteger(actual));
done(error);
});
});
Написать универсальный конвертер величин.
npm install convert-units --save
const convert = require('convert-units')
convert(1.5)
.from('week')
.to('min'); // 15120
express
npm install express --save
const express = require('express');
const app = express();
app.get('/convert', function (req, res) {
res.json({ result: 1 });
});
app.listen(3000);
const express = require('express');
const convert = require('convert-units')
const app = express();
app.get('/convert', (req, res) => {
const result = convert(req.query.value)
.from(req.query.from)
.to(req.query.to);
res.json({ result });
});
app.listen(3000);
supertest
npm install supertest --save-dev
const express = require('express');
const convert = require('convert-units')
const app = express();
app.get('/convert', (req, res) => {
const result = convert(req.query.value)
.from(req.query.from)
.to(req.query.to);
res.json({ result });
});
app.listen(3000);
// app.js
const express = require('express');
const convert = require('convert-units')
const app = express();
app.get('/convert', (req, res) => {
const result = convert(req.query.value)
.from(req.query.from)
.to(req.query.to);
res.json({ result });
});
module.exports = app;
// index.js
require('./app').listen(3000);
// tests/convertor-test.js
const request = require('supertest');
const app = require('../app');
describe('Convertor controller', () => {
it('should return result', () => {
/* ... */
});
});
it('should return result', () => {
return request(app)
.get('/convert')
.query({ value: 1.5, from: 'week', to: 'min' })
.expect(200)
.expect('Content-Type', /json/)
.expect({ result: 15120 });
});
Реализовать веб-версию универсального конвертера величин.
// app.js
const express = require('express');
const convert = require('convert-units');
const app = express();
app.use(express.static('public'));
app.get('/convert', (req, res) => {
const result = convert(req.query.value)
.from(req.query.from)
.to(req.query.to);
res.json({ result });
});
app.listen(3000);
<head>
<!-- подключаем стили, чтобы тесты вяглядели красиво -->
<link href="path/to/mocha.css" rel="stylesheet" />
</head>
<body>
<!-- относительно этого элемента
выводится тестовый отчет -->
<div id="mocha"></div>
<!-- конфигурируем и запускаем тесты -->
<script src="path/to/mocha.js"></script>
<script>mocha.setup('bdd')</script>
<script src="../tests/convertor-test.js"></script>
<script>mocha.run();</script>
</body>
"./node_modules/mocha/mocha.css"
"./node_modules/mocha/mocha.js"
"https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css"
"https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"
<script src="http://chaijs.com/chai.js"></script>
<script>
chai.assert.equal(1 + 1, 2);
</script>
chai.expect(1 + 1).to.equal(2);
chai.expect(Boolean(1)).to.be.true;
chai.should();
[1, 2, 3].should.deep.equal([1, 2, 3]);
[1, 2, 3].should.have.length(3);
[1, 2, 3].should.be.an('array');
describe('Convertor controls', () => {
it('should enable `convert` button for correct value', () => {
const send = document.getElementById('send');
chai.assert.equal(send.getAttribute('disabled'), null);
});
});
describe('Convertor controls', () => {
it('should disable `convert` button for invalid value', () => {
const from = document.getElementById('from');
const send = document.getElementById('send');
from.value = 'invalid value';
from.dispatchEvent(new Event('input'));
chai.assert.equal(send.getAttribute('disabled'), 'disabled');
});
});
phantomjs
PhantomJS is a headless WebKit scriptable with a JavaScript API.
mocha-phantomjs
npm install mocha-phantomjs --save-dev
node_modules/.bin/mocha-phantomjs
-p node_modules/.bin/phantomjs
https://urfu-2016-convertor.herokuapp.com/convert-test.html
Convertor controls
✓ should enable `convert` button for correct value
✓ should disable `convert` button for invalid value
2 passing (8ms)
Spectacular Test Runner for JavaScript
npm install karma --save-dev
npm install karma-mocha karma-chai --save-dev
npm install karma-chrome-launcher --save-dev
node_modules/.bin/karma init karma.config.js
// convertor.js
const value = document.getElementById('value');
const from = document.getElementById('from');
const to = document.getElementById('to');
const send = document.getElementById('send');
const result = document.getElementById('result');
function isValid() { /* ... */ }
function change() { /* ... */ }
function convert() { /* ... */ }
describe('Convertor', function () {
beforeEach(function() {
var fixture = `
from
to
`;
document.body.insertAdjacentHTML('afterbegin', fixture);
});
});
it('should enable `convert` button for correct value', function() {
const send = document.getElementById('send');
chai.assert.equal(send.getAttribute('disabled'), null);
});
it('should disable `convert` button for invalid value', function() {
const from = document.getElementById('from');
const send = document.getElementById('send');
from.value = 'invalid unit';
from.dispatchEvent(new Event('input'));
chai.assert.equal(send.getAttribute('disabled'), 'disabled');
});