'use strict'; var Suite = require('../suite'); var errors = require('../errors'); var createMissingArgumentError = errors.createMissingArgumentError; /** * Functions common to more than one interface. * * @param {Suite[]} suites * @param {Context} context * @param {Mocha} mocha * @return {Object} An object containing common functions. */ module.exports = function(suites, context, mocha) { /** * Check if the suite should be tested. * * @private * @param {Suite} suite - suite to check * @returns {boolean} */ function shouldBeTested(suite) { return ( !mocha.options.grep || (mocha.options.grep && mocha.options.grep.test(suite.fullTitle()) && !mocha.options.invert) ); } return { /** * This is only present if flag --delay is passed into Mocha. It triggers * root suite execution. * * @param {Suite} suite The root suite. * @return {Function} A function which runs the root suite */ runWithSuite: function runWithSuite(suite) { return function run() { suite.run(); }; }, /** * Execute before running tests. * * @param {string} name * @param {Function} fn */ before: function(name, fn) { suites[0].beforeAll(name, fn); }, /** * Execute after running tests. * * @param {string} name * @param {Function} fn */ after: function(name, fn) { suites[0].afterAll(name, fn); }, /** * Execute before each test case. * * @param {string} name * @param {Function} fn */ beforeEach: function(name, fn) { suites[0].beforeEach(name, fn); }, /** * Execute after each test case. * * @param {string} name * @param {Function} fn */ afterEach: function(name, fn) { suites[0].afterEach(name, fn); }, suite: { /** * Create an exclusive Suite; convenience function * See docstring for create() below. * * @param {Object} opts * @returns {Suite} */ only: function only(opts) { opts.isOnly = true; return this.create(opts); }, /** * Create a Suite, but skip it; convenience function * See docstring for create() below. * * @param {Object} opts * @returns {Suite} */ skip: function skip(opts) { opts.pending = true; return this.create(opts); }, /** * Creates a suite. * * @param {Object} opts Options * @param {string} opts.title Title of Suite * @param {Function} [opts.fn] Suite Function (not always applicable) * @param {boolean} [opts.pending] Is Suite pending? * @param {string} [opts.file] Filepath where this Suite resides * @param {boolean} [opts.isOnly] Is Suite exclusive? * @returns {Suite} */ create: function create(opts) { var suite = Suite.create(suites[0], opts.title); suite.pending = Boolean(opts.pending); suite.file = opts.file; suites.unshift(suite); if (opts.isOnly) { if (mocha.options.forbidOnly && shouldBeTested(suite)) { throw new Error('`.only` forbidden'); } suite.parent.appendOnlySuite(suite); } if (suite.pending) { if (mocha.options.forbidPending && shouldBeTested(suite)) { throw new Error('Pending test forbidden'); } } if (typeof opts.fn === 'function') { opts.fn.call(suite); suites.shift(); } else if (typeof opts.fn === 'undefined' && !suite.pending) { throw createMissingArgumentError( 'Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. ' + 'Supply a callback or explicitly skip the suite.', 'callback', 'function' ); } else if (!opts.fn && suite.pending) { suites.shift(); } return suite; } }, test: { /** * Exclusive test-case. * * @param {Object} mocha * @param {Function} test * @returns {*} */ only: function(mocha, test) { test.parent.appendOnlyTest(test); return test; }, /** * Pending test case. * * @param {string} title */ skip: function(title) { context.test(title); }, /** * Number of retry attempts * * @param {number} n */ retries: function(n) { context.retries(n); } } }; };