«От экспериментов с инфраструктурой до внедрения в...

84

Upload: fdconf

Post on 16-Jul-2015

4.398 views

Category:

Presentations & Public Speaking


2 download

TRANSCRIPT

От экспериментов с инфраструктурой до внедрения в продакшен

Дмитрий Махнёв

Работаю в ok.ru

Делаю m.ok.ru

О себе

Автоматизация

Концентрация на новых задачах

Снижение порога входа

Улучшение стабильности

.sidebar { ... } .sidebar.__active { ... } .sidebar_item { ... } .sidebar_item.__selected { ... }

/* sidebar __active sidebar_item (__selected)*/

CSSG

.sidebar { ... } .sidebar.__active { ... } .sidebar_item { ... } .sidebar_item.__selected { ... }

/* sidebar __active sidebar_item (__selected)*/

HTML Parse

CSSG Tree

CSSG Render

HTML Parse

CSSG Tree

CSSG Render

CSS Parse …

Write in File

HTML Parse

<div class="sidebar __active"> <div class="sidebar_item">Item 1</div> <div class="sidebar_item __selected">Item 2</div> <div class="sidebar_item">Item 3</div> <div class="sidebar_item">Item 4</div> <div class="sidebar_item">Item 5</div> </div>

Testing

describe('math test', function () { it('sum works correct', function () { expect(sum(1, 1)).toBe(2); }); it('difference works correct', function () { expect(difference(1, 1)).toBe(0); }); });

describe('tests types', function () { it('sync', function () { expect(true).toBeTruthy(); }); it('async', function (done) { setTimeout(function () { expect(true).toBeTruthy(); done(); }, 100); }); });

Link coming soon…

Unit Testing

Test Driven Development (TDD)

Black Box Testing

✓ Testing

describe('password security level', function () { it('50%', function () { expect(passwordSecurityLevel('qwerty')).toBe(50); });});

Testing Private Methods

Black Box

Input Output

describe('one div with attributes', function () { var simpleDOMResult = parse( '<div class="block" data-foo="bar"></div>' ); var div = simpleDOMResult.childNodes[0]; defaultDivTests(div);});

Testing Private Methods

/** * * @param {ContextOfParse} contextOfParse * @param {String} char */processings[TEXT] = function (contextOfParse, char) { addCharForBuffer(contextOfParse, char); switch (char) { case '<': contextOfParse.state = TAG_START; break; default: contextOfParse.textBuffer += char; }};

/*@defaultTesting.exports*/ processingsExport.processingText = processings[TEXT];

/*@/defaultTesting.exports*/

/** * * @param {String} xml * @return {Object} simpleDOM */module.exports = function (xml) { var contextOfParse = new ContextOfParse(), i = 0, iMax = xml.length, result; for (; i < iMax; i += 1) { processings[contextOfParse.state](contextOfParse, xml.charAt(i)); } processingResultState(contextOfParse); result = contextOfParse.result; contextOfParse.destructor(); return result; };

Tests Runners

✓ Testing ✓ Black Box Testing

Karma — Test Runner for JavaScript

Link coming soon…

Runner Workflow

var config = readConfig();config.browsers.each(function(browser){ var result = startBrowser(browser, config.code); console.output(processingResult(result)); });

Dependency manager

✓ Testing ✓ Black Box Testing ✓ Tests Runners

require('module');

Package Managers

Front-endBack-end & Console

require('../../../../src/default-lib');

Link coming soon…

var cycle = require('default-lib').cycle;

var webpack = require('webpack'); module.exports = { entry: './entry.js', output: { path: __dirname, filename: 'bundle.js' } };

webpack.config.js

var defaultLib = {};defaultLib.getGlobal = require('./utils/getGlobal');defaultLib.typesDetection = require('./utils/typesDetection'); defaultLib.getObjectKeys = require('./utils/getObjectKeys');defaultLib.getObjectLength = require('./utils/getObjectLength');defaultLib.cycleKeys = require('./utils/cycle/cycleKeys');defaultLib.cycle = require('./utils/cycle/cycle'); defaultLib.reversiveCycle = require('./utils/cycle/reversiveCycle'); defaultLib.getObjectSafely = require('./utils/getObjectSafely');defaultLib.onload = require('./utils/onload');module.exports = defaultLib;

Entry Point

/* 0 *//***/ function(module, exports, __webpack_require__) { document.write(__webpack_require__(1)); document.body.addEventListener('click', function () { });/***/ },/* 1 *//***/ function(module, exports, __webpack_require__) { module.exports = 'It works from content.js'; /***/ }

Part of webpack Bundle

webpack: { resolve: { root: [ path.join(__dirname, 'bower_components'), path.join(__dirname, 'src') ] }, plugins: [ new webpack.ResolverPlugin( new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin( 'bower.json', ['main'] ) ) ]}

webpack for karma.config.js

