ogurets 3.1.9

  • Readme
  • Changelog
  • Installing
  • 67

ogurets #

ogurets is a Gherkin + Cucumber implementation in Dart, focused on making your life writing tests as easy as possible, with the minimum of boilerplate fuss.

It is a fork of the excellent source base of dherkin2 but as that project appears to be dead and we cannot release any further versions, it has been renamed to ogurets (огурец) because it sounds cool and it means cucumber.

For information on Gherkin syntax and Behavior Driven Development (BDD) as a general topic, please see: http://cukes.info/

This is one of a few projects that will be released under this organisational banner - with Flutter and IntelliJ support.

ogurets (like dherkin2) supports standard syntax, scenario outlines with data tables, examples and hooks. It also adds support for (and preference for) Cucumber Expressions.


This is based on the original work of Dherkin2, along with some modifications made to make it Dart 2 compatible by others.

The current authors are:

an overview of ogurets #

ogurets carries on from dherkin2 in a number of ways:

  • ogurets is based on Dart 2.2+ and is entirely async/await aware. It expects your functions to be async functions.
  • offers support for Cucumber expressions of {string}, {int} and {float} instead of having to write regular expressions.
  • supports an Object (OguretsOpts) that defines what features are run, what steps to use and shared instances
  • supports steps in classes that have positional instances and shared instances passed to them. This allows you to have a global variable that stays for the entire run and ones that get recreated for each session (such as a scenario session). It is a basic form of Dependency Injection.
  • there is an IntelliJ plugin that gives you support for navigation, step creation, run configurations, and displaying the results of test runs.
  • allows overriding of what is actually being run via environment variables (used by the IntelliJ plugin)
  • added support for @Before and @After hooks with optional tags
  • reports allow flexible reporting style. A basic one and an IntelliJ one are included - and you can chain them or have multiple of them as you wish.
  • fields are extracted out of the example rows so you don't have to.

You can still use your existing Dherkin2 style tests and continue by extending with class based tests.

ogurets extensions

  • ogurets-flutter - and extension for Ogurets focused on supporting Flutter.
  • ogurets IntelliJ plugin - a plugin for IntelliJ that extends the Cucumber support in IntelliJ and Android Studio to allow you to easily create steps, run and debug your tests, and navigate through test codebase.

Usage #

Ogurets based Cucumber tests are closely modeled on Java style Step-def classes with annotations. There is @Given, @When, @Then, @And and @But, all of which aid you in writing your standard Cucumber based set of tests.

An example of a Cucumber feature in Ogurets:

Feature: simple addition feature

  Scenario: A simple addition example
    Given I add 4
    And I add 3
    Then the total should be 7

To ensure this test runs, you will need to create a Stepdef class that implements these steps:

import 'package:ogurets/ogurets.dart';

