Skip to content

Commit

Permalink
Adding beforeStep/afterStep hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
andrasmarozsi-nbcuni committed Apr 25, 2019
1 parent d74bc45 commit ed76ddd
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 5 deletions.
6 changes: 5 additions & 1 deletion src/formatter/json_formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ export default class JsonFormatter extends Formatter {
data.line = line
data.name = pickleStep.text
} else {
data.keyword = isBeforeHook ? 'Before' : 'After'
if (testStep.stepHookDefinitionKeyword) {
data.keyword = testStep.stepHookDefinitionKeyword
} else {
data.keyword = isBeforeHook ? 'Before' : 'After'
}
data.hidden = true
}
if (testStep.actionLocation) {
Expand Down
69 changes: 67 additions & 2 deletions src/formatter/json_formatter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,76 @@ describe('JsonFormatter', () => {

it('outputs the after hook with special properties', function() {
const features = JSON.parse(this.output)
const beforeHook = features[0].elements[0].steps[2]
const afterHook = features[0].elements[0].steps[2]
expect(afterHook).to.not.have.ownProperty('line')
expect(afterHook.keyword).to.eql('After')
expect(afterHook.hidden).to.eql(true)
})
})

describe('with step-hooks', () => {
beforeEach(function() {
this.eventBroadcaster.emit('test-case-prepared', {
sourceLocation: this.testCase.sourceLocation,
steps: [
{
actionLocation: { uri: 'steps.js', line: 10 },
},
{
actionLocation: { uri: 'steps.js', line: 11 },
stepHookDefinitionKeyword: 'BeforeStep',
},
{
sourceLocation: { uri: 'a.feature', line: 6 },
actionLocation: { uri: 'steps.js', line: 11 },
},
{
actionLocation: { uri: 'steps.js', line: 12 },
stepHookDefinitionKeyword: 'AfterStep',
},
{
actionLocation: { uri: 'steps.js', line: 13 },
},
],
})
this.eventBroadcaster.emit('test-case-finished', {
sourceLocation: this.testCase.sourceLocation,
result: { duration: 1, status: Status.PASSED },
})
this.eventBroadcaster.emit('test-run-finished')
})

it('outputs the before hook with special properties', function() {
const features = JSON.parse(this.output)
const beforeHook = features[0].elements[0].steps[0]
expect(beforeHook).to.not.have.ownProperty('line')
expect(beforeHook.keyword).to.eql('After')
expect(beforeHook.keyword).to.eql('Before')
expect(beforeHook.hidden).to.eql(true)
})

it('outputs the before step hook with special properties', function() {
const features = JSON.parse(this.output)
const beforeStepHook = features[0].elements[0].steps[1]
expect(beforeStepHook).to.not.have.ownProperty('line')
expect(beforeStepHook.keyword).to.eql('BeforeStep')
expect(beforeStepHook.hidden).to.eql(true)
})

it('outputs the after step hook with special properties', function() {
const features = JSON.parse(this.output)
const afterStepHook = features[0].elements[0].steps[3]
expect(afterStepHook).to.not.have.ownProperty('line')
expect(afterStepHook.keyword).to.eql('AfterStep')
expect(afterStepHook.hidden).to.eql(true)
})

it('outputs the after hook with special properties', function() {
const features = JSON.parse(this.output)
const afterHook = features[0].elements[0].steps[4]
expect(afterHook).to.not.have.ownProperty('line')
expect(afterHook.keyword).to.eql('After')
expect(afterHook.hidden).to.eql(true)
})
})

describe('with attachments', () => {
Expand Down
4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ export { default as UsageFormatter } from './formatter/usage_formatter'
export { default as UsageJsonFormatter } from './formatter/usage_json_formatter'
export { formatterHelpers }

// Support Code Fuctions
// Support Code Functions
const { methods } = supportCodeLibraryBuilder
export const After = methods.After
export const AfterAll = methods.AfterAll
export const AfterStep = methods.AfterStep
export const Before = methods.Before
export const BeforeAll = methods.BeforeAll
export const BeforeStep = methods.BeforeStep
export const defineParameterType = methods.defineParameterType
export const defineStep = methods.defineStep
export const defineSupportCode = methods.defineSupportCode
Expand Down
27 changes: 27 additions & 0 deletions src/models/test_step_hook_definition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import PickleFilter from '../pickle_filter'
import Definition from './definition'

export default class TestStepHookDefinition extends Definition {
constructor(...data) {
super(...data)
this.pickleFilter = new PickleFilter({
tagExpression: this.options.tags,
})
}

appliesToTestCase({ pickle, uri }) {
return this.pickleFilter.matches({ pickle, uri })
}

getInvalidCodeLengthMessage() {
return this.buildInvalidCodeLengthMessage('0 or 1', '2')
}

getInvocationParameters({ hookParameter }) {
return [hookParameter]
}

getValidCodeLengths() {
return [0, 1, 2]
}
}
58 changes: 57 additions & 1 deletion src/runtime/test_case_runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ export default class TestCaseRunner {
parameters: worldParameters,
})
this.beforeHookDefinitions = this.getBeforeHookDefinitions()
this.beforeStepHookDefinitions = this.getBeforeStepHookDefinitions()
this.afterStepHookDefinitions = this.getAfterStepHookDefinitions()
this.afterHookDefinitions = this.getAfterHookDefinitions()
this.testStepIndex = 0
const testStepCount = this.testCase.pickle.steps.length
const beforeStepsCount =
this.beforeStepHookDefinitions.length * testStepCount
const afterStepsCount = this.afterStepHookDefinitions.length * testStepCount
this.maxTestStepIndex =
this.beforeHookDefinitions.length +
this.testCase.pickle.steps.length +
beforeStepsCount +
testStepCount +
afterStepsCount +
this.afterHookDefinitions.length -
1
this.result = {
Expand Down Expand Up @@ -68,6 +76,12 @@ export default class TestCaseRunner {
steps.push({ actionLocation })
})
this.testCase.pickle.steps.forEach(step => {
this.beforeStepHookDefinitions.forEach(definition => {
const actionLocation = { uri: definition.uri, line: definition.line }
const data = { actionLocation }
data.stepHookDefinitionKeyword = 'BeforeStep'
steps.push(data)
})
const actionLocations = this.getStepDefinitions(step).map(definition => ({
uri: definition.uri,
line: definition.line,
Expand All @@ -81,6 +95,12 @@ export default class TestCaseRunner {
data.actionLocation = actionLocations[0]
}
steps.push(data)
this.afterStepHookDefinitions.forEach(definition => {
const actionLocation = { uri: definition.uri, line: definition.line }
const data = { actionLocation }
data.stepHookDefinitionKeyword = 'AfterStep'
steps.push(data)
})
})
this.afterHookDefinitions.forEach(definition => {
const actionLocation = { uri: definition.uri, line: definition.line }
Expand All @@ -101,6 +121,18 @@ export default class TestCaseRunner {
)
}

getBeforeStepHookDefinitions() {
return this.supportCodeLibrary.beforeTestStepHookDefinitions.filter(
hookDefinition => hookDefinition.appliesToTestCase(this.testCase)
)
}

getAfterStepHookDefinitions() {
return this.supportCodeLibrary.afterTestStepHookDefinitions.filter(
hookDefinition => hookDefinition.appliesToTestCase(this.testCase)
)
}

getStepDefinitions(step) {
return this.supportCodeLibrary.stepDefinitions.filter(stepDefinition =>
stepDefinition.matchesStepName(step.text)
Expand Down Expand Up @@ -192,6 +224,28 @@ export default class TestCaseRunner {
return this.invokeStep(null, hookDefinition, hookParameter)
}

async runStepHooks(step, isBeforeHook) {
let stepHooks = []
const stepInfo = {
text: step.text,
arguments: step.arguments,
location: Object.assign({ uri: this.testCase.uri }, step.locations[0]),
}
if (isBeforeHook) {
stepHooks = this.beforeStepHookDefinitions
} else {
stepHooks = this.afterStepHookDefinitions
}
await Promise.each(stepHooks, async stepHook => {
await this.aroundTestStep(async () => {
if (this.isSkippingSteps()) {
return { status: Status.SKIPPED }
}
return this.invokeStep(null, stepHook, stepInfo)
})
})
}

async runHooks(hookDefinitions, hookParameter, isBeforeHook) {
await Promise.each(hookDefinitions, async hookDefinition => {
await this.aroundTestStep(() =>
Expand All @@ -217,7 +271,9 @@ export default class TestCaseRunner {

async runSteps() {
await Promise.each(this.testCase.pickle.steps, async step => {
await this.runStepHooks(step, true)
await this.aroundTestStep(() => this.runStep(step))
await this.runStepHooks(step, false)
})
}
}

0 comments on commit ed76ddd

Please sign in to comment.