diff --git a/lib/data/context.js b/lib/data/context.js index 50936b8e0..1e2617619 100644 --- a/lib/data/context.js +++ b/lib/data/context.js @@ -26,6 +26,22 @@ export default function (context) { maskSecretInTitle(scenarios) return new DataScenarioConfig(scenarios) }, + Before(fn) { + data.forEach(dataRow => { + if (!dataRow.skip) { + const wrappedFn = (args) => fn({ ...args, current: dataRow.data }) + context.Before(wrappedFn) + } + }) + }, + After(fn) { + data.forEach(dataRow => { + if (!dataRow.skip) { + const wrappedFn = (args) => fn({ ...args, current: dataRow.data }) + context.After(wrappedFn) + } + }) + }, only: { Scenario(title, opts, fn) { const scenarios = [] diff --git a/lib/mocha/hooks.js b/lib/mocha/hooks.js index ded7f7b42..edfabc71d 100644 --- a/lib/mocha/hooks.js +++ b/lib/mocha/hooks.js @@ -110,6 +110,11 @@ class HookConfig { this.hook.retry(n) return this } + + inject(obj) { + this.hook.inject = obj + return this + } } export { diff --git a/test/data/sandbox/codecept.dataDrivenHooks.json b/test/data/sandbox/codecept.dataDrivenHooks.json new file mode 100644 index 000000000..48ca630cb --- /dev/null +++ b/test/data/sandbox/codecept.dataDrivenHooks.json @@ -0,0 +1,14 @@ +{ + "tests": "./*_test.dataDrivenHooks.js", + "timeout": 10000, + "output": "./output", + "helpers": { + "FakeDriver": { + "require": "../helper" + } + }, + "include": {}, + "bootstrap": false, + "mocha": {}, + "name": "sandbox" +} diff --git a/test/data/sandbox/dataDrivenHooks_test.dataDrivenHooks.js b/test/data/sandbox/dataDrivenHooks_test.dataDrivenHooks.js new file mode 100644 index 000000000..0ec4d433e --- /dev/null +++ b/test/data/sandbox/dataDrivenHooks_test.dataDrivenHooks.js @@ -0,0 +1,25 @@ +Feature('Data-driven Before/After hooks'); + +import { dataTable as DataTable } from 'codeceptjs'; + +const hookCalls = []; + +const credentials = new DataTable(['username', 'password']); +credentials.add(['alice', 'pass123']); +credentials.add(['bob', 'pass456']); + +Data(credentials).Before(({ current }) => { + hookCalls.push(`Before: ${current.username}`); +}); + +Data(credentials).After(({ current }) => { + hookCalls.push(`After: ${current.username}`); +}); + +Scenario('test 1', () => { + // Just ensure test runs +}); + +Scenario('test 2', () => { + // Just ensure test runs +}); diff --git a/test/unit/data/dataDrivenHooks_test.js b/test/unit/data/dataDrivenHooks_test.js new file mode 100644 index 000000000..6d7a71e6d --- /dev/null +++ b/test/unit/data/dataDrivenHooks_test.js @@ -0,0 +1,83 @@ +import { expect } from 'chai' +import DataTable from '../../../lib/data/table.js' + +describe('Data-driven Before/After hooks - data structure', () => { + it('should create DataTable with correct structure', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + accounts.add(['admin', '654321']) + + expect(accounts.rows).to.have.lengthOf(2) + expect(accounts.array).to.deep.equal(['login', 'password']) + }) + + it('should have rows property with data and skip', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + + accounts.rows.forEach(row => { + expect(row).to.have.property('data') + expect(row).to.have.property('skip') + expect(row.data).to.include.keys(['login', 'password']) + }) + }) + + it('first row should have correct data', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + accounts.add(['admin', '654321']) + + const firstRow = accounts.rows[0] + expect(firstRow.data.login).to.equal('davert') + expect(firstRow.data.password).to.equal('123456') + }) + + it('second row should have correct data', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + accounts.add(['admin', '654321']) + + const secondRow = accounts.rows[1] + expect(secondRow.data.login).to.equal('admin') + expect(secondRow.data.password).to.equal('654321') + }) + + it('should support filtering skipped rows', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + accounts.add(['admin', '654321']) + + const activeRows = accounts.rows.filter(row => !row.skip) + expect(activeRows).to.have.lengthOf(2) + }) + + it('should extract current from row data', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + + const row = accounts.rows[0] + const current = row.data + + expect(current.login).to.equal('davert') + expect(current.password).to.equal('123456') + }) + + it('should support iterating all rows', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + accounts.add(['admin', '654321']) + + const currentValues = accounts.rows.map(row => row.data) + expect(currentValues).to.have.lengthOf(2) + expect(currentValues[0].login).to.equal('davert') + expect(currentValues[1].login).to.equal('admin') + }) + + it('should detect when row is skipped', () => { + const accounts = new DataTable(['login', 'password']) + accounts.add(['davert', '123456']) + + const firstRow = accounts.rows[0] + expect(firstRow.skip).to.be.false + }) +})