files: [ 'tests/specs/simple-dom.js', 'tests/specs/modules/nodes.js', 'tests/specs/modules/parse/defaultTesting.exports.simpleDOM.parse/' + 'defaultTesting.exports.simpleDOM.parse.js', 'tests/specs/modules/parse/defaultTesting.exports.simpleDOM.parse/' + 'contextOfParse.js', 'tests/specs/modules/parse/defaultTesting.exports.simpleDOM.parse/' + 'microhelpers/**/*.js', 'tests/specs/modules/parse/defaultTesting.exports.simpleDOM.parse/' + 'builders/**/*.js', 'tests/specs/modules/parse/defaultTesting.exports.simpleDOM.parse/' + 'processings/**/*.js', 'tests/specs/modules/parse/parse.js', 'tests/specs/modules/selectors/parseSelector.js']

var path = require('path'); var webpack = require('webpack');var bowerConfig = require('./bower');module.exports = { entry: path.resolve(bowerConfig.main), output: { path: path.resolve(bowerConfig.dist), filename: bowerConfig.umdName + '.js', libraryTarget: 'umd', library: bowerConfig.umdName }, plugins: [ new webpack.ResolverPlugin( new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin( 'bower.json', ['main'] ) ), new webpack.optimize.UglifyJsPlugin() ]};

webpack.config.js

/*@defaultTesting.exports*/processingsExport.processingText = processings[TEXT]; /*@/defaultTesting.exports*/

/** * * @param {ContextOfParse} contextOfParse * @param {String} char */processings[TEXT] = function (contextOfParse, char) { addCharForBuffer(contextOfParse, char); switch (char) { case '<': contextOfParse.state = TAG_START; break; default: contextOfParse.textBuffer += char; }}; /*@defaultTesting.exports*/processingsExport.processingText = processings[TEXT]; /*@/defaultTesting.exports*/

/* 0 *//***/ function(module, exports, __webpack_require__) { document.write(__webpack_require__(1)); document.body.addEventListener('click', function () { });/***/ },/* 1 *//***/ function(module, exports, __webpack_require__) { module.exports = 'It works from content.js'; /***/ }

Part of webpack Bundle

webpack Workflow

var config = readConfig();var files = [config.entry];var bundleParts = [];while (files.length !== 0) { var file = loadFile(files.shift()); var ast = parseToASR( file, function (linkOnFile) { files.push(linkOnFile) } ); bundleParts.push(ast); } createBundle(bundleParts);

module: { loaders: [ //loader removes code for testing { test: /^.*$/, loader: 'regexp', rules: [ { 'for': /regExpRule/g, 'do': '' } ] } ]}

webpack.config.js loader

/*@defaultTesting.{{mode}}*//*@/defaultTesting.{{mode}}*/

Tasks Runner

✓ Testing ✓ Black Box Testing ✓ Tests Runners ✓ Dependency manager

Tasks Runners

Synchronously I/Oⁿ Streams

JS

Run Tests

Build bundle

JS

Run Tests

Build bundle Generate Doc

Commit Publish Publish × 2

gulp-run-sequence

var runSequence = require('gulp-run-sequence');gulp.task('default', function () { runSequence( 'build:test', ['build:dist', 'build:commit', 'build:docs'], 'build:publish' ); });

Environment

✓ Testing ✓ Black Box Testing ✓ Tests Runners ✓ Dependency manager ✓ Tasks Runner

npm i

it('key input add 2 symbols ', function (done) { define('', [ '/res/js/modules/dom/domTraverse.js', '/res/js/modules/inputWithCounter.js' ], function (traverse, inputWithCounter) { var initedInput = initInputWithCounterFor( inputWithCounter, tmpl2CountersAndWrapper ); var counterTextNode = findCounter(initedInput, 0, traverse.getTextNode); var counter2TextNode = findCounter(initedInput, 1, traverse.getTextNode); var instance = initedInput.instance; var input = instance.input; var startValueLength = instance.valueLength; var valueLength; effroi.mouse.focus(input); effroi.keyboard.hit('1', '1'); valueLength = instance.valueLength; expect(valueLength - startValueLength).toBe(2); expect(valueLength).toBe(+counterTextNode.nodeValue); expect(valueLength).toBe(+counter2TextNode.nodeValue); done(); } );});

inputWithCounter Test From m.ok.ru

var keyboard = require('effroi').keyboard; keyboard.focus(element);keyboard.hit('a'); keyboard.hit('b','c','d'); keyboard.combine(keyboard.CTRL, 'v');

describe('angularjs homepage todo list', function () { it('should add a todo', function () { browser.get('http://www.angularjs.org'); element(by.model('todoText')).sendKeys('write a protractor test'); element(by.css('[value="add"]')).click(); var todoList = element.all(by.repeater('todo in todos')); expect(todoList.count()).toEqual(3); expect(todoList.get(2).getText()).toEqual('write a protractor test'); });});

wallaby.js

Ссылки

http://bit.ly/fdc_dm