Specs are markdown documents which are made executable through the use of
"steps". They are then executed by a normal go test
run.
For example, the scenarios below make use of the file created in the next step:
- Create a
spec_test.go
file:
package elicit_test
import (
"github.com/mpwalkerdine/elicit"
"testing"
)
func Test(t *testing.T) {
elicit.New().
WithSpecsFolder(".").
WithSteps(steps).
RunTests(t)
}
var steps = map[string]interface{}{}
- Create a module file
This specification describes (and tests!) the elicit markdown syntax.
Level 1 headings name a Spec e.g.
- Create a
spec_heading.md
file:
# Spec Name
- Running
go test -v
will output:
Spec Name
=========
The name is derived from the root method defined above, the relative path
of the .md
file and the spec heading.
Level 2 headings name a Scenario, e.g.
- Create a
scenario_heading.md
file:
# Spec Name
## Scenario Name
- Running
go test -v
will output:
Spec Name
=========
Pending: 1
Scenario Name
-------------
Pending
List items using the +
character define executable steps, e.g.
- Create a
simple_step.md
file:
# Spec Name
## Scenario Name
+ A Step
- Running
go test -v
will output:
Spec Name
=========
Pending: 1
Scenario Name
-------------
Pending
? A Step
If you wish to include bullets in the specification which aren't steps,
use -
or *
in the markdown.
Steps are run in order, one after the other. If a step is missing an implementation, is skipped or failed, then subsequent steps will be skipped automatically.
Step implementations are described in Steps.
Steps defined before the first scenario are run before every scenario.
A horizontal rule at the end of the file allows steps to be run after every scenario, e.g.
- Create a
before_after_steps.md
file:
# Spec
+ before
## First Scenario
+ step 1
## Last Scenario
+ step 2
---
+ after
- Running
go test -v
will output:
Spec
====
Pending: 2
First Scenario
--------------
Pending
? before
? step 1
? after
Last Scenario
-------------
Pending
? before
? step 2
? after
Note that, like other steps, the before and after steps will be skipped if an earlier step is undefined, skipped or failed.
Tables defined immediately after a step are passed into the step implementation
as a parameter. The step text for these will include the ☷ symbol for each
table in the output log to indicate that the step implementation must accept an
elicit.Table
parameter.
All other tables are added into their parent context to be used for step parameterisation.
Parameterised steps use the <param name>
syntax which corresponds to a table
header. This creates multiple steps in place of the original, but with values
substituted in from the table.
Note that at present only a single table can be used for parameterisation of a single step. The mechanism for handling parameterisation across tables hasn't been decided.
- Create a
tables.md
file:
# Tables
This table is available in all scenarios, and in before/after steps.
a | b | c
---|---|---
1 | 2 | 3
4 | 5 | 6
+ print "before: a = <a>, b = <b>, c = <c>"
## Step Table
+ Step with table
A | Table | Here
----|--------|------
Is | Passed | In
## Scenario Tables
This is a scenario-specific table
d | e | f
---|----|----
7 | 8 | 9
10 | 11 | 12
Scenario steps can use <a>, <b> and <c>, but <d>, <e> and <f> are scoped to this
scenario.
+ print "during: a = <a>"
+ print "during: d = <d>"
---
Any tables in the footer are scoped to the specification.
+ print " after: a = <a>"
- Create step definitions using "github.com/mpwalkerdine/elicit":
steps[`Step with table`] =
func(t *testing.T, table elicit.Table) {
if len(table.Columns) == 0 {
t.Error("No columns")
}
if len(table.Rows) == 0 {
t.Error("No rows")
}
}
steps[`print "(.*)"`] =
func(t *testing.T, v string) {
t.Log(v)
}
- Running
go test -v
will output:
Tables
======
Passed: 2
Step Table
----------
Passed
✓ print "before: a = 1, b = 2, c = 3"
✓ print "before: a = 4, b = 5, c = 6"
✓ Step with table ☷
✓ print " after: a = 1"
✓ print " after: a = 4"
Scenario Tables
---------------
Passed
✓ print "before: a = 1, b = 2, c = 3"
✓ print "before: a = 4, b = 5, c = 6"
✓ print "during: a = 1"
✓ print "during: a = 4"
✓ print "during: d = 7"
✓ print "during: d = 10"
✓ print " after: a = 1"
✓ print " after: a = 4"
If you need to pass a block of text to a step, you can used a fenced code block like the majority of this file.
The output appends a ☰ symbol for each text block.
- Create a
text_block.md
file:
# Text Blocks
## Text Block
+ This step takes a block of text:
```title
Multiple lines
of text which
are passed into
the step
implementation
```
- Create a step definition using
github.com/mpwalkerdine/elicit
,strings
:
steps[`This step takes a block of text:`] =
func(t *testing.T, text elicit.TextBlock) {
trimmed := strings.TrimSpace(text.Content)
lines := strings.Split(trimmed, "\n")
t.Log("\n> " + strings.Join(lines, "\n> "))
}
- Running
go test -v
will output:
Text Blocks
===========
Passed: 1
Text Block
----------
Passed
✓ This step takes a block of text: ☰
--- PASS: Test (0.00s)
--- PASS: Test/text_block.md/Text_Blocks (0.00s)
--- PASS: Test/text_block.md/Text_Blocks/Text_Block (0.00s)
steps_test.go:15:
> Multiple lines
> of text which
> are passed into
> the step
> implementation