{"id":162555,"date":"2012-12-17T14:37:03","date_gmt":"2012-12-17T10:37:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=162555"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=162555","title":{"rendered":"<span class=\"post_title\">\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 nodejs<\/span>"},"content":{"rendered":"<div class=\"content html_format\">   \t\u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/161943\/\">\u0440\u0430\u0437<\/a> \u044f \u043f\u0438\u0441\u0430\u043b \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 nodejs \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c expressjs \u043a\u0430\u043a \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438 jade \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430. \u0412 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u044f \u0445\u043e\u0447\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f:<br \/>   \u2014 <a href=\"http:\/\/visionmedia.github.com\/mocha\/\">Mocha<\/a> \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043b\u0435\u0433\u043a\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e. \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u0447\u0435\u0442\u044b \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u0445, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0443\u043c\u0435\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432.<br \/>   \u2014 <a href=\"https:\/\/github.com\/visionmedia\/should.js\/\">Should<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0441\u0442\u0438\u043b\u0435 \u00ab\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f\u00bb <sub>(\u041d\u0435 \u043d\u0430\u0448\u0435\u043b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f)<\/sub><br \/>   \u2014 <a href=\"https:\/\/github.com\/visionmedia\/supertest\">SuperTest<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f HTTP \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 nodejs<br \/>   \u2014 <a href=\"http:\/\/siliconforks.com\/jscoverage\/\">jscoverage<\/a> \u2014 \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/p>\n<p>  <a name=\"habracut\"><\/a><\/p>\n<p>  \u042f \u043d\u0435 \u0441\u0442\u0430\u043b \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u0441 \u043d\u0443\u043b\u044f, \u0430 \u0440\u0435\u0448\u0438\u043b \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u044b <a href=\"https:\/\/github.com\/zxcabs\/4fun\/tree\/master\/express\/app1\">\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/a> \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0432 \u0435\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0443 app2.<\/p>\n<p>  \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u043c \u043c\u043e\u0434\u0443\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b package.json. \u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f: mocha, should, supertest.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">package.json<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">{ \t&quot;name&quot;: &quot;app2&quot;, \t&quot;version&quot;: &quot;0.0.0&quot;, \t&quot;author&quot;: &quot;Evgeny Reznichenko &lt;kusakyky@gmaill.com&gt;&quot;, \t&quot;dependencies&quot;: { \t\t&quot;express&quot;: &quot;3&quot;, \t\t&quot;jade&quot;: &quot;*&quot;, \t\t&quot;should&quot;: &quot;*&quot;, \t\t&quot;mocha&quot;: &quot;*&quot;, \t\t&quot;supertest&quot;: &quot;*&quot; \t}  }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <b>npm i<\/b>, \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439.<br \/>  \u0418 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c jscoverage (\u043f\u043e\u0434 Ubuntu <b>sudo apt-get install jscoverage<\/b>).<\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e lib \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0442\u0443\u0434\u0430 \u043d\u0430\u0448 app.js, \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0447\u0442\u043e \u0431\u044b \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435.<br \/>  \u041e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b app.js, \u0447\u0442\u043e \u0431\u044b \u043e\u043d \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u0440\u0443\u0436\u0443, \u0430 \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b index.js \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0432\u0435\u0448\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u0441\u043e\u043a\u0435\u0442. \u0418 \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0442\u0438 \u043a views \u0438 public \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u043c.<br \/>  \u0414\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u0430\u043a:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var app = require('.\/lib\/app.js'); app.listen(3000); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">lib\/app.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var express = require('express'), \tjade = require('jade'), \tfs = require('fs'), \tapp = express(), \tviewOptions = { compileDebug: false, self: true };  \/\/data var db = { \t\tusers: [  \t\t\t{ id: 0, name: 'Jo', age: 20, sex: 'm' }, \t\t\t{ id: 1, name: 'Bo', age: 19, sex: 'm' }, \t\t\t{ id: 2, name: 'Le', age: 18, sex: 'w' }, \t\t\t{ id: 10, name: 'NotFound', age: 18, sex: 'w' } \t\t], \t\ttitles: { \t\t\t'\/users': '\u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439', \t\t\t'\/users\/profile': '\u041f\u0440\u043e\u0444\u0438\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f' \t\t} \t};  \/\/utils function merge(a, b) { \tvar key; \t \tif (a && b) { \t\tfor (key in b) { \t\t\ta[key] = b[key]; \t\t} \t} \t \treturn a; } \t \/\/App settings\t app.set('views', __dirname + '\/..\/views'); app.set('view engine', 'jade'); app.set('title', '\u041c\u043e\u0439 \u0441\u0430\u0439\u0442'); app.locals.compileDebug = viewOptions.compileDebug; app.locals.self = viewOptions.self; app.use(express.static(__dirname + '\/..\/public')); app.use(app.router); app.use(function (req, res, next) { \tnext('not found'); });  \/\/error app.use(function (err, req, res, next) { \tif (\/not found\/i.test(err)) { \t\tres.locals.title = '\u041d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e :('; \t\tres.render('\/errors\/notfound'); \t} else { \t\tres.locals.title = '\u041e\u0448\u0438\u0431\u043a\u0430'; \t\tres.render('\/errors\/error'); \t} }); app.use(express.errorHandler());   \/\/routes  \/\/\u0417\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440 app.all('*', function replaceRender(req, res, next) { \tvar render = res.render, \t\tview = req.path.length &gt; 1 ? req.path.substr(1).split('\/'): []; \t\t \tres.render = function(v, o) { \t\tvar data, \t\t\ttitle = res.locals.title; \t\t \t\tres.render = render; \t\tres.locals.title = app.get('title') + (title ? ' - ' + title: ''); \t\t\/\/\u0442\u0443\u0442 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0447\u0435\u0441\u0442\u044c \u0447\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0434\u0442\u0438 \t\t\/\/\u0438\u043c\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430\t\t\t\t\t \t\tif ('string' === typeof v) { \t\t\tif (\/^\\\/.+\/.test(v)) { \t\t\t\tview = v.substr(1).split('\/'); \t\t\t} else { \t\t\t\tview = view.concat(v.split('\/')); \t\t\t} \t\t\t \t\t\tdata = o; \t\t} else { \t\t\tdata = v; \t\t}  \t\t\/\/\u0432 res.locals \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0440\u0438\u043d\u0433\u0430 \t\t\/\/\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (res.locals.title) \t\tdata = merge(data || {}, res.locals); \t\t \t\tif (req.xhr) { \t\t\t\/\/\u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0430\u044f\u043a\u0441 \u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c json \t\t\tres.json({ data: data, view: view.join('.') }); \t\t} else { \t\t\t\/\/\u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0430\u044f\u043a\u0441, \u0442\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435  \t\t\t\/\/\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 history api) \t\t\tdata.state = JSON.stringify({ data: data, view: view.join('.') });             \/\/\u0418 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u043a \u0448\u0430\u0431\u043b\u043e\u043d\u0443. \u0414\u0430\u043b\u0435\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043e\u043d \u043d\u0443\u0436\u0435\u043d. \t\t\tview[view.length - 1] = '_' + view[view.length - 1]; \t\t\t\/\/\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0430\u043c \u0440\u0435\u043d\u0434\u0435\u0440 \t\t\tres.render(view.join('\/'), data); \t\t} \t}; \t \tnext(); });   \/\/\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0438 app.all('*', function loadPageTitle(req, res, next) { \tres.locals.title = db.titles[req.path]; \tnext(); });  app.get('\/', function(req, res){ \tres.render('index'); });  app.get('\/users', function(req, res){ \tvar data = { users: db.users }; \tres.render('index', data); });  app.get('\/users\/profile', function(req, res, next){ \tvar user = db.users[req.query.id], \t\tdata = { user: user }; \t \tif (user) { \t\tres.render(data); \t} else { \t\tnext('Not found'); \t} });   \/\/ function loadTemplate(viewpath) { \tvar fpath = app.get('views') + viewpath, \t\tstr = fs.readFileSync(fpath, 'utf8'); \t \tviewOptions.filename = fpath; \tviewOptions.client = true; \t \treturn jade.compile(str, viewOptions).toString();\t }  app.get('\/templates', function(req, res) { \t \tvar str = 'var views = { ' \t\t\t+\t'&quot;index&quot;: (function(){ return ' + loadTemplate('\/index.jade')  + ' }()),' \t\t\t+\t'&quot;users.index&quot;: (function(){ return ' + loadTemplate('\/users\/index.jade')  + ' }()),' \t\t\t+\t'&quot;users.profile&quot;: (function(){ return ' + loadTemplate('\/users\/profile.jade')  + ' }()),' \t\t\t+\t'&quot;errors.error&quot;: (function(){ return ' + loadTemplate('\/errors\/error.jade')  + ' }()),' \t\t\t+\t'&quot;errors.notfound&quot;: (function(){ return ' + loadTemplate('\/errors\/notfound.jade')  + ' }())' \t\t\t+ '};'  \tres.set({ 'Content-type': 'text\/javascript' }).send(str); });  module.exports = app; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u0444\u0430\u0439\u043b app.js, \u044f\u0432\u043d\u043e \u043d\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0442\u0440\u0438 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0447\u0430\u0441\u0442\u0438:<br \/>   \u2014 \u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u0438 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445<br \/>   \u2014 \u0412\u043e \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0441\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0443\u0442\u0438\u043b\u0438\u0442\u044b, \u0441\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <b>merge<\/b><br \/>   \u2014 \u0412 \u0442\u0440\u0435\u0442\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0430\u043c \u0441\u0435\u0440\u0432\u0435\u0440<\/p>\n<p>  \u0421 \u0436\u0435\u043b\u0430\u043d\u0438\u044f\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c, \u043d\u0430\u0447\u043d\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c Makefile \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Makefile<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">MOCHA = .\/node_modules\/.bin\/mocha  test: \t@NODE_ENV=test $(MOCHA) \\ \t\t-r should \\ \t\t-R spec  .PHONY: test <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>   \u2014 -r \u2014 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0447\u0442\u043e Mocha \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 should<br \/>   \u2014 -R \u2014 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432 \u043a\u0430\u043a\u043e\u043c \u0432\u0438\u0434\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u0438\u0434\u0435\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0430\u043c \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u043e\u0432 \u043e\u0442\u0447\u0435\u0442\u043e\u0432, \u044d\u0442\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"http:\/\/habrastorage.org\/storage2\/30d\/353\/641\/30d35364193c74fb5d0e2587d26676e5.jpg\"\/>  <\/div>\n<\/div>\n<h5>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u00ab\u0442\u0443\u043b\u0437\u044b\u00bb<\/h5>\n<p>  \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e Mocha \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u044b \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 test, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0430\u043a\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442.<br \/>  \u0410 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u043d\u0430\u0448\u0438 \u00ab\u0442\u0443\u043b\u0437\u043e\u0432\u00bb, \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u043b\u0430\u043d.<br \/>   \u2014 \u0412 \u00ab\u0442\u0443\u043b\u0437\u0430\u0445\u00bb \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f merge<br \/>   \u2014 \u0424\u0443\u043d\u043a\u0446\u0438\u044f merge \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043b\u0438\u0432\u0430\u0442\u044c \u0434\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043e\u0434\u0438\u043d<br \/>   \u2014 \u041f\u0440\u0438\u0447\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c\u0441\u044f, \u0432\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c<br \/>   \u2014 \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442<\/p>\n<p>  BDD \u0442\u0435\u0441\u0442\u044b \u0432 Mocha \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441 \u0431\u043b\u043e\u043a\u0430 <b>describe();<\/b>, \u0441\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0430\u0445 <b>it();<\/b> \u043e\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0431\u043b\u043e\u043a\u0430 describe(). \u0414\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043b\u044e\u0431\u0430\u044f \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0431\u043b\u043e\u043a\u043e\u0432 describe() \u0434\u0440\u0443\u0433 \u0432 \u0434\u0440\u0443\u0433\u0430. \u0422\u0430\u043a \u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0445\u0443\u043a\u0438: before(), after(), beforeEach(), \u0438 afterEach(). \u0425\u0443\u043a\u0438 \u0442\u0430\u043a \u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u0431\u043b\u043e\u043a\u0430 describe(). \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0445\u0443\u043a\u0430\u0445 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0435\u0439\u043a\u043e\u0432\u043e\u0439 \u0411\u0414.<\/p>\n<p>  \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 test \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b tools.js \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442 \u0434\u043b\u044f tools.merge.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">test\/tools.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var tools = require('..\/lib\/tools\/index.js');  describe('tools', function () { \t \t\/\/\u0412 &quot;\u0442\u0443\u043b\u0437\u0430\u0445&quot; \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f merge \tit('should be have #merge', function () { \t\ttools.should.be.have.property('merge'); \t\ttools.merge.should.be.a('function'); \t}); \t \tdescribe('#merge', function () { \t\t\/\/\u0424\u0443\u043d\u043a\u0446\u0438\u044f merge \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043b\u0438\u0432\u0430\u0442\u044c \u0434\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043e\u0434\u0438\u043d \t\tit('should merged', function () { \t\t\tvar a = { foo: '1' }, \t\t\t\tb = { bar: '2' }; \t\t\t\t \t\t\ttools.merge(a, b).should.eql({ foo: '1', bar: '2' }); \t\t}); \t\t \t\t\/\/\u041f\u0440\u0438\u0447\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c\u0441\u044f, \u0432\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \t\tit('should be extend', function () { \t\t\tvar a = { foo: '1' }, \t\t\t\tb = { bar: '2' }; \t\t\t\t \t\t\ttools.merge(a, b); \t\t\t\/\/\u0441\u0442\u0440\u043e\u0433\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435, \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f \u0447\u0442\u043e \u044d\u0442\u043e  \t\t\t\/\/\u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \t\t\ta.should.not.equal({ foo: '1', bar: '2' }); \t\t\ta.should.equal(a); \t\t}); \t\t \t\t\/\/\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \t\tit('should not be extended', function () { \t\t\tvar a = { foo: '1' }, \t\t\t\tb = { bar: '2' }; \t\t\t\t \t\t\ttools.merge(a, b); \t\t\tb.should.not.eql({ foo: '1', bar: '2' }); \t\t}); \t}); }); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0415\u0441\u043b\u0438 \u043c\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0435\u0441\u0442, \u0442\u043e \u0441\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0435\u0449\u0435 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f tools, \u0447\u0442\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0443 \u043d\u0430\u0441 \u0435\u0449\u0435 \u043d\u0435\u0442 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b lib\/tools\/index.js \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u0442\u0443\u0434\u0430 \u043a\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <b>merge<\/b> \u0438\u0437 lib\/app.js. <br \/>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0435\u0441\u0442 <b>make test<\/b> \u0438 \u0443\u0432\u0438\u0434\u0438\u043c \u0447\u0442\u043e \u0432\u0441\u0435 \u0447\u0435\u0442\u044b\u0440\u0435 \u0442\u0435\u0441\u0442\u0430 \u0437\u0430\u0432\u0430\u043b\u0435\u043d\u044b,  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"http:\/\/habrastorage.org\/storage2\/ff9\/54d\/3f5\/ff954d3f5abe0cbf5bcd0fadcf7f5e37.jpg\"\/>  <\/div>\n<\/div>\n<p>   \u0442.\u043a. \u0437\u0430\u0432\u0430\u043b\u0435\u043d \u0441\u0430\u043c\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0442\u043e \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f tools \u043d\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f merge. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c\u0443 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0435. <br \/>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a jscoverage \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 <b>&#8212;encoding=utf8<\/b> \u0438 <b>&#8212;no-highlight<\/b> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c <b>lib<\/b>, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0443\u043a\u0430\u0436\u0435\u043c <b>lib-cov<\/b>. \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a Mocha \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <b>COVERAGE=1<\/b> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u043f\u043e\u0440\u0442\u0435\u0440\u0430 \u0443\u043a\u0430\u0436\u0435\u043c <b>html-cov<\/b>, \u0447\u0442\u043e \u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u0443\u044e html \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Makefile<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">MOCHA = .\/node_modules\/.bin\/mocha  test: \t@NODE_ENV=test $(MOCHA) \\ \t\t-r should \\ \t\t-R spec   test-cov: lib-cov \t@COVERAGE=1 $(MOCHA) \\ \t\t-r should \\ \t\t-R html-cov &gt; coverage.html  lib-cov: clear \t@jscoverage --encoding=utf8 --no-highlight lib lib-cov  clear: \t@rm -rf lib-cov coverage.html \t .PHONY: test test-cov clear <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0442\u0435\u0441\u0442\u0443 \u0438 \u0432 \u0441\u0430\u043c\u043e\u043c\u0443 \u0432\u0435\u0440\u0445\u0443 \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u0441\u0442\u0440\u043e\u0447\u043a\u0443:  <\/p>\n<pre><code class=\"javascript\">var tools = require('..\/lib\/tools\/index.js'); <\/code><\/pre>\n<p>  \u043d\u0430  <\/p>\n<pre><code class=\"javascript\">var tools = process.env.COVERAGE \t\t\t? require('..\/lib-cov\/tools\/index.js') \t\t\t: require('..\/lib\/tools\/index.js'); <\/code><\/pre>\n<p>  \u0412\u0441\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <b>make test-cov<\/b>. \u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b coverage.html, \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f, \u0444\u0430\u0439\u043b \u0441\u0430\u043c\u043e\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u0435\u043d \u0438 \u043c\u043e\u0436\u0435\u0442 \u0442\u0443\u0442 \u0436\u0435 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"http:\/\/habrastorage.org\/storage2\/763\/3a7\/345\/7633a7345f6b1bd4f1a498044fc31d87.jpg\"\/>  <\/div>\n<\/div>\n<p>  \u041a\u0440\u0430\u0441\u043d\u044b\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u0441\u0442\u0440\u043e\u0447\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0438 \u0435\u0434\u0438\u043d\u043e\u0433\u043e \u0437\u0430\u0445\u043e\u0434\u0430, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u0447\u0442\u043e \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u043e \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u0422\u0430\u043a \u0436\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043e\u0431\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u0430\u0445 \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443.<\/p>\n<p>  \u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0441\u0440\u0435\u0434\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u0411\u0414 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<h5>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0431\u0430\u0437\u043e\u0439<\/h5>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c.<br \/>  1) \u0423 \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0434\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 User \u0438 UserList<br \/>  2) \u041c\u043e\u0434\u0435\u043b\u044c User \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b:<br \/>   \u2014 find \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0442\u0438\u043f\u0430 UserList, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442 <br \/>   \u2014 findById \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u0441\u043a\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0418\u0434 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0442\u0438\u043f\u0430 User, \u043b\u0438\u0431\u043e \u043d\u0438\u0447\u0435\u0433\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u0442\u0430\u043a\u0438\u043c \u0438\u0434 \u043d\u0435\u0442<br \/>   \u2014 save \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 err \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438<br \/>   \u2014 toJSON \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0442\u0438\u043f\u0430 User \u043a json<br \/>  3) \u041c\u043e\u0434\u0435\u043b\u044c UserList \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434 toJSON  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 \u0442\u0435\u0441\u0442\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var should = require('should'), \tdb = process.env.COVERAGE \t\t\t? require('..\/lib-cov\/models\/db.js') \t\t\t: require('..\/lib\/models\/db.js'), \tmodels = process.env.COVERAGE \t\t\t? require('..\/lib-cov\/models\/index.js') \t\t\t: require('..\/lib\/models\/index.js'), \tUser = models.User, \tUserList = models.UserList; \t describe('models', function () {  \t\/\/\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u0430 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \t\/\/\u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 &quot;describe('models')&quot; \tbefore(function () { \t\tdb.regen(); \t});  \t\/\/\u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c User \tit('should be have User', function () { \t\tmodels.should.be.have.property('User'); \t\tmodels.User.should.be.a('function'); \t}); \t \t\/\/\u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c UserList \tit('should be have UserList', function () { \t\tmodels.should.be.have.property('UserList'); \t\tmodels.UserList.should.be.a('function'); \t}); \t \t\/\/\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c User \tdescribe('User', function () { \t\t \t\t\/\/\u043c\u043e\u0434\u0435\u043b\u044c User \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 find \t\tit('should be have #find', function () { \t\t\tUser.should.be.have.property('find'); \t\t\tUser.find.should.be.a('function'); \t\t}); \t\t \t\t\/\/\u043c\u043e\u0434\u0435\u043b\u044c User \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 findById \t\tit('should be have #findById', function () { \t\t\tUser.should.be.have.property('findById'); \t\t\tUser.findById.should.be.a('function'); \t\t}); \t\t \t\t\/\/\u043c\u043e\u0434\u0435\u043b\u044c User \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 save \t\tit('should be have #save', function () { \t\t\tUser.prototype.should.be.have.property('save'); \t\t\tUser.prototype.save.should.be.a('function'); \t\t}); \t\t \t\t\/\/\u043c\u043e\u0434\u0435\u043b\u044c User \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 toJSON \t\tit('should be have #toJSON', function () { \t\t\tUser.prototype.should.be.have.property('toJSON'); \t\t\tUser.prototype.toJSON.should.be.a('function'); \t\t}); \t\t \t\tdescribe('#find', function () { \t\t\t \t\t\t\/\/find \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c UserList \t\t\tit('should be instanceof UserList', function (done) { \t\t\t\tUser.find(function (err, list) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\tlist.should.be.an.instanceOf(UserList); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); \t\t\t \t\t\t\/\/find \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c UserList, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442 \t\t\tit('should not be exist', function (done) { \t\t\t\t\/\/\u0414\u0440\u043e\u043f\u0430\u0435\u043c \u0411\u0414 \t\t\t\tdb.drop(); \t\t\t\t \t\t\t\tUser.find(function (err, list) { \t\t\t\t\t\/\/\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0411\u0414 \t\t\t\t\tdb.generate(); \t\t\t\t\tif (err) return done(err); \t\t\t\t\tlist.should.be.an.instanceOf(UserList); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); \t\t}); \t\t \t\tdescribe('#findById', function () { \t\t\t \t\t\t\/\/findById \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0442\u0438\u043f\u0430 User \t\t\tit('should be instanceof User', function (done) { \t\t\t\tUser.findById(0, function (err, user) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\tuser.should.be.an.instanceOf(User); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); \t\t\t \t\t\t\/\/findById \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e \t\t\tit('should not be exists', function (done) { \t\t\t\tUser.findById(100, function (err, user) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\tshould.not.exist(user); \t\t\t\t\tdone(); \t\t\t\t});\t\t\t\t \t\t\t}); \t\t}); \t\t \t\tdescribe('#save', function () { \t\t \t\t\t\/\/save \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443, \u0435\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \t\t\tit('should not be saved', function (done) { \t\t\t\tvar user = new User({ name: 'New user', age: 0, sex: 'w' }); \t\t\t\t \t\t\t\tuser.save(function (err) { \t\t\t\t\terr.should.eql('Invalid age'); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); \t\t\t \t\t\t\/\/\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0445\u043e\u0440\u043e\u0448\u043e, \u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d \u043d\u043e\u0432\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \t\t\tit('should be saved', function (done) { \t\t\t\tvar newuser = new User({ name: 'New user', age: 2, sex: 'w' }); \t\t\t\t \t\t\t\tnewuser.save(function (err) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\t \t\t\t\t\tUser.findById(newuser.id, function (err, user) { \t\t\t\t\t\tif (err) return done(err); \t\t\t\t\t\tuser.should.eql(newuser); \t\t\t\t\t\tdone(); \t\t\t\t\t}); \t\t\t\t}); \t\t\t}); \t\t}); \t\t \t\tdescribe('#toJSON', function () { \t\t \t\t\t\/\/toJSON \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c json \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \t\t\tit('should be return json', function (done) { \t\t\t\tUser.findById(0, function (err, user) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\tuser.toJSON().should.be.eql({ id: 0, name: 'Jo', age: 20, sex: 'm' }); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); \t\t}); \t}); \t \tdescribe('UserList', function () { \t \t\t\/\/UserList \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043c\u0435\u0442\u043e\u0434 toJSON \t\tit('should be have #toJSON', function () { \t\t\tUserList.prototype.should.be.have.property('toJSON'); \t\t\tUserList.prototype.toJSON.should.be.a('function'); \t\t}); \t}); }); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041a\u043e\u0434 \u0441\u043d\u0430\u0431\u0436\u0435\u043d \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445.  <\/p>\n<pre><code class=\"javascript\">\tbefore(function () { \t\tdb.regen(); \t}); <\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u0435\u0434\u0438\u043d\u043e\u0436\u0434\u044b \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0411\u0414, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434 regen, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0448\u0443 \u0411\u0414 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. <br \/>  \u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e \u0447\u0442\u043e, \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0431\u0434 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u043f\u0440\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <b>done()<\/b> \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u0430, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0448\u0438\u0431\u043a\u0443 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043d\u0435\u0435 \u0436\u0435. \u041a\u0443\u0441\u043e\u043a \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438:  <\/p>\n<pre><code class=\"javascript\">...              \/\/find \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c UserList \t\t\tit('should be instanceof UserList', function (done) { \t\t\t\tUser.find(function (err, list) { \t\t\t\t\tif (err) return done(err); \t\t\t\t\tlist.should.be.an.instanceOf(UserList); \t\t\t\t\tdone(); \t\t\t\t}); \t\t\t}); ... <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 lib, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e models, \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430\u0448 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models\/db.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">\/*  * \u0424\u044d\u0439\u043a\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0434  *\/   \/\/\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 var users = [];  exports.users = users;  \/\/\u0421\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0411\u0414 \u0432 \u043d\u0430\u0447\u0430\u043b\u043e exports.regen = function () { \texports.drop(); \texports.generate(); };  exports.drop = function () { \t\/\/\u0427\u0442\u043e \u0431\u044b \u043d\u0435 \u043f\u043e\u0442\u0435\u0440\u044f\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c,  \t\/\/\u043c\u044b \u043e\u043f\u0443\u0441\u0442\u043e\u0448\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0442\u0430\u043a\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \tusers.splice(0, users.length); };  exports.generate = function () { \t\/\/\u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \tusers.push({ id: 0, name: 'Jo', age: 20, sex: 'm' }); \tusers.push({ id: 1, name: 'Bo', age: 19, sex: 'm' }); \tusers.push({ id: 2, name: 'Le', age: 18, sex: 'w' }); \tusers.push({ id: 10, name: 'NotFound', age: 18, sex: 'w' });\t };  \/\/\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 exports.generate(); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models\/user.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var util = require('util'), \tdb = require('.\/db.js'), \tUserList = require('.\/userlist.js'), \tusers = db.users;  \/*  * \u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439  *\/ var User = module.exports = function User(opt) { \tthis.id = users.length; \tthis.name = opt.name; \tthis.age = opt.age; \tthis.sex = opt.sex; \t \tthis.isNew = true; }  \/*  * \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u0431\u0430\u0437\u044b  *\/ function loadFromObj(obj) { \tvar user = new User(obj); \t \tuser.id = obj.id; \tuser.isNew = false; \t \treturn user; }  \/*  * \u0418\u0449\u0435\u043c \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u044f\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432  *\/ User.find = function (fn) { \tvar i,  \t\tl = users.length, \t\tlist;  \tif (l) { \t\tlist = new UserList(); \t\t \t\tfor (i = 0, l; l &gt; i; i += 1) { \t\t\tlist.push(loadFromObj(users[i])); \t\t} \t} \t \tfn(null, list); };  \/*  * \u0418\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e id  *\/ User.findById = function (id, fn) { \tvar obj = users[id], \t\tuser; \t \tif (obj) { \t\tuser = loadFromObj(obj); \t} \t \tfn(null, user); };  \/*  * \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c  *\/ User.prototype.save = function (fn) { \tvar err; \t \t\/\/\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \tif (Number.isFinite(this.age) && this.age &gt; 0 && this.age &lt; 150) { \t\tif (this.isNew) { \t\t\tusers.push(this.toJSON()); \t\t\tthis.isNew = false; \t\t} else { \t\t\tusers[this.id] = this.toJSON(); \t\t} \t} else { \t\terr = 'Invalid age'; \t} \t \tfn(err); };  User.prototype.toJSON = function () { \tvar json = { \t\t\tid: this.id, \t\t\tname: this.name, \t\t\tage: this.age, \t\t\tsex: this.sex \t\t}; \t \treturn json; }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models\/userlist.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var util = require('util');  \/*  * UserList - \u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043e\u0442 Array  *\/ var UserList = module.exports = function UserList() { \tArray.apply(this) } util.inherits(UserList, Array);  UserList.prototype.toJSON = function () { \tvar i,  \t\tl = this.length, \t\tarr = new Array(l); \t \tfor (i = 0; l &gt; i; i += 1) { \t\tarr[i] = this[i].toJSON(); \t} \t \treturn arr; }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models\/index.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">exports.User = require('.\/user.js'); exports.UserList = require('.\/userlist.js'); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u043c \u043a\u043e\u0434 lib\/app.js \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043d\u0435\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 User \u0438 \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0431\u0443\u0434\u0435\u043c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0435.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">lib\/app.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var      ... \tUser = require('.\/models\/index.js').User,     ...  ... app.get('\/users', function(req, res, next){ \tUser.find(function (err, users) { \t\tif (err) { \t\t\tnext(err); \t\t} else { \t\t\tres.render('index', { users: users.toJSON() }); \t\t} \t}); });  app.get('\/users\/profile', function(req, res, next){ \tvar id = req.query.id; \t \tUser.findById(id, function(err, user) { \t\tif (user) { \t\t\tres.render({ user: user.toJSON() }); \t\t} else { \t\t\tnext('Not found'); \t\t} \t}); }); ... <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h5>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h5>\n<p>  \u041e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u0430\u044f \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0447\u0430\u0441\u0442\u044c. \u042d\u0442\u043e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e http \u0441\u0435\u0440\u0432\u0435\u0440. \u0427\u0435\u0441\u0442\u043d\u043e \u043f\u0440\u0438\u0437\u043d\u0430\u044e\u0441\u044c, \u0447\u0442\u043e \u0442\u0443\u0442 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0445\u0430\u043b\u044f\u0432\u0438\u0442\u044c \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u0447\u0435\u0442\u044b\u0440\u0435 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438:<br \/>  1) \u041e\u0442\u0432\u0435\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0432 html \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441<br \/>  2) \u041e\u0442\u0432\u0435\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0432 json \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0430\u044f\u043a\u0441<br \/>  3) GET \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u0441\u0430\u0439\u0442\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443\/\u043e\u0431\u044a\u0435\u043a\u0442, \u0433\u0434\u0435 title \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 &#8216;\u041c\u043e\u0439 \u0441\u0430\u0439\u0442&#8217;<br \/>  \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 supertest, \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043b\u0435\u0433\u043a\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">test\/app.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var request = require('supertest'), \tapp = process.env.COVERAGE \t\t\t? require('..\/lib-cov\/app.js') \t\t\t: require('..\/lib\/app.js'); \t describe('Response html or json', function () { \t\/\/\u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c  \t\/\/\u043e\u0442\u0432\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 html \tit('should be responded as html', function (done) { \t\trequest(app) \t\t\t.get('\/') \t\t\t.expect('Content-Type', \/text\\\/html\/) \t\t\t.expect(200, done); \t}); \t \t\/\/\u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0430\u044f\u043a\u0441, \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c json \tit('should be responded as json', function (done) { \t\trequest(app) \t\t\t.get('\/') \t\t\t.set('X-Requested-With', 'XMLHttpRequest') \t\t\t.expect('Content-Type', \/application\\\/json\/) \t\t\t.expect(200, done); \t}); });  describe('GET \/', function () {  \t\/\/\u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c title === \u041c\u043e\u0439 \u0441\u0430\u0439\u0442 \tit('should be included title', function (done) { \t\trequest(app) \t\t\t.get('\/') \t\t\t.end(function (err, res) { \t\t\t\tif (err) return done(err); \t\t\t\tres.text.should.include('&lt;title&gt;\u041c\u043e\u0439 \u0441\u0430\u0439\u0442&lt;\/title&gt;'); \t\t\t\tdone(); \t\t\t}); \t}); \t \t\/\/\u0414\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c title === \u041c\u043e\u0439 \u0441\u0430\u0439\u0442 \tit('should be included title', function (done) { \t\trequest(app) \t\t\t.get('\/') \t\t\t.set('X-Requested-With', 'XMLHttpRequest') \t\t\t.end(function (err, res) { \t\t\t\tif (err) return done(err); \t\t\t\tres.body.should.have.property('data'); \t\t\t\tres.body.data.should.have.property('title', '\u041c\u043e\u0439 \u0441\u0430\u0439\u0442'); \t\t\t\tdone(); \t\t\t}); \t}); }); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 request() \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 http.Server \u043b\u0438\u0431\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. SuperTest \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <a href=\"https:\/\/github.com\/visionmedia\/superagent\">SuperAgent<\/a> \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 <b>expect()<\/b> \u043b\u0438\u0431\u043e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 <b>end()<\/b>.<\/p>\n<h5>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h5>\n<p>  \u0412\u043e\u0442 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u043e\u0436\u043d\u043e (\u0438 \u0434\u0430\u0436\u0435 \u043d\u0443\u0436\u043d\u043e) \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0414\u0430\u0436\u0435 \u0432 \u043c\u043e\u0435\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0447\u0435\u043c \u0441\u0430\u043c\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043d\u043e \u0434\u0430\u0436\u0435 \u044d\u0442\u0438 \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u043e\u043b\u043d\u044b\u0435 \u0438 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u0430 \u043e\u0448\u0438\u0431\u043a\u0430, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438\u0445. \u0425\u043e\u0442\u044f \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c User \u043f\u043e\u043a\u0440\u044b\u0442\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0432 \u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. <br \/>  \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u044b \u044d\u0442\u043e \u043d\u0435 \u043f\u0430\u043d\u0430\u0446\u0435\u044f, \u0442\u0435\u0441\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043c\u0435\u043b\u043e\u0447\u0438, \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435 \u043c\u0435\u0441\u0442\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.<\/p>\n<p>  \u041a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/zxcabs\/4fun\/tree\/master\/express\/app2\">github&#8217;e<\/a>    \t   \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/162555\/\"> http:\/\/habrahabr.ru\/post\/162555\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">   \t\u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/161943\/\">\u0440\u0430\u0437<\/a> \u044f \u043f\u0438\u0441\u0430\u043b \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 nodejs \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c expressjs \u043a\u0430\u043a \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438 jade \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430. \u0412 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u044f \u0445\u043e\u0447\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f:<br \/>   \u2014 <a href=\"http:\/\/visionmedia.github.com\/mocha\/\">Mocha<\/a> \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043b\u0435\u0433\u043a\u043e \u0438 \u043f\u0440\u043e\u0441\u0442\u043e. \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u0447\u0435\u0442\u044b \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u0445, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0443\u043c\u0435\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432.<br \/>   \u2014 <a href=\"https:\/\/github.com\/visionmedia\/should.js\/\">Should<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0441\u0442\u0438\u043b\u0435 \u00ab\u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f\u00bb <sub>(\u041d\u0435 \u043d\u0430\u0448\u0435\u043b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f)<\/sub><br \/>   \u2014 <a href=\"https:\/\/github.com\/visionmedia\/supertest\">SuperTest<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f HTTP \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 nodejs<br \/>   \u2014 <a href=\"http:\/\/siliconforks.com\/jscoverage\/\">jscoverage<\/a> \u2014 \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-162555","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/162555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=162555"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/162555\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=162555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=162555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=162555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}