All Projects → cabbage-ex → Cabbage

cabbage-ex / Cabbage

Licence: mit
Story BDD tool for executing elixir in ExUnit

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to Cabbage

karate-runner
VSCode Extension for Karate
Stars: ✭ 23 (-77.45%)
Mutual labels:  gherkin, cucumber
Godog
Cucumber for golang
Stars: ✭ 1,287 (+1161.76%)
Mutual labels:  gherkin, cucumber
gavel-spec
Behavior specification for Gavel, validator of HTTP transactions
Stars: ✭ 105 (+2.94%)
Mutual labels:  gherkin, cucumber
scenari
Clojure BDD library - Executable Specification with Behavior-Driven Development
Stars: ✭ 57 (-44.12%)
Mutual labels:  gherkin, cucumber
bat
Gherkin based DSL for testing HTTP APIs via Cucumber.JS
Stars: ✭ 30 (-70.59%)
Mutual labels:  gherkin, cucumber
vscode-cucumber
Code snippets to write scenarios faster + Syntax highlight for .feature files
Stars: ✭ 24 (-76.47%)
Mutual labels:  gherkin, cucumber
cucumber-react
React components for Cucumber
Stars: ✭ 15 (-85.29%)
Mutual labels:  gherkin, cucumber
Augurk
living documentation on your own terms
Stars: ✭ 38 (-62.75%)
Mutual labels:  gherkin, cucumber
flutter gherkin
A Gherkin parsers and runner for Dart and Flutter which is very similar to cucumber
Stars: ✭ 160 (+56.86%)
Mutual labels:  gherkin, cucumber
gherkin
Pure Rust implementation of Gherkin language (`.feature` file) for Cucumber testing framework.
Stars: ✭ 41 (-59.8%)
Mutual labels:  gherkin, cucumber
cucumber-performance
A performance testing framework for cucumber
Stars: ✭ 28 (-72.55%)
Mutual labels:  gherkin, cucumber
Karate
Test Automation Made Simple
Stars: ✭ 5,497 (+5289.22%)
Mutual labels:  gherkin, cucumber
base project for web automation projects
base project with example for web automation projects with serenity BDD, screenplay and cucumber
Stars: ✭ 17 (-83.33%)
Mutual labels:  gherkin, cucumber
Awesome-Cucumber
A collection of awesome Cucumber and Gherkin-related resources
Stars: ✭ 33 (-67.65%)
Mutual labels:  gherkin, cucumber
mocha-cakes-2
A BDD plugin for Mocha testing framework
Stars: ✭ 44 (-56.86%)
Mutual labels:  gherkin, cucumber
CucumberSwift
A lightweight swift Cucumber implementation
Stars: ✭ 40 (-60.78%)
Mutual labels:  gherkin, cucumber
docs
Cucumber user documentation
Stars: ✭ 110 (+7.84%)
Mutual labels:  gherkin, cucumber
cucumber6-ts-starter
Starter project to write and debug cucumber-js features in TypeScript language
Stars: ✭ 62 (-39.22%)
Mutual labels:  gherkin, cucumber
sonar-gherkin-plugin
SonarQube Cucumber Gherkin Analyzer
Stars: ✭ 33 (-67.65%)
Mutual labels:  gherkin, cucumber
Behat
BDD in PHP
Stars: ✭ 3,696 (+3523.53%)
Mutual labels:  gherkin, cucumber

Cabbage

Coverage Status CircleCI Build Status Hex.pm

(Looking contribution for a better icon!)

A simple addon on top of ExUnit which provides compile time translation of .feature files to exunit tests. Big thanks to @meadsteve and the White Bread project for a huge head start on this project.

Installation

Available in Hex, the package can be installed as:

  1. Add cabbage to your list of dependencies in mix.exs:
def deps do
  [{:cabbage, "~> 0.3.0"}]
end

Example Usage

By default, feature files are expected inside test/features. This can be configured within your application with the following:

config :cabbage, features: "some/other/path/from/your/project/root"

Inside test/features/coffee.feature you might have something like:

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

To translate this to a simple exunit test, all you need to do is provide the translation of lines to steps in the test. Inside test/features/coffee_test.exs (or anywhere you like really).