class MyStepdefs {
  @Given(r'I add {int}')
  void iAdd(int toadd) async {
    // Write code here that turns the phrase above into concrete actions


  @Then(r'the total should be {int}')
  void theTotalShouldBe(int total) async {
    // Write code here that turns the phrase above into concrete actions


NOTE: if you are using the IDEA plugin, you can just use Alt-Enter and it will create them for you.

To allow us to use some state which exists only for the scenario, lets go and create ourselves a scenario state class.

class ScenarioState {
  int total = 0;

And get Ogurets to create it for each scenario run and pass it to us, the whole stepdef becoming:

import 'package:ogurets/ogurets.dart';

import '../lib/scenario_state.dart';

class MyStepdefs {
  final ScenarioState state;


  @Given(r'I add {int}')
  void iAdd(int toadd) async {
    state.total += toadd;

  @Then(r'the total should be {int}')
  void theTotalShouldBe(int total) async {
    assert(total == state.total);

When run using Ogurets, this gives something like this:

Feature: simple addition feature # test/features/add.feature:1

	Scenario: A simple addition example # test/features/add.feature:3

		I add 4	 # test/features/add.feature:4

		I add 3	 # test/features/add.feature:5

		the total should be 7	 # test/features/add.feature:6

Scenarios passed: 1

Features passed: 1

You can also use Scenario Outline style Gherkin tests to achieve the same effect, but in a table.

  Scenario Outline: A simple addition example
    Given I add <amt1>
    And I add <amt2>
    Then the total should be <total>
      | amt1 | amt2 | total |
      | 4    | 3    | 7     |

Run #

ogurets can be executed in a number of ways. In all case, you need to ensure the vm-flag --enable-asserts is passed to dart to ensure your assertions throw exceptions. For example:

dart --enable-asserts test/ogurets_run.dart

If you do this from IDEA, it automatically adds it for you.

ogurets Custom Runner

You create a new OguretsOpts and give it your features (individual files or recursed folders) and tell it to run. You can tell it to not fail on missing steps, turn debug on, provide instances that will live across all tests.

NOTE: if you are using the Ogurets IntelliJ IDEA plugin, this will be automatically generated for you.

void main(args) async {
  var def = new OguretsOpts()
   ..instance(new SharedInstance())

  await def.run();

Your classes can be constructed so as to take classes that are either defined in the OguretsOpts or they are dynamically constructed at runtime. If they themselves depend on a class it will cycle through creating the entire tree. "Cucumber Expressions" will be turned into regexs as the code is walked through.


class Expressions {
     ScenarioSession _session;
     @Given("I have a {string} with {float}")
     void strFloat(String s, num f) {
       _session.sharedStepData[s] = f;

NOTE: You cannot include anything in the constructor that it does not know about.

ogurets hooks #

Hooks work largely like you would expect them to. You can:

  • specify a tag or not (in the annotation). If not, then the before or after will run on every scenario triggered.
  • specify instances to be injected, including the ScenarioStatus that holds details about the current scenario. The ScenarioStatus object holds a map called 'augments' which allows you to put in Scenario related things (such as references to screen shots, or json objects or whatever you like) so you will be able to build custom reports that output those things.

There are several hooks that you can use to make your tests run better:

  • @BeforeRun/@AfterRun - these run before and after the run. They are not tagged but they can have an order. The Ogurets Flutter plugin uses them to start and stop the Flutter application.
  • @Before/@After - these run before and after a scenario (regardless of success or failure).
  • @BeforeStep/@AfterStep - these run before and after a step (even on failure). When the AfterStep runs, you are able to determine if the scenario has failed and if so, you can take action.

NOTE: no optional parameters are allowed as there is no "context".

import 'package:ogurets/ogurets.dart';

import 'scenario_session.dart';

class Hooks {
  void beforeEach(ScenarioSession session, ScenarioStatus tracker) {
    session.sharedStepData['before-all'] = 'here';
    tracker.addendum['before-all'] = true; // this will be attached to the scenario object that generates the report

  void afterEach(ScenarioSession session) {
    session.sharedStepData['after-all'] = 'here';

  @Before(tag: 'CukeExpression')
  void beforeExpression(ScenarioSession session) {
    session.sharedStepData['before-expr'] = 'here';

  @After(tag: 'CukeExpression')
  void afterExpression(ScenarioSession session) {
    session.sharedStepData['after-expr'] = 'here';

ogurets tags #

Tags also work as per the Cucumber style, where they can be on a feature or on a scenario. If tags are passed they are specifically honoured, if they aren't then all scenarios will be run.

Using the ~@tag syntax prevents the tagged scenario or feature from being run, leaving all others open. Combining ~@tag and @tags leads to non-deterministic behaviour.

Feature: load the sample data via the api

  Scenario Outline: There should be superusers loaded
    Given the system has been initialized
    And I am logged in as the initialized user
    When I register a new user with email "<email>" and groups "<groups>"
    And complete their registration with name "<name>" and password "<password>" and email "<email>"
    Then the user exists and has superuser groups
    And I can login as user "<email>" with password "<password>"
      | name             | email                  | password    | groups    |
      | Капрельянц Ирина | Ирина@mailinator.com   | password123 | superuser |
      | Irina Southwell  | irina@mailinator.com   | password123 | superuser |
      | Richard Vowles   | richard@mailinator.com | password123 | superuser |


  • running with the command line: --tags @dataload would run all features here,
  • running with --tags @superuserload would run the scenario, ignoring the tag on the feature.
  • running with --tags ~@superuserload would run the scenarios in the feature but it would not run the @superuserload tagged feature.
  • running with --tags ~@dataload would ignore the whole feature and it wouldn't be otherwise examined for positive tags.


Ogurets relies on simple assertions when doing BDD style testing. Dart provides a rich api for doing comparison, so an assertion library like Fest Assert is largely unnecessary.

  @Given("the total should be {int}")
  void totalShouldBe(int amt) async {
    var calcedVal = (_scenarioSession.sharedStepData["add"] as int);
    assert(amt == calcedVal);

The more detailed expect library provide by the Dart Test library is heavily tied to that library and not usable elsewhere.


Library comes with an executable runner script cucumberd in bin/ directory. Create symbolic link in a directory on your path, like /usr/local/bin:

cd /usr/local/bin
ln -s path/to/ogurets/bin/cucumberd.dart cucumberd


cucumberd example/gherkin/test_feature.feature

Note: cucumberd will auto-include all step definitions in steps/ sub-directory. Ability to add steps source locations via command-line arguments is planned.

ogurets style Custom Runner

Alternatively, you might opt for writing your own script:

   library my_bdd_runner;

   import 'package:ogurets/ogurets.dart';
   import 'my_step_defs.dart'; // import stepdefs, mandatory since no auto-scanning happens

   main(args) {

   // write your StepDefs below

Invoke the runner : $ dart my_bdd_runner.dart my_gherkin.feature

Anatomy of a stepdef #

A stepdef is a top-level function annotated with one of Gherkin keywords. Such a function can take any number of positional parameters, and up to three optional named parameters.

@And("I am a table step \"(\\w+?)\"")
i_am_a_table(arg1, {exampleRow, table, out}) {

Table found on the step will be passed in as table. A scenario outline row will be passed in as exampleRow

Output #

Due to asynchronous nature of execution, output of print statements will not appear near the gherkin step that ran them. For that purpose, optional named parameter out will be injected if the stepdef function states that it takes it. Please use the reporters if you wish to override the syntax.

3.1.9 #

  • load steps from disk instead of having to specify them all
  • better reporting
  • timings
  • all updates from tobindh

3.1.8 #

  • added @ignore syntax (tobindh)
  • allowed specification of extra formatters via Opts (tobindh)
  • tidied up logging messages (tobindh)
  • added support for skipped scenarios in reporting

3.1.7 #

  • opened up the intl version to include 0.16 because Flutter master has changed

3.1.6 #

  • added in beforestep/afterstep annotations
  • added moved examples to own directory, turned them into a test.

3.1.5 #

  • logic around tags was causing everything to run even if you specified a scenario name
  • too much print logging

3.1.4 #

  • karthi.kk - reported an issue with tags not working as expected. Tags were not triggering properly on feature level and scenario level as per other cucumber variants.
  • support for ~tags so you can turn off specific tags

3.1.3 #

  • karthi.kk - reported issue with existing dherkin2 table parser which only allowed single word entries in table.

3.1.2 #

  • updated documentation
  • updated the IDEA formatter so it outputs examples correctly
  • ensure each example line in a scenario outline has a separate scenario status so it doesn't prevent other examples from running.

3.1.1 #

  • Introducing ogurets for the first time

1.0.1+1 #

  • Introduced this changelog.

1.0.1 #

  • Upgraded all dependencies.
  • Minimal required Dart SDK is now 2.0.0.
  • Removed log4dart because it is not dart2 compatible. Replaced it with the logging lib from pub.dart.

1.0.0 #

  • The fork removed all future-code and replaced it with async/await. The reason for that is that it can properly be used in dart2 tests.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  ogurets: ^3.1.9

2. Install it

You can install packages from the command line:

with pub:

$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:ogurets/ogurets.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Apr 7, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6

Health suggestions

Format bin/cucumberd.dart.

Run dartfmt to format bin/cucumberd.dart.

Format lib/ogurets.dart.

Run dartfmt to format lib/ogurets.dart.

Format lib/ogurets_core.dart.

Run dartfmt to format lib/ogurets_core.dart.

Fix additional 11 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/gherkin_parser.dart (Run dartfmt to format lib/src/gherkin_parser.dart.)
  • lib/src/model/anotations.dart (Run dartfmt to format lib/src/model/anotations.dart.)
  • lib/src/model/feature.dart (Run dartfmt to format lib/src/model/feature.dart.)
  • lib/src/model/scenario.dart (Run dartfmt to format lib/src/model/scenario.dart.)
  • lib/src/model/step.dart (Run dartfmt to format lib/src/model/step.dart.)
  • lib/src/output/basic_formatter.dart (Run dartfmt to format lib/src/output/basic_formatter.dart.)
  • lib/src/output/console_buffer.dart (Run dartfmt to format lib/src/output/console_buffer.dart.)
  • lib/src/output/delegating_formatter.dart (Run dartfmt to format lib/src/output/delegating_formatter.dart.)
  • lib/src/output/formatter.dart (Run dartfmt to format lib/src/output/formatter.dart.)
  • lib/src/output/intellij_formatter.dart (Run dartfmt to format lib/src/output/intellij_formatter.dart.)
  • lib/src/status/status.dart (Run dartfmt to format lib/src/status/status.dart.)

Maintenance issues and suggestions

Use constrained dependencies. (-20 points)

The pubspec.yaml contains 1 dependency without version constraints. Specify version ranges for the following dependencies: intl.

Maintain an example.

None of the files in the package's example/ directory matches known example patterns.

Common filename patterns include main.dart, example.dart, and ogurets.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.0 <3.0.0
ansicolor ^1.0.2 1.0.2
args ^1.5.0 1.6.0
intl >=0.15.8 0.16.1
logging ^0.11.3+2 0.11.4
sprintf ^4.0.0 4.0.2
Transitive dependencies
path 1.6.4
Dev dependencies
pedantic ^1.9.0