<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Cucumis Sextus

... a Cucumber-like Behavior-Driven Development (BDD) Test Framework for Perl 6.

## State

This is still in development, but already works for most basic cases. There are 
bound to be many bugs, please let me know how you get along.

### Missing Features

* Harness improvements to allow parallel execution
* TAP integration
* Different types of reporting
* Neater printing of featrues/scenarios/steps as they are being executed

## Usage

This is trying to be faithful and compatible to the "consensus" Cucumber 
implementation, which also means that most of this documentation applies
and will also explain background and theory better than I possibly could: 
https://github.com/cucumber/cucumber/wiki/A-Table-Of-Content

Please let me know if there are any surprising discrepancies.

### Basic Feature Files

By default, cucumis will search for feature files under features/*.feature, the 
syntax of these is the same as in other cumumber implementations. Currently only 
basic scenarios are supported, no tables or templates. An example:

    Feature: Basic Calculator Functions
        In order to check I've written the Calculator class correctly
        As a developer I want to check some basic operations
        So that I can have confidence in my Calculator class.

    Scenario: First Key Press on the Display
        Given a new Calculator object
        And having pressed 1
        Then the display should show 1

### Step Definitions

Cucumis will load all .pm6 files under 'step_definitions' in the same directory 
that holds the feature file in question, e.g. "features/step_definitions/StepDefs.pm6":

    unit module StepDefs;

    use CucumisSextus::Glue;

    Given /'a new Calculator object'/, sub () {
        # implement!
    };

    Step /'having pressed' \s* (\d+)/, sub ($num) {
        # implement!
    };

Step definition modules are using semi-keywords from the CucumisSextus::Glue module 
and a regular expression to define step definitions. The "Step" keywords matches any
ype/verb in the scenario steps, and serves as a sort of wildcard. 

When cucumis executes a feature file, it will find the appropriate step definition 
for each step, and execute it. If there is no step definition or there is a problem 
with it, it will report an error.

Note that the step definitions can have arguments that are taken from captures
within the regular expression, as in the "having pressed example above. You can
even use non-capturing groups in the regex and slurpy arguments (quite cool!):


    Step /'having pressed' \s+ (\S+) [\s+ 'and' \s+ (\S+)]*/, sub (+@btns) {
        for @btns -&gt; $b {
            # implement!
        }
    }

Within your glue code, you can use any exception (except X::CucumisSextus::FeatureExecFailure, 
which is to signal problems when trying to run the step, not *within* the step) to signal
a failure. The next steps of the scenario will be skipped, but the remaining scenarios of the 
feature will be executed, as will be other features.

    Then /'the display should be off'/, sub () {
        die "display should be off, but isn't";
    }

### Execution

In order to execute the tests described in a feature file, the "cucumis6" tool can 
be used:

    cucumis6 features

Cucumis will execute your features, producing some more output, and then report the results:

    14 scenarios executed, 4 skipped, 12 succeeded, 2 failed

The return code form the command will only be 0 if there are no problems executing cucumis, 
and if there are no failed scenarios.

### Tags

You can tag your features and scenarios like this:

    @calc @basic 
    Feature: Basic Calculator Functions
        In order to check I've written the Calculator class correctly
        As a developer I want to check some basic operations
        So that I can have confidence in my Calculator class.

    @positive
    Scenario: First Key Press on the Display
        Given a new Calculator object
        And having pressed 1
        Then the display should show 1

And then select only certain features and scenarios (the latter inherit all the 
tags from the corresponding feature as well as have their own tags) when executing 
cucumis:

    cucumis6 --tags=@calc

You can negate the matches with a '~', and OR them together with commas:

    cucumis6 --tags=@calc,@print
    cucumis6 --tags=~@positive

And you can AND them together by repeatedly specifying --tags:

    cucumis6 --tags=@calc --tags@basic

### Background Scenarios

You can define "background" scenarios:

    Feature: Basic Calculator Functions
    In order to check I've written the Calculator class correctly
    As a developer I want to check some basic operations
    So that I can have confidence in my Calculator class.

    Background: Unboxing a new Calculator
        Given a freshly unboxed Calculator
        And having it switched on

    Scenario: First Key Press on the Display
        Given a new Calculator object
        And having pressed 1
        Then the display should show 1
    
    Scenario: Second Key Press on the Display
        Given a new Calculator object
        And having pressed 1
        And having pressed 2
        Then the display should show 12

These background scenarios will get executed before each of the other 
scenarios of the feature. There can only be one background scenario and
it needs to be the first one in the feature.

### Tables

Your steps can contain tabular data:

    Scenario: Separation of calculations
        Given a new Calculator object
        And having successfully performed the following calculations
            | first | operator | second | result |
            | 0.5   | +        | 0.1    | 0.6    |
            | 0.01  | /        | 0.01   | 1      |
            | 10    | *        | 1      | 10     |
        And having pressed 3
        Then the display should show 3

