Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tags #34

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@
* [Tags](docs/tags.md)
* [Background](docs/gherkin.md#background)
* [Scenario Outline](docs/gherkin.md#background)
* [Background](gdocs/herkin.md#background)
* [Data Tables](docs/gherkin.md#background)
* [Doc Strings](docs/gherkin.md#background)
* [Comments](#)
* [Doc Strings](docs/gherkin.md#doc-strings)
* [Comments](docs/gherkin.md#comments)
* [Internationalisation](#)
* [Step Definitions](docs/step-definitions.md)
* [Regular Expressions](#)
Expand Down
211 changes: 211 additions & 0 deletions docs/gherkin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
# Gherkin

Gherkin is the language that Cucumber understands. It is a Business Readable, [Domain Specific Language](http://martinfowler.com/bliki/BusinessReadableDSL.html) that lets you describe software’s behaviour without detailing how that behaviour is implemented.

Gherkin serves two purposes — documentation and automated tests. The third is a bonus feature — when it yells in red it’s talking to you, telling you what code you should write.

Gherkin’s grammar exists in different flavours for many spoken languages (37 at the time of writing), so that your team can use the keywords in your own language.

There are a few conventions.

* Single Gherkin source file contains a description of a single feature.
* Source files have `.feature` extension.

## Gherkin Syntax

A Gherkin source file usually looks like this
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add gherkin after backticks to get syntax highlighting

Feature: Some terse yet descriptive text of what is desired
Textual description of the business value of this feature
Business rules that govern the scope of the feature
Any additional information that will make the feature easier to understand

Scenario: Some determinable business situation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be easier to digest if there were only 3 steps - Given, When, Then. It can become more advanced further down.

Given some precondition
And some other precondition
When some action by the actor
And some other action
And yet another action
Then some testable outcome is achieved
And something else we can check happens too

Scenario: A different situation
...
```

First line starts the feature. Lines 2–4 are unparsed text, which is expected to describe the business value of this feature. Line 6 starts a scenario. Lines 7–13 are the steps for the scenario. Line 15 starts next scenario and so on.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid referring to line numbers unless we can display them in the margin somehow. Maybe GitBook has a plugin for that?


Read more

* [Feature Introduction](gherkin.md#feature) – general structure of a feature
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inter document links shouldn't repeat the file name, only the anchor

* [Given/When/Then (Steps)](gherkin.md#steps)

## Feature Introduction {#feature}

Every `.feature` file conventionally consists of a single feature. A line starting with the keyword Feature followed by free indented text starts a feature. A feature usually contains a list of scenarios. You can write whatever you want up until the first scenario, which starts with the word Scenario (or localized equivalent; Gherkin is localized for [dozens of languages](https://github.com/cucumber/cucumber/wiki/Spoken-languages)) on a new line. You can use tagging to group features and scenarios together independent of your file and directory structure.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start by explaining that a Cucumber feature is a grouping of related scenarios, describing the same software feature.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please break long lines. Makes commenting easier.


Every scenario consists of a list of steps, which must start with one of the keywords **Given, When, Then, But** or **And**. Cucumber treats them all the same, but you shouldn’t. Here is an example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bold each word (without the comma inside).

Saying people should treat the differently without explaining how isn't helpful (people are very confused about it).

  • Given describes the current state of the world. It can also describe something that has happened in the past.
  • When is an event, or an action that is expected to cause an observable change
  • Then is an expected and observable outcome, or result


```
Feature: Serve coffee
Coffee should not be served until paid for
Coffee should not be served until the button has been pressed
If there is no coffee left then money should be refunded

Scenario: Buy last coffee
Given there are 1 coffees left in the machine
And I have deposited 1$
When I press the coffee button
Then I should be served a coffee
```

In addition to a scenario, a feature may contain a background, scenario outline and examples. Respective keywords (in English) and places to read more about them are listed below. You can get a list of localized keywords with cucumber `--i18n [LANG]`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capitalise keywords, and link to their section.

Don't assume Ruby - we should rather generate docs with all the translations.


| keyword | localized | more info see |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a bullet list where you only use the last column. The first two columns aren't useful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove file path from links, use anchors only

|-----------------|-------------------------|-------------------|
| name | 'English' | |
| native | 'English' | |
| encoding | 'UTF-8' | |
| feature | 'Feature' | [Feature](gherkin.md#feature)
| background | 'Backgroound' | [Background](gherkin.md#background)
| scenario | 'Scenario' | [Scenario](gherkin.md#feature)
| scenario_outline| 'Scenario Outline' | [Scenario Outline](gherkin.md#background)
| examples | 'Examples'/ 'Scenarios' | [Scenario Outline](docs/gherkin.md#background)
| given | 'Given' | [Given/When/Then (Steps)](docs/gherkin.md#steps)
| when | 'When' | [Given/When/Then (Steps)](docs/gherkin.md#steps)
| then | 'Then' | [Given/When/Then (Steps)](docs/gherkin.md#steps)
| and | 'And' | [Given/When/Then (Steps)](docs/gherkin.md#steps)
| but | 'But' | [Given/When/Then (Steps)](docs/gherkin.md#steps)

## Step definitions {#steps}
Copy link
Contributor

@aslakhellesoy aslakhellesoy Jul 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step definitions don't belong in this document. Please move to a separate step-definitions.md doc, in a separate PR.


For each step Cucumber will look for a matching **step definition**. A step definition is written in Ruby. Each step definition consists of a keyword, a string or regular expression, and a block. Example:

{% codetabs name="Ruby", type="rb" -%}
# features/step_definitions/coffee_steps.rb

Then "I should be served coffee" do
@machine.dispensed_drink.should == "coffee"
end
{%- language name="Java", type="java" -%}
{% raw %}
@Given("I have \\$100 in my Account")
public void iHave$100InMyAccount() throws Throwable {
// TODO: code that puts $100 into User's Account goes here
}
{% endraw %}
{%- endcodetabs %}

Step definitions can also take parameters if you use regular expressions:

{% codetabs name="Ruby", type="rb" -%}
# features/step_definitions/coffee_steps.rb

Given /there are (\d+) coffees left in the machine/ do |n|
@machine = Machine.new(n.to_i)
end
{%- language name="Java", type="java" -%}
{% raw%}
@Given("I have deposited \\$(100) in my Account")
public void iHaveDeposited$100InMyAccount(int amount) {
// TODO: code goes here
}
{% endraw %}
{%- endcodetabs %}

This step definition uses a regular expression with one match group – `(\d+)`. (It matches any sequence of digits). Therefore, it matches the first line of the scenario. The value of each matched group gets yielded to the block as a string. You must take care to have the same number of regular expression groups and block arguments. Since block arguments are always strings, you have to do any type conversions inside the block, or use Step Argument Transforms.

When Cucumber prints the results of the running features it will underline all step arguments so that it’s easier to see what part of a step was actually recognised as an argument. It will also print the path and line of the matching step definition. This makes it easy to go from a feature file to any step definition.

Take a look at [Step Definitions](step-definitions.md) and the examples directory to see more.

## Background {#background}

A background section in a feature file allows you to specify a set of steps that are common to every scenario in the file. Instead of having to repeat those steps over and over for each scenario, you move them up into a Background element. There are a couple of advantages to doing this:

A Background is much like a scenario containing a number of steps. The difference is when it is run. The background is run before each of your scenarios but after any of your Before [Hooks](hooks.md).

Example:

```
Feature: Change PIN
#some feature description comes here

Background:
Given I have been issued a new card
And I insert the card, entering the correct PIN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you express these steps in past tense please?

And I choose "Change PIN" from the menu

Scenario: Change PIN successfully
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unindent these two scenarios to be at the same level as the background

When I change the PIN to 9876
Then the system should remember my PIN is now 9876

Scenario: Try to change PIN to the same as before
When I try to change the PIN to the original PIN number
Then I should see a warning message
And the system should not have changed my PIN
```

You can have a single `Background` element per feature file, and it must appear before any of the `Scenario` or `Scenario Outline` elements. Just like all the other _Gherkin_ elements, you can give it a name, and you have space to put a multiline description before the first step. For example:

```
Feature: Change PIN
In order to be able to change it to something they can easily
remember, customers with new bank cards need to be able to
change their PIN using the ATM.

Background: Insert a newly issued card and sign in
Whenever the bank issues new cards to customers, they are supplied
with a Personal Identification Number (PIN) that is randomly
generated by the system.

Given I have been issued a new card
And I insert the card, entering the correct PIN
...
```

### Good practices for using Background

* Don’t use `Background` to set up complicated state unless that state is actually something the client needs to know.
* Keep your `Background` section short.
* Make your `Background` section vivid.
* Keep your scenarios short and don’t have too many.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good guideline, but it's not about Background, is it?


## Doc Strings {#doc-strings}

Doc strings just allow you to specify a larger piece of text than you could fit on a single line. For example, if you need to describe the precise content of an email message, you could do it like this:

```
Scenario: Ban Unscrupulous Users
When I behave unscrupulously
Then I should receive an email containing:
"""
Dear Sir,
Your account privileges have been revoked due to your unscrupulous behavior.
Sincerely,
The Management
"""
And my account should be locked
```

Just like a [Data Tables](docs/gherkin.md#datatable), the entire string between the `"""` triple quotes is attached to the step above it. The indentation of the opening `"""` is not important, although common practice is to indent two spaces in from the enclosing step, as shown.

The indentation inside the triple quotes, however, is significant: imagine the left margin running down from the start of the first """. If you want to include indentation within your string, you need to indent it within this margin.

## Comments {#comments}

As well as the description fields that follow Feature and Scenario keywords, Cucumber allows you to precede these keywords with comments.
Like in Ruby, comments start with a `#` character. Unlike in Ruby, comments have to be the first and the only thing on a line (well, apart from whitespace).

Here’s an example:
```
# This feature covers the account transaction and hardware-driver modules
Feature: Withdraw Cash
In order to buy beer
As an account holder
I want to withdraw cash from the ATM

# Can't figure out how to integrate with magic wand interface
Scenario: Withdraw too much from an account in credit
...
```
108 changes: 108 additions & 0 deletions docs/hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Hooks

Cucumber provides a number of hooks which allow us to run blocks at various points in the Cucumber test cycle. You can define them anywhere in your support or step definition layers, using the methods `Before` and `After`. Hooks are global by default, meaning they run for every scenario in your
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/layers/code/

features. If you want them to run for just certain scenarios, you need to tag
those scenarios and then use a [tagged hook](hooks.md#tagged-hooks).

## Scenario hooks

`Before` hooks will be run before the first step of each scenario. They will run in the same order of which they are registered.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make a h3 section for Before and After hooks? can you also describe how Before hooks are similar to Background, and when to use each one? (Before hooks are for techynthings like starting browsers or servers, starting database transactions etc,


{% codetabs name="Ruby", type="rb" -%}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make each code tab do the same thing

Before do
# Do something before each scenario.
end
{%- language name="Java", type="java" -%}
{% raw %}
@Before
public void beforeCallingScenario() {
System.out.println("*********** About to start the scenario.");
}
{% endraw %}
{%- endcodetabs %}

or like this:

{% codetabs name="Ruby", type="rb" -%}
Before do |scenario|
Copy link
Contributor

@aslakhellesoy aslakhellesoy Jul 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discourage this kind of logging - Cucumber's own formatters take care of that. Instead, show something more useful you can do with a Scenario object, like embedding something into the reports, like an image (typically from a screenshot) or text.

# The +scenario+ argument is optional, but if you use it, you can get the title,
# description, or name (title + description) of the scenario that is about to be
# executed.
Rails.logger.debug "Starting scenario: #{scenario.title}"
end
{%- endcodetabs %}

`After` hooks will be run after the last step of each scenario, even when there are failing, undefined, pending or skipped steps. They will run in the opposite order of which they are registered.
{% codetabs name="Ruby", type="rb" -%}
After do |scenario|
# Do something after each scenario.
# The +scenario+ argument is optional, but
# if you use it, you can inspect status with
# the #failed?, #passed? and #exception methods.

if scenario.failed?
subject = "[Project X] #{scenario.exception.message}"
send_failure_email(subject)
end
end
{%- language name="Java", type="java" -%}
{% raw %}
@After
public void afterRunningScenario(Scenario scenario) {
System.out.println("*********** Just finished running scenario: "
+ scenario.getStatus());
}
{% endraw %}
{%- endcodetabs %}

`Around` hooks give you more power than Before and After hooks, allowing you to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Around hooks have caused a lot of pain, and it's a feature we're likely to deprecate and eventually remove. It only exists for ruby. I suggest not documenting it (and perpetuating its use).

actually control how many times the scenario is run. An Around hook is passed
two parameters: an object that represents the scenario and a block of code
that, when called, will run the scenario:

{% codetabs name="Ruby", type="rb" -%}
Around do |scenario, block|
puts "About to run #{scenario.name}"
block.call
puts "Finished running #{scenario.name}"
end
{%- endcodetabs %}

`Around` hooks also accept tags, so you can restrict them to run for only some
scenarios, just like `Before` and `After` hooks. One great trick we’ve seen them used for is to run the same scenario twice under different conditions, like this:

{% codetabs name="Ruby", type="rb" -%}
Around('@run_with_and_without_javascript') do |scenario, block|
Capybara.current_driver = Capybara.javascript_driver
block.call
Capybara.use_default_driver
block.call
end
{%- endcodetabs %}

## Tagged hooks {#tagged-hooks}

Both `Before` and `After` accept a tag expression, which you can use to selectively add the hook to only certain scenarios.

{% codetabs name="Ruby", type="rb" -%}
@admin
Feature: Delete Widgets
...
Before('@admin') do
user = create_user(:admin => true)
login_as user
end
{%- language name="Java", type="java" -%}

@admin
Feature: Delete Widgets
...
{% raw %}
@Before("@admin")
public void logInAsAdmin() {
// Log in as admin user
}
{% endraw %}
{%- endcodetabs %}

Now, to run a scenario when you need to be logged in as an administrator, you just have to tag the scenario with `@admin`, and this code will automatically run before the steps of the scenario.
26 changes: 26 additions & 0 deletions docs/tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Tags

Tags are a way to group Scenarios. They are `@`-prefixed strings and you can place as many tags as you like above `Feature`, `Scenario`, `Scenario Outline` or `Examples` keywords. Space character are invalid in tags and may separate them.

Tags are inherited from parent elements. For example, if you place a tag above a `Feature`, all scenarios in that feature will get that tag.

If you want to tag all the scenarios in a feature at once, just tag the `Feature` element at the top, and all the scenarios will inherit the tag. You can still tag individual scenarios as well.

Similarly, if you place a tag above a `Scenario Outline` or `Examples` keyword, all scenarios derived from examples rows will inherit the tags.

A `Scenario` or `Feature` can have as many tags as you like. Just separate them with spaces:

```
@billing @bicker @annoy
Feature: Verify billing
```

Cucumber can perform different operations before and after each scenario based on what tags are present on a scenario.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant. Remove?


There are three main reasons for tagging scenarios:

* _Filtering_: Cucumber allows you to use tags as a filter to pick out specific scenarios to run or report on. You can even have Cucumber fail your test run if a certain tag appears too many times.
* _Hooks_: Run a block of Ruby code whenever a scenario with a particular tag is about to start or has just finished.
* _Documentation_: You simply want to use a tag to attach a label to certain scenarios, for example to label them with an ID from a project management tool.

See [tagged hooks](hooks.md#tagged-hooks) for more details.