UNPKG

4.53 kBJavaScriptView Raw
1/**
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2016 Arnaud Dezandee
5 *
6 * Authors:
7 * Arnaud Dezandee <dezandee.arnaud@gmail.com>
8 */
9
10/**
11 * Dependencies
12 */
13
14import path from 'path';
15import dbg from 'debug';
16import arity from 'util-arity';
17import Promise from 'bluebird';
18import Immutable from 'immutable';
19import defaultsDeep from 'lodash.defaultsdeep';
20import pkg from '../package.json';
21
22import Step from './step.js';
23import Driver from './driver.js';
24import definitions from './step_definitions/index.js';
25
26/**
27 * Private
28 */
29
30const debug = dbg('mink');
31
32const DEFAULT_PARAMS = {
33 driver: {
34 viewportSize: {
35 width: 1366,
36 height: 768,
37 },
38 baseUrl: process.env.BASE_URL,
39 desiredCapabilities: {
40 browserName: 'firefox',
41 },
42 logLevel: 'silent',
43 port: 4444,
44 },
45};
46
47function noop() {
48 // No operation performed.
49}
50
51/**
52 * Public
53 */
54
55class Mink {
56 constructor() {
57 this.steps = Immutable.Map();
58
59 this.parameters = null;
60 this.cucumber = null;
61 this.driver = null;
62 }
63
64 /**
65 * Mink initialization method and entry point
66 *
67 * @param {Object} cucumber cucumber-js context
68 * @param {Object} parameters
69 * @returns {void}
70 */
71 init(cucumber, params = {}) {
72 debug('init', params);
73
74 const parameters = defaultsDeep(params, DEFAULT_PARAMS);
75 const driver = new Driver(parameters.driver);
76
77 this.parameters = parameters;
78 this.cucumber = cucumber;
79 this.driver = driver;
80
81 this.registerHooks(cucumber, driver);
82
83 definitions.forEach(([pattern, fn]) => {
84 this.defineStep(pattern, fn);
85 });
86 }
87
88 /**
89 * Define a new step inside Mink-Cucumber context for use in .features files.
90 *
91 * @param {RegExp} pattern step regex
92 * @param {Function} fn step function
93 * @returns {Step}
94 */
95 defineStep(pattern, fn) {
96 debug('defineStep', pattern);
97
98 if (!this.steps.has(pattern)) {
99 this.steps = this.steps.set(pattern, new Step(pattern, fn));
100
101 if (this.cucumber) {
102 const wrappedFn = arity(fn.length, (...args) =>
103 Promise.try(() => fn.apply(this, args))
104 );
105 this.cucumber.defineStep(pattern, wrappedFn);
106 }
107 }
108
109 return this.steps.get(pattern);
110 }
111
112 /**
113 * Search for a matching registered step.
114 *
115 * @param {String} line
116 * @returns {Step}
117 */
118 findStep(line) {
119 debug('findStep', line);
120
121 const step = this.steps.find(s => !!s.match(line));
122 if (!step) throw new Error(`Could not findStep with line "${line}"`);
123
124 return step;
125 }
126
127 /**
128 * @param {String} input line
129 * @returns {Promise}
130 */
131 runStep(line, cb = noop) {
132 debug('runStep', line);
133
134 const step = this.findStep(line);
135 return step.runWith(this, line, cb);
136 }
137
138 /**
139 * @param {Array} lines
140 * @returns {Promise}
141 */
142 manyStep(lines, cb = noop) {
143 debug('manyStep', lines.join(', ').substr(0, 80));
144
145 return Promise.each(lines, line => (
146 this.runStep(line)
147 )).asCallback(cb);
148 }
149
150 /**
151 * @param {Array<Step>}
152 * @returns {Promise}
153 */
154 metaStep(steps, cb = noop) {
155 debug('metaStep', steps);
156
157 return Promise.each(steps, step => (
158 step.runWith(this)
159 )).asCallback(cb);
160 }
161
162 /**
163 * Register mink driver hooks on cucumber context
164 *
165 * @param {Object} Cucumber cucumber-js context
166 * @param {Object} DriverInstance mink driver instance
167 * @returns {void}
168 */
169 registerHooks(cucumber, driver) {
170 cucumber.registerHandler('BeforeFeatures', (event, done) =>
171 driver.init()
172 .then(() => driver.setViewportSize(driver.parameters.viewportSize))
173 .then(() => done())
174 .catch(error => console.error(error))
175 );
176
177 cucumber.registerHandler('AfterFeatures', (event, done) =>
178 driver.end()
179 .then(() => done())
180 .catch(error => console.error(error))
181 );
182
183 if (driver.parameters.screenshotPath) {
184 cucumber.After(event => {
185 if (!event.isFailed()) return null;
186
187 const fileName = [event.getName() || 'Error', ':', event.getLine(), '.png'].join('');
188 const filePath = path.join(driver.parameters.screenshotPath, fileName);
189 return driver.saveScreenshot(filePath);
190 });
191 }
192 }
193}
194
195// Aliases
196Mink.prototype.Given = Mink.prototype.defineStep;
197Mink.prototype.Then = Mink.prototype.defineStep;
198Mink.prototype.When = Mink.prototype.defineStep;
199Mink.prototype.DEFAULT_PARAMS = DEFAULT_PARAMS;
200Mink.prototype.VERSION = pkg.version;
201
202/**
203 * Interface
204 */
205
206export default new Mink();