Your step definition code will get the table passed in as a array of 
hashes, in the final parameter after the captures. The keys come from the
first line of the table in your feature file, and you get one entry per 
following row:

    Step /'having successfully performed the following calculations'/, sub (@table) {
        say @table.perl;
    }

would yield:

    [{:first("0.5"), :operator("+"), :result("0.6"), :second("0.1")}, 
     {:first("0.01"), :operator("/"), :result("1"), :second("0.01")}, 
     {:first("10"), :operator("*"), :result("10"), :second("1")}]

### Multiline Data

In a way similar to tables, you can add multiline verbatim data to your step
definitions by starting and ending such a section with three quotes:

    Feature: Basic Calculator Functions
    In order to check I've written the Calculator class correctly
    As a developer I want to check some basic operations
    So that I can have confidence in my Calculator class.

    Scenario: Ticker Tape
        Given a new Calculator object
        And having entered the following sequence
        """
        1 + 2 + 3 + 4 + 5 + 6 -
        100
        * 13 \=\=\= + 2 =
        """
        Then the display should show -1025

Note that while the indentation of the three quotes themselves, like any other line
in a feature file, is not relevant, that indentation is removed from each line in the
multiline data. This also means that your indentation needs to be somewhat conistent 
or cucumis will fail to do so.

The multiline data is passed to your step definition as a single argument after any
captures, just like with tables. Note that you can only use multiline data or tables 
in a step, not both.

### Hooks

You can create "before" and "after" hooks in your glue code, these will be 
executed before and after each scenario respectively. Before hooks will be 
executed in the order they are registered, and after hooks in reverse order. 
Note however that registration order is unpredicatble across multiple glue 
code modules. These hooks get executed for *any* scenario, so you typically 
want to inspect the feature and scenario passed in before doing anything:

    Before sub ($feature, $scenario) {
        if $feature.tags.first(* ~~ 'hooked') {
            # implement!
        }
    }

    After sub ($feature, $scenario) {
        # implement!
    }

### Outlines and Examples

You can write a single scenario and execute it multiple times for different 
sets of input and output values using outlines and examples:

    Scenario Outline: Basic arithmetic
        Given a new Calculator object
        And having keyed &lt;first&gt;
        And having keyed &lt;operator&gt;
        And having keyed &lt;second&gt;
        And having pressed =
        Then the display should show &lt;result&gt;
        Examples:
        | first | operator | second | result |
        | 5.0   | +        | 5.0    | 10     |
        | 6     | /        | 3      | 2      |
        | 10    | *        | 7.550  | 75.5   |
        | 3     | -        | 10     | -7     |

Note that the glue code regular expression has to match the substituted value, 
not the original one from the step text.

### Other Languages

If you want to write your feature files in your native language rather than in
english, you can certianly do that by putting a language directive into the first
line of your feature file:

    #language: hi
    爨ｰ爭も､ｪ 爨ｲ爭�､�: 爨ｮ爭も､ｲ爨ｭ爭も､､ 爨伶､｣爨� 爨歩､ｾ爨ｰ爭財､ｯ
        爨憫､ｾ爨≒､� 爨歩､ｰ爨ｨ爭� 爨歩･� 爨ｲ爨ｿ爨� 爨ｮ爭謂､も､ｨ爭� 爨伶､｣爨� 爨ｵ爨ｰ爭財､� 爨歩･� 爨ｸ爨ｹ爭 爨｢爨も､� 爨ｸ爭� 爨ｲ爨ｿ爨籾､ｾ 爨ｹ爭�
        爨鐘､� 爨ｵ爨ｿ爨歩､ｾ爨ｸ爨� 爨歩･� 爨ｰ爭も､ｪ 爨ｮ爭�､� 爨ｮ爭謂､� 爨歩･≒､� 爨ｬ爭≒､ｨ爨ｿ爨ｯ爨ｾ爨ｦ爭 爨歩､ｾ爨ｰ爭財､ｯ爭金､� 爨歩･ 爨憫､ｾ爨も､� 爨歩､ｰ爨ｨ爨ｾ 爨壟､ｾ爨ｹ爨､爨ｾ 爨ｹ爭も､�
        爨､爨ｾ爨歩､ｿ 爨ｮ爭�､ｰ爭� 爨伶､｣爨閉�爨ｵ爨ｰ爭財､� 爨ｮ爭�､� 爨ｮ爭≒､杳･� 爨ｭ爨ｰ爭金､ｸ爨ｾ 爨ｹ爭金･､
    爨ｪ爨ｰ爨ｿ爨ｦ爭�､ｶ爭財､ｯ: 爨ｪ爭財､ｰ爨ｦ爨ｰ爭財､ｶ爨ｨ 爨ｪ爨ｰ 爨ｪ爭財､ｰ爨･爨ｮ 爨歩･≒､も､憫･ 爨ｦ爨ｬ爨ｾ爨鐘､�
        爨ｪ爭も､ｰ爭財､ｵ爨ｾ爨ｨ爭≒､ｮ爨ｾ爨ｨ 爨鐘､� 爨ｨ爨� 爨伶､｣爨� 爨ｵ爨ｸ爭財､､爭�
        爨扉､ｰ 1 爨ｦ爨ｬ爨ｾ爨ｯ爨ｾ 爨ｹ爭≒､�
        爨�､､爨� 爨ｪ爭財､ｰ爨ｦ爨ｰ爭財､ｶ爨ｨ 1 爨ｦ爨ｿ爨籾､ｾ爨ｨ爨ｾ 爨壟､ｾ爨ｹ爨ｿ爨�

And then write the appropriate step definition code:

    Then /'爨ｪ爭財､ｰ爨ｦ爨ｰ爭財､ｶ爨ｨ' \s+ (\d+) \s+ '爨ｦ爨ｿ爨籾､ｾ爨ｨ爨ｾ 爨壟､ｾ爨ｹ爨ｿ爨�'/, sub ($num) {
        # XXX implement
    }

Note that you could even use Hindi number literals like 爭ｧ instead 
of the arabic ones in the example above, the \d does detect them 
correctly and $num.Int will convert to a number as well!

This should even work for right-to-left languages, but of course
you get the usual problems with shells, editors and the like:

    #language: fa
    ﾙ維顧俑ｯﾛ�: ﾘｹﾙ��鈷ｧﾘｪ ﾘｳﾘｧﾘｯﾙ� ﾙ�ｧﾘｴﾛ雇� ﾘｭﾘｳﾘｧﾘｨ
        ﾘｬﾙ�ｪ ﾘｧﾘｱﾘｲﾛ鈷ｧﾘｨﾛ� ﾘｧﾛ雇�ｩﾙ� ﾚｩﾙ�ｧﾘｳ ﾙ�ｧﾘｴﾛ雇� ﾘｭﾘｳﾘｧﾘｨ ﾘｱﾘｧ ﾘｨﾙ� ﾘｯﾘｱﾘｳﾘｪﾛ� ﾙ�畏ｴﾘｪﾙ� ﾘｧﾙ�
        ﾘｨﾙ� ﾘｹﾙ�畏ｧﾙ� ﾛ顧ｩ ﾘｨﾘｱﾙ�ｧﾙ�� ﾙ�維鈷ｳ ﾚ��ｯ ﾘｹﾙ��鈷ｧﾘｪ ﾘｳﾘｧﾘｯﾙ� ﾘｱﾛ鈷ｧﾘｶﾛ� ﾘｱﾘｧ ﾘｧﾘｱﾘｲﾛ鈷ｧﾘｨﾛ� ﾙ�� ﾚｩﾙ��
        ﾘｪﾘｧ ﾘｧﾘｲ ﾚｩﾙ�ｧﾘｳ ﾙ�ｧﾘｴﾛ雇� ﾘｭﾘｳﾘｧﾘｨﾙ� ﾘｧﾘｷﾙ�雇�ｧﾙ� ﾘｭﾘｧﾘｵﾙ� ﾚｩﾙ��

    ﾘｳﾙ�ｧﾘｱﾛ雇�: ﾘｧﾙ異�雇� ﾘｯﾚｩﾙ�� ﾙ�ｴﾘｱﾘｯﾙ� ﾘｴﾘｯﾙ� ﾘｯﾘｱ ﾘｵﾙ�ｭﾙ� ﾙ��ｧﾛ鈷ｴ
        ﾘｨﾘｧ ﾙ�ｱﾘｶ ﾛ顧ｩ ﾘｴﾛ� ﾘｬﾘｯﾛ鈷ｯ ﾙ�ｧﾘｴﾛ雇� ﾘｭﾘｳﾘｧﾘｨ 
        ﾙ� ﾙ�ｴﾘｱﾘｯﾙ� ﾘｴﾘｯﾙ� ﾛｱﾛｲﾛｳ
        ﾘ｢ﾙ�ｯﾘｧﾙ� ﾘｵﾙ�ｭﾙ� ﾙ��ｧﾛ鈷ｴ ﾘｨﾘｧﾛ鈷ｯ ﾛｱﾛｲﾛｳ ﾘｱﾘｧ ﾙ�ｴﾘｧﾙ� ﾘｨﾘｯﾙ�ｯ

## Feedback and Contact

Please let me know what you think: Robert Lemmen &lt;robertle@semistable.com&gt;
</pre></body></html>