defmodule MyApp.Features.CoffeeTest do
  # Options, other than file:, are passed directly to `ExUnit`
  use Cabbage.Feature, async: false, file: "coffee.feature"

  # `setup_all/1` provides a callback for doing something before the entire suite runs
  # As below, `setup/1` provides means of doing something prior to each scenario
  setup do
    on_exit fn -> # Do something when the scenario is done
      IO.puts "Scenario completed, cleanup stuff"
    end
    %{my_starting: :state, user: %User{}} # Return some beginning state
  end

  # All `defgiven/4`, `defwhen/4` and `defthen/4` takes a regex, matched data, state and lastly a block
  defgiven ~r/^there (is|are) (?<number>\d+) coffee(s) left in the machine$/, %{number: number}, %{user: user} do
    # `{:ok, state}` gets returned from each callback which updates the state or
    # leaves the state unchanged when something else is returned
    {:ok, %{machine: Machine.put_coffee(Machine.new, number)}}
  end

  defgiven ~r/^I have deposited £(?<number>\d+)$/, %{number: number}, %{user: user, machine: machine} do
    {:ok, %{machine: Machine.deposit(machine, user, number)}} # State is automatically merged so this won't erase `user`
  end

  # With no matches, the map is empty. Since state is unchanged, its not necessary to return it
  defwhen ~r/^I press the coffee button$/, _, state do
    Machine.press_coffee(state.machine) # instead would be some `hound` or `wallaby` dsl
  end

  # Since state is unchanged, its not necessary to return it
  defthen ~r/^I should be served a coffee$/, _, state do
    assert %Coffee{} = Machine.take_drink(state.machine) # Make your `assert`ions in `defthen/4`s
  end
end

The resulting compiled test will be logically equivalent to:

defmodule MyApp.Features.CoffeeTest do
  use ExUnit.Case, async: false

  setup do
    on_exit fn ->
      IO.puts "Scenario completed, cleanup stuff"
    end
    {:ok, %{my_starting: :state, user: %User{}}}
  end

  # Each scenario would generate a single test case
  @tag :integration
  test "Buy last coffee", %{my_starting: :state, user: user} do
    # From the given
    state = %{user: user, machine: Machine.put_coffee(Machine.new, number)}
    # From the and
    state = Map.put(state, :machine, Machine.deposit(machine, user, number))
    # From the when
    Machine.press_coffee(state.machine)
    # From the then
    assert %Coffee{} = Machine.take_drink(state.machine)
  end
end

This provides the best of both worlds. Feature files for non-technical users, and an actual test file written in Elixir for developers that have to maintain them.

Tables & Doc Strings

Using tables and Doc Strings can be done easily, they are provided through the variables under the names :table and :doc_string. An example can be seen in test/data_tables_test.exs and test/features/data_tables.feature.

Running specific tests

Typically to run an ExUnit test you would do something like mix test test/some_test.exs:12 and elixir will automatically load test/some_test.exs for you, but only run the test on line 12. Since the feature files are being translated into ExUnit at compile time, you'll have to specify the .exs file and not the .feature file to run. The line numbers are printed out as each test runs (at the :info level, so you may need to increase your logger config if you dont see anything). An example is like as follows:

# Runs scenario of test/features/coffee.feature on line 13
mix test test/feature_test.exs:13

Developing

Using Docker Compose

A docker-compose.yml is provided for running the tests in containers.

$ docker-compose up

To wipe all _build and deps you can run:

$ docker-compose down -v

If you want to interactive, using standard mix commands, such as updating dependencies:

$ docker-compose run --rm test deps.update --all

Or, if you want to run a single test, that can be accomplished with:

$ docker-compose run --rm cabbage test test/feature_test.exs

Roadmap

  • [x] Scenarios
  • [x] Scenario Outlines
  • [x] ExUnit Case Templates
  • [x] Data tables
  • [x] Executing specific tests
  • [x] Tags implementation
  • [ ] Background steps
  • [ ] Integration Helpers for Wallaby (separate project?)
  • [ ] Integration Helpers for Hound (separate project?)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].