Only this pageAll pages
Powered by GitBook
1 of 25

Concordia

Loading...

Introduction

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Language

Loading...

Loading...

How It Works

Loading...

Loading...

Upgrade

Loading...

Loading...

Loading...

Loading...

Development

Loading...

Loading...

Loading...

Overview of the Language

Overview of the Concordia declarations:

Features and Scenarios

A Featuredefines a desired behavior for the software, a piece of functionality that gives some business value. A Scenario is a high-level usage scenario of a Feature. A Feature can have many Scenarios.

Since Feature and Scenario are business-oriented declarations, they are not used by Concordia Compiler to generate test cases. You can write them freely. Although, we recommend you to use the User Story template for a Feature and the Given-When-Then template for a Scenario. Example:

Feature: Sales Report
  As a manager
  I would like to generate a sales report
  In order to track company sales

Scenario: Daily sales report
  Given that I am authenticated as a manager
  When I open the sales report
    and I choose the option "Daily report"
  Then I see a list with all the today's sales 
    and the total value

This is the User Story template:

  • As a <role>

  • I would like to <goal to perform>

  • In order to <received benefit> (or So that <received benefit>)

And this is the Given-When-Then (GWT) template:

  • Given <some context or precondition>

  • When <some action is carried out>

  • Then <a result or postcondition is observed>

In the GWT template, additional sentences of each kind are written in the next line and receive the prefix and.

Features and Scenarios must have a name, but their description are not required. Thus, you can write the above example like this (although we recommend against):

Feature: Sales Report

Scenario: Daily sales report

Feature files receive the extension .feature. Only one feature per file is allowed.

Variants

A Variant is a test-oriented declaration that describes a possible interaction between a user and the system in order to accomplish a Scenario. You can write more than one Variantfor a same Scenario .

A Variant must use the GWT template and first person singular ("I") in its sentences. Concordia Compiler uses Natural Language Processing (NLP) techniques to understand Variant sentences, aiming to transform them into test cases. Example:

Feature: New User

Scenario: Successful registration

  Variant: Register with a new account
    Given that I am on "https://example.com/register"
    When I fill <#name> with "Bob"
      and I fill <#dateOfBirth> with "11/30/1990"
      and I enter with "bob@example.com" in <#email>
      and I inform "m123456" in <#pass>    
      and I type "m123456" in <#confirmation>
      and I click <#ok>
    Then I see "Welcome, Bob" 

Concordia Compiler understands the sentences from line 7 to11 as being variations of the same action, fill.

Of course, the vocabulary is limited. Although, you can extend it whether you need (by adding new synonyms to a specific dictionary file). Actions and common variations are documented and suggestions are always welcomed.

In the sentences above, the values were denoted between quotation marks, e.g. "bob@example.com". Numeric values are also accepted and do not need quotation marks. Example: 97.

Widgets (of the user interface) are written between < and >. Example: <#email>. Concordia adopts the well-known CSS query selectors to locate widgets, regardless the user interface (its plugins convert them to the format adopted by the testing framework). You can also use XPath (although some plug-ins may not accept it). Examples:

  • # (hashtag) to find a widget by its id. Example: #email

  • . (dot) to find a widget by its class, if applicable. Example: .colorful

  • @ (at) to find a widget by its name. Example: @pass

  • ~ (tilde) to find a widget by its mobile name, if applicable. Example: ~pass

  • no prefixed characters, to find a widget by its type. Example: input

  • // (double slash) to find a widget by its XPath. Example: //table/tbody/tr[1]

Whether you are testing a web application, you may find Katalon-Concordia useful. It's a browser extension - available for Google Chrome and Mozilla Firefox - that extends Katalon Recorder to save a recorded interaction as Variant sentences. Using it may reduce the time needed to locate the widgets of an existing application.

States

A State is denoted by a text between tilde (~), such as ~a state~, and must be written inside Variant sentences only. Example:

Then I have a ~user logged in~

A Variant can both produce or require states. A State is produced by a Then sentence, like in the prior example. A State is required by a Given or a When sentence. For instance:

Given that I have ~user logged in~

By declaring a required State, you're establishing a dependency among the current Variant and the ones that can produce it. Since that State is often produced by a Variant from another Feature, you have to import the corresponding Feature file. Concordia Compiler will only search for states from imported Feature files.

When transforming Variants into Test Cases, Concordia Compiler will:

  • Remove any (Then) sentences with a produced State; and

  • Replace any (Given or When) sentences with a required State by sentences from the Variant that can produce it.

Whether there are different Variants that can produce a (same) required State, Concordia Compiler will be able to combine each of them with the current Variant, aiming to produce Test Cases that explore different execution paths. For more information, please read the section State Based-Combination.

Example

Let's say that we have a simple Login feature like this:

Feature: Login

Scenario: Sucessful login

  Variant: Login with username and password
    Given that I am on the [Login Screen]
    When I enter with "bob" in {Username}
      and I enter with "123456" in {Password}
      and I click on {OK}
    Then I see "Welcome"
      and I have ~user logged in~


Constants:
  - "Login Screen" is "/page"
  
UI Element: Username

UI Element: Password

UI Element: OK
  - type is button

Now let's suppose that a user has to be logged in to access its account details:

import "login.feature"

Feature: My Account

  Scenario: See my account data
  
    Variant: Show basic data by default
      Given that I have ~user logged in~
        and I am on the [Account Screen]
      Then I see {User} with "bob"
        and I see {Name} with "Robert Downey Jr"


Constants:
  - "Account Screen" is "/account"
        
UI Element: User

Concordia Compiler will produce my-account.testcase with a Test Case like the following, that includes steps from both the features:

import "my-account.feature"

@scenario(1)
@variant(1)
Test Case: See my account data - 1
  Given that I am on the "/login"
  When I enter with "bob" in <username>
    and I enter with "123456" in <password>
    and I click on <ok>
  Then I see "Welcome"
  Given that I am on the "/account
  Then I see <user> with "bob"
    and I see <name> with "Robert Downey Jr"

Concordia Compiler can optimize the combination among Features in order to reduce the amount of produced test cases and, therefore, the total execution time. You can also opt to get full coverage - which is ideal before releasing a feature.

Test Cases

A Test Case represents a test case produced for a certain Variant . Concordia Compiler can generate many Test Case declarations from a same Variant, each one covering different states, input combinations and oracles. The generation considers the following declarations:

  • Variant

  • states

  • UI Element

  • Constants

  • Table

  • Database

The simplest Test Case is one whose sentences are exactly equal to the Variant's. That's the case when the Variant does not use other declarations and it explicits all the input test data to use.

For comparison, whether we simply remove with "Bob"from the sentenceWhen I fill <#name> with "Bob" , Concordia Compiler will generate a pseudo-random value to complete the sentence, and it will be like this: When I fill <#name> with "A~!39esljdns so2u1 *ns%".

Concordia Compiler uses a single seed to generate pseudo-random numbers in its algorithms and values. Everytime it runs, a new seed is produced. You can set the seed using the CLI parameter --seed. By setting the seed, the compiler will pick the same paths and produce the same values - which is desirable for reproducing the same behavior in the application under test, but not for discovering new defects.

Don't worry about writing Test Cases. Write Variants and let Concordia generates the Test Cases for you.

UI Elements

A UI Element represents a user interface element and can denote its expected behavior through properties.

Although a Widget is easy to declare, it can have some shortcomings:

1) It can make a sentence hard to read, specially when it uses XPath or CSS locators.

For example, the sentence

When I click on <//*[@id="section1"]/div[1]/div[2]>

does inform what the action really means. The same sentence with a UI Element reference becomes

When I click on {Continue}

Then the UI Element can be declared as:

UI Element: Continue
  - locator: //*[@id="section1"]/div[1]/div[2]  

Here locator is a property that denotes how to find it in the UI.

2. It can be hard to maintain. When a Widget appears in more than one Scenario and its locator needs to change (e.g. you have changed it in the UI), you need to search and replace all its occurrences in the document. With a UI Element, you just need to change the property locator.

3. It does not offer resources for test generation other than its locator.

A UI Element offers properties that can describe the behavior related to it. These properties are used to infer the test data and test oracles to generate.

Example:

UI Element: Net Price
  - minimum value is 10.00
    Otherwise I see "Net Price must be greater than U$ 10"    

Concordia Compiler infers 6 possible test cases from the above declaration, applying different testing techniques.

These are the UI Element properties:

  • id or locator ⇨ how to locate the widget

  • type ⇨ widget type, like textbox, button, etc.

  • editable ⇨ whether the UI Element is editable (or not)

  • data type ⇨ data type of an editable UI Element

  • required⇨ whether the UI Element is required (or not)

  • format⇨ data format, denoted by a regular expression

  • value⇨ defines how the value is produced

  • minimum value ⇨ defines how the minimum value is produced

  • maximum value ⇨ defines how the maximum value is produced

  • minimum length ⇨ defines how the minimum length is produced

  • maximum length ⇨ defines how the maximum length is produced

By default, declaring a UI Element without properties is the same as declaring it with:

  • id or locator equal to the UI Element name in camelCase (e.g., "Net Price" becomes "netPrice"). The adopted case is configurable.

  • type equal to textbox

  • data type equal to string

Concordia Compiler is able to guess some properties from the others. For instance, editable is enabled when type is a widget capable of receiving input data; data type can be inferred from any attributed value; etc.

Another example:

UI Element: Profession
  - value is in [ "Programmer", "Tester", "Analyst" ]

Concordia Compiler infers 4 possible test cases from the above declaration, applying different testing techniques.

Please see the language reference for more details. Let's proceed with the other declarations for now.

Import

A Import declaration allows you to import declarations from another .featurefile. Example:

Import "login.feature"

Imported declarations are Feature, Constants, Table, Database, and UI Element.

Constants

A Constants block defines one or more constants. Every Constant holds an immutable value that is accessible through the declared name. Example:

Constants:
  - "Register Page" is "https://example.com/register"
  - "Coupon Number" is 12345

Constants are accessed by their name between [ and ]. Example:

    Given that I am on the [Register Page]
    When I fill {Coupon} with [Coupon Number]

Constants are global declarations and cannot have duplicate names. You can use them in UI Element properties and Variant sentences.

Table

A Table declares values in rows and columns to use in UI Element properties. Example:

Table: Customer
  | name           | age |
  | Ada Lovelace   | 36  |
  | Dennis Ritchie | 70  |
  | Donald Knuth   | 82  |
  | George Boole   | 49  |
  | Niklaus Wirth  | 83  |
  
  
UI Element: Name
  - value comes from "SELECT name FROM [Customer]"
    Otherwise I see "Customer not found."

Concordia Compiler infers 4 possible test cases from the above declaration, applying different testing techniques.

Note that SQL is used to select values from the declared table, which is denoted between [ and ] (like Constants). Table names are global and share the same namespace as Constant names.

Database

A Database provides a way to indicate a connection to an existing database or file. Example:

Database: AcmeDB
  - type is "mysql"
  - name is "acme"
  - host is "http://127.0.0.1"
  - username is "tester"
  - password is "testing123"
  
  UI Element: Name
  - value comes from "SELECT name FROM [AcmeDB.customer]"
    Otherwise I see "Customer not found."

Concordia Compiler infers 4 possible test cases from the above declaration, applying different testing techniques.

SQL is used to select values from a table or view from the declared database, which is denoted between [ and ] . Its table or view names are separated by a dot (.). Database names are global and share the same namespace as Tables and Constants.

Test Events

In order to set the execution environment up, testers can define events that can run database commands or command-line scripts. These events can occur before or after Scenarios or Features:

  • Before Each Scenario: executes before every test of each Scenario of the current Feature.

  • After Each Scenario: executes after every test of each Scenario of the current Feature.

  • Before Feature: executes once, before all the tests of the current Feature.

  • After Feature: executes once, after all the tests of the current Feature.

  • Before All: executes once, before all the tests of the application under test.

  • After All: executes once, after all the tests of the application under test.

Test Events are written like Variants, using Given-When-Then. Since they usually perform actions, it is very likely to useWhen in most sentences. Example:

Before Feature:
   Given that I connect to [AcmeDB]
   When I run the script 'DELETE FROM customer'
     and I run the script 'INSERT INTO customer ( name, age ) VALUES ( "Alice", 20 ), ( "Bob", 30 )'     
     and I run the command 'rmdir log'

Commands and database scripts are denoted between apostrophe (').

Test Coverage and Techniques

Time is a crucial constraint in software development and software teams often need to focus their test efforts on the most important application paths.

⚠ UNDER CONSTRUCTION ⚠

In software testing, test coverage is some kind of metric that helps you to understand what parts of your application (or code) are exercised by your tests. The number of feasible paths through them grows exponentially with an increase in application size and can even be infinite in the case of applications with unbounded loop iterations. That is a problem called path explosion problem. Concordia Compiler deals with it by providing sets of combination and selection strategies, and trying to achieve full path coverage over time.

Test Coverage

  • All the Features, Scenarios, and Variants are covered by default.

  • The CLI parameter --files can filter the .feature files to be considered.

  • The CLI parameter --ignore can indicate the .feature files to be ignored, when a directory is given.

  • The tag @ignore can be used to mark a Feature or Variant to be ignored by the test generator. However, it can still be used by other Features or Variants.

  • The tag @importance (e.g., @importance( 8 )) can be used to denote the importance of a Feature. CLI parameters --sel-min-feature and --sel-max-feature can then be used to filter the features to be considered by the test generator. Example: concordia --sel-min-feature 7 makes the compiler considers the features with importance value of 7 or above. By default, all the features receive an importance value of 5.

  • Variants are selected and combined using State-based Strategies (see below).

  • All the UI Elements constraints are covered by default, using a set of Testing Techniques (see below).

State-based Strategies

In Concordia, you can declare a State in a Variant sentence using a text between tile (~), like this:

Given that I have ~payment method selected~

There are three types of State:

  1. Precondition: when declared in a Given sentence;

  2. State Call: when declared in a When sentence;

  3. Postcondition: when declared in a Then sentence.

Both Preconditions and State Calls are considered required States. That is, they denote a dependency of a certain State of the system that needs to be executed. A Precondition needs to be executed before the Variant starts, and a State Call needs to be executed during the Variant's execution.

A Postcondition is a produced State, that is, a state of the system produced by a successful execution of a Variant. Therefore, whether something goes wrong during a Variant's execution, it will not produce the declared State.

When the current Variant requires a State, Concordia Compiler will look for imported Features' Variants able to produce it. To generate complete Test Cases for the current Variant, it will:

  1. Select the Variants to combine;

  2. Generate successful test scenarios for the selected Variants;

  3. Select the successful test scenarios to combine;

  4. Generate (successful and unsuccessful) test scenarios for the current Variant;

  5. Combine the selected successful test scenarios with the test scenarios of the current Variant;

  6. Transform all the test scenarios into test cases (i.e., valued test scenarios).

Steps 1 and 3 can adopt different strategies. Concordia Compiler let's you:

  • Parameterize how the Variants will be selected, using --comb-variant; and

  • Parameterize how the successful test scenarios will be combined, using --comb-state.

Variant selection

Available strategies for --comb-variant:

  • random: Selects a random Variant that produces the required State. That's the default behavior;

  • first: Selects the first Variant that produces the required State;

  • fmi: Selects the first most important Variant (since two Variants can have the same importance value) that produces the required State;

  • all: Selects all the Variants that produce the required State.

Example:

npx concordia --comb-variant=all

State combination

Available strategies for --comb-state:

  • sre: Single random of each - that is, randomly selects a single, successful test scenario of each selected Variant. That's the default behavior;

  • sow : Shuffled one-wise - that is, shuffles the successful test scenarios than uses one-wise combination.

  • ow: One-wise selection;

  • all: Selects all the successful test scenarios to combine.

Example:

npx concordia --comb-state=all

Full vs random selection

Strategies that use random selection can take different paths every time they are used. Furthermore, they reduce considerably the amount of generated paths - i.e., it avoids "path explosion" - and thus the amount of produced test cases.

Full-selection strategies can be used for increase path coverage. Although, it also increases the needed time to check all the paths, which may be undesirable for frequent tests.

By default, Concordia Compiler uses random selection strategies.

Testing Techniques

Concordia Compiler can infer input test data from Variants, UI Elements, Constants, Tables, and Databases. The more constraints you declare, the more test cases it generates.

Adopted techniques to generate input test data include:

  • Boundary-value analysis

  • Equivalence partitioning

  • Random testing

  • Special cases

These are well-known, effective black-box testing techniques for discovering relevant defects on applications.

Data Test Cases

We call Data Test Cases those test cases used to generate input test data. They are classified into the following groups: RANGE, LENGTH, FORMAT, SET, REQUIRED, and COMPUTED. The group COMPUTEDis not available on purpose, since a user-defined algorithm to produce test data can have bugs on itself. Thus, one should provide expected input and output values in order to check whether the application is able to correctly compute the output value based on the received input value.

Every group has a set of related data test cases, applied according to the declared constraints and selected algorithms:

Group

Data Test Case

Description

RANGE

LOWEST_VALUE

The lowest value for the data type, e.g., lowest integer

RANDOM_BELOW_MIN_VALUE

A random value below the minimum value

JUST_BELOW_MIN_VALUE

The value just below the minimum value, considering the data type and decimal places if applicable

MIN_VALUE

Exactly the minimum value

JUST_ABOVE_MIN_VALUE

The value just above the minimum value, considering the data type and decimal places if applicable

ZERO_VALUE

Zero (0)

MEDIAN_VALUE

The median between the minimum value and the maximum value

RANDOM_BETWEEN_MIN_MAX_VALUES

A random value between the minimum value and the maximum value

JUST_BELOW_MAX_VALUE

The value just below the maximum value, considering the data type and decimal places if applicable

MAX_VALUE

Exactly the maximum value

JUST_ABOVE_MAX_VALUE

The value just above the maximum value, considering the data type and decimal places if applicable

RANDOM_ABOVE_MAX_VALUE

A random value above the maximum value

GREATEST_VALUE

The greatest value for the data type, e.g., greatest integer

LENGTH

LOWEST_LENGTH

An empty string

RANDOM_BELOW_MIN_LENGTH

A string with random characters and random length, less than the minimum length

JUST_BELOW_MIN_LENGTH

A string with random characters and length exactly below the minimum length

MIN_LENGTH

A string with random characters and length exactly equal to the minimum length

JUST_ABOVE_MIN_LENGTH

A string with random characters and length exactly above the minimum length

MEDIAN_LENGTH

A string with random characters and length equal to the median between the minimum length and the maximum length

RANDOM_BETWEEN_MIN_MAX_LENGTHS

A string with random characters and random length, between the minimum length and the maximum length

JUST_BELOW_MAX_LENGTH

A string with random characters and length exactly below the maximum length

MAX_LENGTH

A string with random characters and length exactly equal to the maximum length

JUST_ABOVE_MAX_LENGTH

A string with random characters and length exactly above the maximum length

RANDOM_ABOVE_MAX_LENGTH

A string with random characters and random length, greater than the maximum length

GREATEST_LENGTH

The greatest length supported for a string (see Notes)

FORMAT

VALID_FORMAT

A value that matches the defined regular expression

INVALID_FORMAT

A value that does not match the defined regular expression

SET

FIRST_ELEMENT

The first element in the defined set or query result

RANDOM_ELEMENT

A random element in the defined set or query result

LAST_ELEMENT

The last element in the defined set or query result

NOT_IN_SET

A value that does not belong to the defined set or query result

REQUIRED

FILLED

A random value

NOT_FILLED

Empty value

COMPUTED

RIGHT_COMPUTATION

A value generated by the defined algorithm

WRONG_COMPUTATION

A value different from that generated by the defined algorithm

Maximum length for random string values

By default, the maximum length for randomly-generated string values is 500. This value is used for reducing the time to run test scripts, since long strings take time to be entered.

You can set maximum length using the CLI parameter --random-max-string-size. Example:

npx concordia --random-max-string-size=300

You can also set it in the configuration file (.concordiarc) by adding the property randomMaxStringSize. Example:

"randomMaxStringSize": 300

Properties vs Data Test Cases

Data Test Cases (DTC) are selected for every declared UI Element and its properties. The more properties you declare for a UI Element, the more data you provide for Concordia Compiler to generate DTC.

Example of some evalutations:

  • When no properties are declared, FILLED and NOT_FILLED are both applied and considered as valid values;

  • When the property required is declared, NOT_FILLED (empty) is considered as an invalid value;

  • When the property value is declared:

    • if it comes from a set of values (inclusing a query result), all the DTC of the group SET are applied;

    • otherwise, ...

  • When the property minimum value is declared:

There is more logic involved for generating these values. ...

Example 1

Let's describe a user interface element named Salary :

UI Element: Salary
  - data type is double

When no property is defined or only the property data typeis defined,

We defined the property data type as double, since the default data type is string.

Since few restrictions were made, Salary will be tested with the test cases of the group REQUIRED:

  1. FILLED: a pseudo-random double value is generated;

  2. NOT_FILLED: an empty value will be used.

Now let's add a minimum value restriction.

UI Element: Salary
  - data type is double
  - minimum value is 1000.00
    Otherwise I must see "Salary must be greater than or equal to 1000"

Some tests of the group RANGE are now applicable:

  1. LOWEST_VALUE: the lowest possible double is used

  2. RANDOM_BELOW_MIN_VALUE: a random double before the minimum value is generated

  3. JUST_BELOW_MIN_VALUE: a double just below the minimum value is used (e.g., 999.99)

  4. MIN_VALUE: the minimum value is used

  5. JUST_ABOVE_MIN_VALUE: a double just above the minimum value is used (e.g., 1000.01)

  6. ZERO_VALUE: zero (0) is used

Since 1000.00 is the minimum value, the data produced by the tests 1, 2, 3, and 6 of the group VALUE are considered invalid, while 4 and 5 are not. For these tests considered invalid, the behavior defined in Otherwise, that is

    Otherwise I must see "Salary must be greater than or equal to 1000"

is expected to happen. In other words, this behavior serves as test oracle and must occur only when the produced value is invalid.

Unlike this example, when the expected system behavior for invalid values is not specified and a test data is considered invalid, Concordia expects that test should fail. In this case, it generates the Test Case with the tag @fail.

Now let's add maximum value restriction:

UI Element: Salary
  - data type is double
  - minimum value is 1000.00
    Otherwise I must see "Salary must be greater than or equal to 1000"
  - maximum value is 30000.00
    Otherwise I must see "Salary must be less than or equal to 30000"

All the tests of the group RANGE are now applicable. That is, the following tests will be included:

  1. MEDIAN_VALUE: the median between the minimum and the maximum values

  2. RANDOM_BETWEEN_MIN_MAX_VALUES: a pseudo-random double value between the minimum and the maximum values

  3. JUST_BELOW_MAX_VALUE: the value just below the maximum value

  4. MAX_VALUE: the maximum value

  5. JUST_ABOVE_MAX_VALUE: the value just above the maximum value

  6. RANDOM_ABOVE_MAX_VALUE: a pseudo-random double above the maximum value

  7. GREATEST_VALUE: the greatest possible double

The tests from 5 to 7 will produce values considered invalid.

Example 2

Let's define a user interface element named Profession and a table named Professions from which the values come from:

UI Element: Profession
  - type is select
  - value comes from "SELECT name from [Professions]"
  - required

Table: Professions
  | name       |
  | Lawyer     |
  | Accountant |
  | Dentist    |
  | Professor  |
  | Mechanic   |

Applicable test are:

  • FILLED

  • NOT_FILLED

  • FIRST_ELEMENT

  • RANDOM_ELEMENT

  • LAST_ELEMENT

  • NOT_IN_SET

The first two tests are in the group REQUIRED. Since we declared Profession as having a required value, the test FILLED is considered valid but NOT_FILLED is not. Therefore, it is important to remember declaring required inputs accordingly.

The last four tests are in the group SET. Only the last one, NOT_IN_SET, will produce a value considered invalid.

Example 3

In this example, let's adjust the past two examples to make Salary rules dynamic and change according to the Profession.

Firstly, we add two columns the the Professions table:

Table: professions
  | name       | min_salary | max_salary |
  | Lawyer     | 100000     |  900000    |
  | Accountant |  90000     |  800000    |
  | Dentist    | 150000     |  900000    |
  | Professor  |  80000     |  500000    |
  | Mechanic   |  50000     |  120000    |

Then, we change the rules to retrieve the values from the table:

UI Element: Salary
  - data type is double
  - minimum value comes from the query "SELECT min_salary FROM [Professions] WHERE name = {Profession}"
    Otherwise I must see "The given Salary is less than the minimum value"
  - maximum value comes from the query "SELECT max_salary FROM [Professions] WHERE name = {Profession}"
    Otherwise I must see "The given Salary is greater than the maximum value"

The reference to the UI Element {Profession} inside the query, makes the rules of Salary depend on Profession. Every time a Profession is selected, the minimum value and the maximum value of Salary changes according to the columns min_salary and max_salary of the table Professions.

Using a Plug-in

Concordia Compiler uses plug-ins for:

  1. setting the testing environment up;

  2. generating and executing test scripts;

  3. converting and reporting test results.

Every plug-in can generate test scripts for a different testing framework or programming language.

Plug-ins

Name (concordialang-...)

Target platform

Needs Java?

RTS*

web

No

No

web

No

No

web

Yes, Java 8+

Yes

Android, iOS, Windows

It depends**

Yes

Notes:

  • (*) RTS means "Requires a Testing Server", that is, if it requires a testing server to run the test scripts (e.g., Selenium Standalone).

  • (**) Appium requires Java for testing web-based mobile applications or using the Android SDK.

  • codeceptjs-testcafe uses the frameworks CodeceptJS and TestCafé, and works with probably any browser.

  • codeceptjs-playwright uses the frameworks CodeceptJS and Playwright,

    requires Node 10.14 or above, and works with Chromium, Firefox, and Safari.

  • codeceptjs-webdriverio uses the frameworks CodeceptJS and WebDriverIO, and works with Chrome, Firefox, IE, and Edge.

  • codeceptjs-appium uses the frameworks CodeceptJS and Appium, and requires some additional configuration to work.

  • codeceptjs-testcafe and codeceptjs-playwright are only available for Concordia Compiler 2 or above.

Installation

Use --plugin-install plus the plug-in name. Example:

npx concordia --plugin-install codeceptjs-testcafe

You can also use NPM for installing a plug-in. In this case, you must prefix the plug-in name withconcordialang- . Example: npm install -D concordialang-codeceptjs-testcafe.

Upgrade

Just uninstall the plug-in and then install it again. Example:

npx concordia --plugin-uninstall codeceptjs-playwright
npx concordia --plugin-install codeceptjs-playwright 

How to use a plug-in

Concordia has the following plug-in commands:

  • plugin-install to install a plug-in

  • plugin-uninstallto uninstall a plug-in

  • plugin-serve to start a testing server using the plug-in

  • plugin to use a plug-in

  • plugin-info to show information about a plug-in

  • plugin-list to list installed plug-ins

All but the latter command (plugin-list) require a plug-in name.

👉 Whether you have a configuration file with the property plugin defined, you can omit the plugin name from a command. Example:

{
  "plugin": "codeceptjs-playwright"
}

Commonly used commands

You can omit the argument <plugin> if you have a configuration file with the property "plugin" defined.

Starting a testing server

Some plug-ins (WebDriverIO, Appium) require a testing server to execute test scripts. A testing server controls a browser or an emulator during tests.

We recommend to open a new terminal/console and then start the testing server:

npx concordia --plugin-serve <plugin>

Naturally, you must replace <plugin> with the plugin name.

The testing server will remain open. To stop it later, type Ctrl + C.

Generating and executing test scripts

Whether your plug-in needs a testing server, start it beforehand.

npx concordia --plugin <plugin>

Generating test scripts without executing them

You can use --no-run to avoid running test scripts and use --no-result to avoid reading the last report with test results. Test scripts will be generated but not executed.

npx concordia --plugin <plugin> --no-run --no-result

Executing existing test scripts (without generating them)

You can use --no-script to avoid generating test scripts. Only existing test scripts will be executed.

npx concordia --plugin <plugin> --no-script

See also

  • Configuration file

  • Commands for plug-ins

  • Creating a plug-in

Using Databases

Concordia to retrieve test data or to set the testing environment up before or after running test scripts.

Installation

Installing

To reduce the number of downloaded packages, Concordia Compiler 2 does not install database drivers by default anymore - as version 1 did.

Use --db-install plus the driver name. Example:

Available driver names:

Database drivers are installed as development dependencies of your application.

You can also install or uninstall them with NPM, prefixing the driver name with database-js-. Example: npm i -D database-js-mysql.

Uninstalling

Use --db-uninstall plus the driver name. Example:

Upgrading

Just uninstall and then install it again.

Usage

A is global declaration. You must declare it once and then import its file in other features. Example:

A database can be referenced inside UI properties and Test Events by its name between [ and ]. Example: [My DB]. To reference a database table, separate the table name from the database name with with a dot (.) - e.g. [My DB.profession]. Let's see an example:

Instead of reinventing the wheel, Concordia uses SQL to query and modify databases and files. Even JSON and INI files can be queried with SQL.

In the example above, the property value from the UI Element "Profession" indicates that its (valid) values are retrieved from the table "profession" that belongs to the database declared as "My DB". The test event Before Each Scenario was declared to connect to the database, clean the table "profession", and then insert new records that the UI Element "Profession" will use.

See also

Understanding Concordia

Imagine a solution in which you can write software requirements using an Agile-style, restricted natural language and it automatically generates for you using effective testing techniques such as , , and and it can also use test data from . Well, that's Concordia. Its solution is composed by a metalanguage and a compiler.

Concordia is also who was the personification of "concord" or "agreement". The idea is that the metalanguage help users, stakeholders, and software teams to discussing and reaching an agreement about the software requirements. A shared understanding about the requirements is essential to create the right software.

Concordia metalanguage

Concordia allows you to focus on writing your application's business rules and defining its expected behavior for when users interact with it. Stakeholders, business analysts, testers, and programmers can now discuss the application using a single language, a single source of truth. Business-focused and testing-focused declarations are clearly separated, so you can discuss technological details only with the interested parties.

With Concordia, you can write both and requirements, although it produces only functional test cases. Because it adopts -style declarations, you don't have to write it so formally (like usually do) and you can use plain text - which is easy to evolve with your codebase.

We invite you to and see how it is easy to understand. It is currently available in English (en) and Portuguese (pt).

Concordia compiler

Concordia compiler mix techniques with and to understand declarations in Concordia Language - which uses restricted natural language. After detecting declarations, it infers test scenarios, test data, and test oracles to generate test cases in a framework-independent format (see the ). Finally, it uses a plug-in created for a specific testing framework to generate test scripts (that is, source code), execute them and read their results. You don't need to write code. And the compiler checks your declarations for logic errors and other possible problems.

Follow the to see it in action! 😉

Concordia plug-ins

Concordia compiler uses plug-ins to transform Abstract Test Cases (ATS) into test scripts - that is, into source code. Every plug-in can be implemented to generate source code for a specific programming language and testing framework - in Java, Python, Go, PHP or whatever the language you prefer. The generated source code is not tied to JavaScript or TypeScript.

See the and for your favorite programming language and testing framework.

Related things

Tools

  • is a browser extension for Chrome and Firefox that converts recordings from (which is a - that is, it records all the actions that you perform while interacting with the application under test in order the reproduce them later) to Variant sentences. That's very handful for discovering elements' identification in web applications (e.g., their id properties or their ) and obtaining Variant sentences with the corresponding interaction.

  • is a command-line tool that generates User Interface Prototypes (UIP) from Concordia features. It can help discussing features with stakeholders and accelerating their construction. Currently there is a customizable plug-in for HTML-based interfaces.

  • is a command-line tool that generates an HTML page with an interactive graph that shows features files' relationships.

Publications

  1. PINTO, Thiago Delgado. Unifying Agile requirements specification quality control and implementation conformance assurance. 2018. Doctoral Thesis. Pontifical Catholic University of Rio de Janeiro, Informatics Department, 2018.

  2. PINTO, Thiago Delgado; COSTA, Pablo Veiga; GONÇALVES, Willian Inácio. User Interface Prototype Generation from Agile Requirements Specifications written in Concordia. 2019. WebMedia'19: Proceedings on the 25th Brazilian Symposium on Multimedia and the Web, Rio de Janeiro, 2019. ACM. DOI:

Actions

Abstract actions recognized through Natural Language Processing

Concordia Language contains a set of meta-actions that can be used by different testing frameworks for generating test scripts. Concordia Compiler uses Intent Recognition (yes, like chatbots do) to understand sentences and extract the desired action to perform. Later these actions are sent to testing frameworks for conversion into commands.

Concordia actions are recognized in Variants, Test Cases, and Test Events.

The following list presents the available actions and gives some examples on how to use them in sentences. We expect that you do not have to memorize them but, instead, see the things you can do. Try to write the sentences the way you speak, using first person singular (I) . When there is a UI Element in the sentence, embrace it with { and }, like {this}. The compiler will tell you whether it cannot understand some sentence you wrote. If you think it should have understood something, . We'll try to augment the compiler's vocabulary to understand it the next time.

accept

Accepts a browser message or app message.

amOn

Indicates a webpage or screen in which it is expected to be at.

append

Adds a value to an element.

attachFile

Attaches a file. It selects a file and confirms its choice (e.g., clicks Open).

cancel

Cancels a browser message or app message.

check

Checks a checkbox.

clear

Empties an input field or browser cookie

click

Clicks on something in the screen.

close

Closes a tab, a set of tabs, or an app (mobile only).

connect

Connects to a database.

The next sentence is for only:

disconnect

Disconnects from a database.

The next sentence is for only:

doubleClick

Performs a double click on something.

drag

Drags and drops something to a widget.

fill

Indicates that a field is being filled. If desired, a value can be given. Otherwise, a value will be generated for the corresponding Test Case.

fill + target

hide

Hides something.

install

Installs an app.

maximize

Maximizes a window or the browser.

move

Moves the mouse cursor to a place or element.

open

Opens something

press

Presses a key or key combination, separated by comma.

Some special keys (case sensitive!):

  • Add

  • Alt

  • ArrowDown or Down arrow

  • ArrowLeft or Left arrow

  • ArrowRight or Right arrow

  • ArrowUp or Up arrow

  • Backspace

  • Command

  • Control

  • Del

  • Divide

  • End

  • Enter

  • Equals

  • Escape

  • F1 to F12

  • Home

  • Insert

  • Meta

  • Multiply

  • Numpad 0 to Numpad 9

  • Pause

  • Pagedown or PageDown

  • Pageup or PageUp

  • Semicolon

  • Shift

  • Space

  • Subtract

  • Tab

pull

Extracts a device's resource from a path.

refresh

Refreshes/reloads the current page.

remove

Removes/uninstall an app by its internal name (mobile only).

resize

Resizes a window.

rightClick

Performs a right click on something.

run

Runs a console command or a database script (SQL command).

👉 Available for only.

👉 Commands and SQL scripts must be declared between single quotes ('), in a single line.

👉 SQL scripts must reference their database.

SQL Syntax

Concordia Compiler uses to access databases and files through SQL-like commands. The supported SQL syntax may vary from one database to another. Please see the .

JSON and CSV as databases: INSERT accepts JSON objects or arrays as values. Example:

Excel and Firebase databases: Syntax similar to JSON and CSV databases. However, it has some limitations, as pointed out in :

SQL commands are limited to SELECT, UPDATE, INSERT and DELETE. WHERE works well. JOINs are not allowed. GROUP BY is not supported. LIMIT and OFFSET are combined into a single LIMIT syntax: LIMIT [offset,]number

INI databases: INSERT and DELETE are not supported yet by . UPDATE example:

SQLite databases: Currently uses that doesn't persist the changes in the file (only in memory).

saveScreenshot

Takes a screenshot an saves into a file.

scrollTo

Scrolls to a certain element.

see

Indicates that something can be seen. You can also negate the sentence to indicate something cannot be seen.

select

Selects a value for an element.

shake

Shakes the device - MOBILE ONLY.

swipe

Performs a swipe action - MOBILE ONLY

switch

  • Switches to a certain iframe and back to the application page; OR

  • Switches to a certain tab; OR

  • Switches an app to native mode or web mode - MOBILE ONLY.

NOTE: When switching to an iframe, all the commands that follow it will be applied to it.

tap

Performs a tap on an element - MOBILE ONLY

uncheck

Unchecks a checkbox.

wait

Wait for something.

codeceptjs-testcafe
codeceptjs-playwright
codeceptjs-webdriverio
codeceptjs-appium
npx concordia --db-install mysql

Driver Name

Database

note

csv

CSV files

xlsx

Excel files

firebase

Firebase

ini

INI files

json

JSON files

Already installed

mysql

MySQL

adodb

MS Access

Windows only

mssql

MS SQL Server

postgres

PostgreSQL

sqlite

SQLite

npx concordia --db-uninstall mysql
Database: My DB
  - type is "mysql"
  - host is "127.0.0.1"
  - name is "acme"
  - username is "tester"
  - password is "secret"
  
Database: Another DB
  - type is "json"
  - path is "./db.json"
import "db.feature"

# ... other declarations here ...

UI Element: Profession
  - value comes from "SELECT name FROM [My DB.profession]"
    Otherwise, I see "Profession not found."
  - required
    Otherwise, I see "Please select the profession."
    
Before Each Scenario:
  Given that I connect to [My DB]
  When I run the script 'DELETE FROM profession'
    and I run the script 'INSERT INTO profession (name) VALUES ("Enginner"), ("Accountant")' 
    
can use databases
Database
Supported syntax
Declaring Tables
functional test scripts
equivalence partitioning
boundary-value analysis
random testing
combinatorial testing
databases and files
the name of a roman goddess
metalanguage
functional
non-functional
Agile
Use Cases
take a look at the language
compiler
machine learning
natural language processing
produced test cases
Quick Start
available plug-ins
how to create a plug-in
Katalon-Concordia
Katalon Recorder
capture-replay tool
XPath
CLUI
cc-graph
https://doi.org/10.1145/3323503.3360639
 # Simple alert
 When I accept the alert

 # Alert with a message
 When I accept the alert "Do you want to continue?"

 # Confirmation dialog
 When I accept the confirmation

 # Confirmation dialog with a message
 When I accept the confirmation "Do you want to continue?"

 # Popup dialog
 When I accept the popup

 # Popup dialog with a message
 When I accept the popup "Are you sure?"

 # Prompt dialog
 When I accept the prompt

 # Prompt dialog with a message
 When I accept the prompt "What's your name?"
 # URL
 Given that I am on "http://concordialang.org"

 # Contant
 Given that I am on [Some Page]
 # Append a value to a UI Element
 When I append "Foo" to {Foo}
 When I append 100 to {Bar}
 When I append [My Contant] to {Zoo}

 # Append a value to a UI literal
 When I append "Bar" to <#foo>
 When I append 200 to <#foo>
 When I append [My Contant] to <#zoo>
 When I attach the file "/path/to/file" to {Foo}
 When I attach the file [My File] to {Foo}

 When I attach the file "/path/to/file" to <#bar>
 When I attach the file [My File] to <#bar>
 When I cancel the alert

 When I cancel the confirmation

 When I cancel the popup

 When I cancel the prompt
 When I check {Foo}

 When I check <#bar>
 When I clear {Foo}

 When I clear <#bar>

 When I clear the cookie "app"

 When I clear the cookie [App Cookie]
 When I click on {Foo}

 When I click on <#bar>

 When I click on "Some Text"

 When I click on [Value From Contant]
 When I close the current tab

 When I close the other tabs

 # Mobile only
 When I close the app
 When I connect to the database [TestDB]
 When I disconnect from the database [TestDB]
When I double click {Foo}

 When I double click <#bar>

 When I double click "Some Text"

 When I double click [My Contant]
 When I drag {Foo} to {Bar}

 When I drag <#foo> to <#bar>
 When I fill   {Foo}
 When I inform {Foo}
 When I enter  {Foo}
 When I type   {Foo}


 When I fill {Foo} with "foo"
 When I fill {Foo} with [My Contant]
 When I fill <#bar> with "bar"
 When I fill <#bar> with 3.1415


 When I type "bar" in {Foo}
 When I type "foo" in <#bar>
 When I type 3.1416 in {Zoo}
 When I type [My Contant] in <#zoo>
 # Hides the device's keyboard - Mobile only
 When I hide the keyboard
 When I install the app "com.example.android.myapp"
 When I maximize the window
 When I move the cursor to {Foo}
 When I move the cursor to <#bar>

 When I move the cursor to {Foo} at 100, 200
 # Opens the device's notifications panel - Mobile only
 When I open the notifications panel
 When I press "Enter"
 When I press "Control", "Alt", "Delete"
 When I press "Control", "S"
 # Mobile only
 When I pull "/storage/emulated/0/DCIM/logo.png" to "some/path"
 When I refresh the page
 When I refresh the current page

 When I reload the page
 When I reload the current page
 # Mobile only
 When I remove the app "com.example.android.myapp"
 When I resize the window to 600, 400
 When I right click {Foo}
 When I right click <#bar>
 When I right click "Some Text"
 When I right click [Contant]
 # Run a command in the console/terminal
 
 When I run the command 'rmdir foo'
 When I run the command './script.sh'
 When I run the command [My Command]
 
 # Run a SQL scripts in a database
 
 When I run the script 'INSERT INTO [MyDB].product ( name, price ) VALUES ( "Soda", 1.50 )'
 When I run the script 'INSERT INTO [MyDB].Users( UserName, UserSex, UserAge ) VALUES ( "Newton", "Male", 25 )'
 When I run the script 'INSERT INTO [MyDB].`my long table name`( `long column`, `another long column`) VALUES ("Foo", 10)'
 
 When I run the script 'UPDATE [MyDB].Users SET UserAge=26, UserStatus="online" WHERE UserName="Newton"'
 When I run the script 'UPDATE [MyDB].`my long table name` SET `long column` = "Bar" WHERE `another long column` = 70'
 
 When I run the script 'DELETE FROM [MyDB].Users WHERE UserName="Newton"'
 When I run the script 'DELETE FROM [MyDB].`my long table name` WHERE `another long column` = 70'
 When I run the script 'INSERT INTO [MyDB] VALUES { "name": "Mary", "surname": "Jane", "age": 21 }'
 When I run the script 'UPDATE [MyDB] SET age = 22 WHERE name = "Mary"'
 When I save a screenshot to "foo.png"

 When I take a photo to "bar.png"
 When I scroll to <#foo>
 When I scroll to {Bar}
# Some text
 
 Then I see "Some Text"
 Then I see 3.1416
 Then I see [Some Contant]
  
 Then I do not see "Some Text"
 Then I don't see [Some Contant]
 
 Then see the text "Some Text"
 Then I don't see the text "Some Text"


# UI Element or a UI literal

 Then I see {Foo}
 Then I don't see <#bar> 

        
# Value is/isn't inside a UI Element or a UI literal

 Then I see "hello" in {foo}
 Then I see "world" in <#bar>
 
 Then I don't see "hello" in {foo}
 Then I don't see "world" in <#bar> 
 
 Then I do not see {Foo} with "hello"
 Then I don't see <bar> with "world"
 
 
# Attribute from a UI Element or UI literal 
 
 Then I see {Foo} with the attribute "maxlength" valued "200"

 Then I see the attribute "type" of <#bar> to be "text"


# CSS class or Style - WEB ONLY

 Then I see {Foo} with the class "primary-button"

 Then I see {Foo} with the style "color: blue"


# UI Element or ui literal is/isn't enabled

 Then I see {Foo} is enabled
 Then I see <#bar> is enabled
 
 Then I do not see {Foo} is enabled
 Then don't see <#bar> is enabled
 
 
# UI Element or ui literal is/isn't checked

 Then I see {Foo} is checked
 Then I see <#bar> is checked
 
 Then I do not see {Foo} is checked
 Then don't see <#bar> is checked


# Title

 Then I see "Some Text" in the title
 Then I don't see [My Constant] in the title
 
 Then I see the title with "foo"
 Then I don't see the title with [My Constant]
 
 
# URL 

 Then I see the url "/foo"
 Then I don't see the url "/bar"
 
 
# Cookie

 Then I see the cookie "foo"
 Then I don't see the cookie [My Cookie]
 

# App is installed/not installed - MOBILE ONLY

 Then I see that the app "com.example.android.myapp" is installed
  
 Then I see that the app "com.example.android.myapp" is not installed


# An activity - MOBILE ONLY

 Then I see that the current activity is ".HomeScreenActivity"
 
 # Device locked/unlocked - MOBILE ONLY
 
 Then I see that the device is locked
 
 Then I see that the device is locked
 
 # Device orientation - MOBILE ONLY
 
 Then I see that the orientation is landscape
 Then I see that the orientation is portrait
  
 When I select "foo" in {Foo}
 When I select [Contant] in <#bar>
 When I shake the device
 When I shake the phone
 When I shake the tablet
 # To a certain position
 When I swipe <#io.selendroid.myapp:id/LinearLayout1> to 100, 200
 
 # An UI Element/literal to another
 When I swipe {Foo} to {Bar}
 When I swipe <#foo> to <#bar>
 
 # Down
 When I swipe <#io.selendroid.myapp:id/LinearLayout1> down
 
 # Up
 When I swipe <#io.selendroid.myapp:id/LinearLayout1> up
 
 # Left
 When I swipe <#io.selendroid.myapp:id/LinearLayout1> left
 
 # Right
 When I swipe <#io.selendroid.myapp:id/LinearLayout1> right
 
# IFRAME

# To the first iframe

 When I switch to the iframe
 
# To a certain iframe
 
 When I switch to the iframe {My Frame}
 When I switch to the iframe <#frame1>
 
# To an iframe inside another iframe

 When I switch to the iframe {SubFrame 1} inside {Frame 1}
 When I switch to the iframe <#subframe1> inside <#frame1>
 
# Back to the application page

 When I switch to the application
 When I switch to the page  
  
# TAB

 When I switch to the next tab
 When I switch to the previous tab
 When I switch to the tab 3
 
 
 # MOBILE-WEB SWITCHING
 
 # To native app
 When I switch to native
 # To web app
 When I switch to web
 
  When I tap {Confirm}
  When I tap <~confirm>
 When I unckeck {Foo}
 When I uncheck <#bar>
 
 # Unchecks an element inside another element
 
 When I uncheck {Foo} in <#bar>
# -------
# ELEMENT
# -------

# An element

 When I wait for {Foo}
 When I wait for <#bar>
  
# An element to hide
 
 When I wait {Foo} to hide
 When I wait <#bar> to hide

# An element to be enabled
   
 When I wait {Foo} to be enabled
 When I wait <#bar> to be enabled
 
# An element to be visible
   
 When I wait {Foo} to be visible
 When I wait <#bar> to be visible

# An element to be invisible (same as to hide)
   
 When I wait {Foo} to be invisible
 When I wait <#bar> to be invisible

# Value inside element

 When I wait for the value "foo" in {Foo}
 When I wait for the value [My Constant] in <#bar>


# ----
# TEXT
# ----

 When I wait for the text "Foo"


# ----
# URL
# ---- 
 
 When I wait for the url "/foo"


# -------
# SECONDS
# -------

# Seconds

 When I wait 1 second
 When I wait 2 seconds
 
# Seconds for an element
 
 When I wait 1 second for {Foo}
 When I wait 5 seconds for <#bar>

# Seconds for an element to hide
 
 When I wait 1 second for {Foo} to hide
 When I wait 5 seconds for <#bar> to hide

# Seconds for an element to be enabled
 
 When I wait 1 second for {Foo} to be enabled
 When I wait 5 seconds for <#bar> to be enabled
 
# Seconds for an element to be visible
 
 When I wait 1 second for {Foo} to be visible
 When I wait 5 seconds for <#bar> to be visible

# Seconds for an element to be invisible (same as to hide)
 
 When I wait 1 second for {Foo} to be invisible
 When I wait 5 seconds for <#bar> to be invisible         
 
# Value inside element

 When I wait 1 second for the value "foo" in {Foo}
 When I wait 5 seconds for the value [My Constant] in <#bar>     
                                          
# Text
 
 When I wait 3 seconds for the text "Foo"
 
# URL
 
 When I wait 3 seconds for the url "/foo"
 
please tell us
Test Events
Test Events
Test Events
database-js
documentation of the corresponding driver
its documentation
database-js-ini
database-js-sqlite
sql.js

Configuration file

Concordia Compiler can use a configuration file in JSON format named .concordiarc. You can generate it by running the following command:

npx concordia --init

You'll be asked about the desired configuration and then the file will be saved.

Example:

{
    "language": "pt",
    "directory": "docs/features",
    "plugin": "codeceptjs-testcafe",
    "dirScript": "test/e2e",
    "dirResult": "test/e2e/output"
}

Configuration file's properties are similar to CLI parameters. The example above defines: "pt" (meaning "Portuguese") as the default language; the directory "docs/features" for features and test cases; the plug-in "codeceptjs-testcafe" for generating test scripts; the directory "test/e2e" for test scripts; and the directory "test/e2e/output" for output files such as report files and screenshots.

CLI options take precedence over values from the configuration file

File-related options

directory

Type

Default value

CLI option

string

"." (current dir)

--directory

Directory to search for .feature and .testcase files.

Example:

{
  "directory": "./features"
}

recursive

Type

Default value

CLI option

boolean

true

--recursive

Use recursive directory search.

Example:

{
  "recursive": false
}

files

Type

Default value

CLI option

string or string array

(none)

--files

Files to consider, instead of considering directory. The files must be separated by colon.

Example:

{
  "files": "/path/to/file1.feature,/other/file2.feature"
}

Another example:

{
  "files": [
    "/path/to/file1.feature",
    "/other/file2.feature"
  ]
}

We recommend you to configure the property directory whether your project can have new files.

ignore

Type

Default value

CLI option

string or string array

(none)

--ignore

Files to ignore, considering the parameter directory. The files must be separated by colon. Example:

{
  "ignore": [
    "/path/to/file1.feature",
    "/other/file2.feature"
  ]
}

extensions

To-Do

encoding

Type

Default value

CLI option

string

"utf8"

--encoding

File encoding of the files. Accepted values are:

  • utf8 or utf-8

  • latin1

  • ascii

  • ucs2 or ucs-2

  • utf16le or utf-16le

Naturally, the files must be edited with the given file encoding.

Language-related options

To-Do

Plug-in related options

To-Do

Processing-related options

To-Do

Generation-related options

To-Do

Strategy-related options

To-Do

Category

Option

Data Type

Default value

Description

Files

directory

string

none

Directory to search for specification and test case files

recursive

boolean

true

Recursive directory search

encoding

string

"utf-8"

Default file encoding

extensions

array of string

[ ".feature" ]

File extensions to search

ignore

array of string

[]

Files to ignore

files

array of string

[]

Files to consider, instead of considering directory

Language

language

string

"en"

Default specification language

Plug-in

plugin

string

none

Plug-in to use

Processing

verbose

boolean

false

Verbose output

compileSpecification

boolean

true

Whether it is desired to compile the specification

generateTestCase

boolean

true

Whether it is desired to generate test case files

generateScript

boolean

true

Whether it is desired to generate test script files

executeScript

boolean

true

Whether it is desired to execute test script files

analyzeResult

boolean

true

Whether it is desired to analyze test script results

dirTestCase

string

same as features'

Output directory for test case files

dirScript

string

"./test"

Output directory for test script files

dirResult

string

"./output"

Output directory of test script results

lineBreaker

string

OS' default

Character(s) used to break lines in text files

Generation

caseUi

string

"camel"

String case used to identify UI Elements when their ids are not defined. Possible values are "camel", "pascal", "snake", "kebab", or "none".

caseMethod

string

"snake"

String case used for test scripts' methods. Possible values are "camel", "pascal", "snake", "kebab", or "none".

tcSuppressHeader

boolean

false

Whether it is desired to suppress header comments in test case files

tcIndenter

string

" "

Character(s) used as indenter for test case files

seed

string

current date and time

Randomic seed used by all the algorithms

randomMinStringSize

integer

0

Minimum size for random strings

randomMaxStringSize

integer

500

Maximum size for random strings

randomTriesToInvalidValue

integer

5

Tries to generate random values that are not in a set of values

Strategies

combVariant

string

"random"

Algorithm to select and to combine the Variants with the state needed by a certain Variant. Options are: "random" to pick a random Variant, "first" to pick the first one, "fmi" to pick the first most important, or "all" to combine them all.

combState

string

"sre"

Algorithm to select and to combine the Test Scenarios of every State of the selected Variants. Options are: "sre" to select a random Test Scenario of every State, "sow" to use the shuffled one-wise algorithm, "ow" to use the one-wise algorithm, or "all" to combine them all.

combInvalid

string

integer

"smart"

Number of UI Elements that will receive invalid data test cases at a time, e.g. 1. String options are "none" for no invalid values, "smart" to let the compiler decide, "random" to select a random number of UI Elements, "all" to select all the invalid values.

combData

string

"sow"

Algorithm to combine data test cases. Options are: "sre" to select a random data test case to combine, "sow" to use the shuffled one-wise algorithm, "ow" to use the one-wise algorithm, or "all" to combine them all.

Command Line Interface

CLI

Basic syntax is:

concordia [dir] [options]

where:

  • A parameter between[ and ] means that it is optional.

  • [dir] is the directory that contains your .feature files. Whether it is not informed, the tool searches all the subdirectories from the current path.

  • [options] changes how the tool behaves.

You can run concordia --help to see all the command line interface (CLI) options.

You need to use npx before the commands if you opted for a local installation.

Configuration

--config

Indicates a configuration file

Alias: -c

concordia --config /path/to/.concordiarc

By default the configuration file is loaded from the current directory.

--init

Creates a configuration file and optionally installs plug-ins and databases.

concordia --init

This command asks about your preferences. By hitting Enter without giving an answer, it will select the suggested (default) value. You can use Up and Down to navigate the answers and hit Enter to select it. For multiple selection (when available), hitSpace.

By using a configuration file (e.g. .concordiarc) you avoid informing the configured parameters in the console/terminal. For instance, whether plugin is defined in the configuration file, you don't need to inform --plugin anymore.

CLI options take precedence over values from configuration files.

--save-config

Add CLI parameters to the configuration file

The following example will consider the given directory and add it to the configuration file:

concordia --save-config --directory ./features

Directories and files

--directory

Indicates the directory that has .feature and .testcase files.

Alias: -d

When not given, it will search the current directory and all subdirectories recursively.

We strongly recommend to use it or set it in the configuration file.

Example:

concordia --directory ./features

This is equivalent to:

concordia ./features

You can use it with --no-recursive to disable recursive search.

--file

Specifies .feature files to consider

Aliases: -f, --files

Files must be separated by comma.

concordia --file "file1.feature,/path/to/file2.feature"

Whether the command also informs a directory (e.g. --directory), it searches the files inside the directory. Example:

concordia ./feature --file "f1.feature,f2.feature"

The example above will search for ./feature/f1.feature and ./feature/f1.feature.

--ignore

Specify .feature files to ignore when a directory is informed

Alias: -i

Files must be separated by comma.

concordia ./feature --ignore "f3.feature,f4.feature"

--no-recursive

Disables recursive search when a directory is informed

concordia ./features --no-recursive

Output directories

The directories will be used by a plug-in. We strongly recommend that you specify them in a configuration file.

--dir-result

Specifies the directory for test reports and screenshots.

Alias: -O

concordia --dir-result output

--dir-script

Specifies the directory for test script files.

Alias: -o

concordia --dir-script test

Language and locale

--language

Sets the default language to consider.

Alias: -l

The language code must have only 2 characters and needs to be one of the available languages.

concordia --language pt

--language-list

Lists the available language codes.

concordia --language-list

--locale-list

Lists the available locales.

concordia --locale-list

Processing and output

--just-script

Just generates test scripts

concordia --just-script

--just-spec

Just verifies specification files

concordia --just-spec

--just-test-case

Just generates test cases

concordia --just-script

--just-run

Just execute test script files

concordia --just-run

--no-script

Avoids generating test scripts

concordia --no-script

--no-spec

Avoids processing specification files

concordia --no-spec

--no-test-case

Avoids generating test cases

concordia --no-test-case

--no-result

Avoids reading test scripts' results

concordia --no-result

--no-run

Avoids running test scripts

concordia --no-run

Use -x to combine --no-run and --no-result

concordia -x

--verbose

Uses a verbose output

concordia --verbose

Test script execution

These parameters require a plugin (--plugin) and some plug-ins may not support them.

--instances

Number of parallel instances to execute.

Alias: -I

concordia --instances 2

--headless

Executes browsers in headless mode.

Alias: -H

concordia --headless

--script-file

Sets one or more test script files to execute

Aliases: -F, --script-files

Files must be separated by comma.

concordia --script-file "test1.js,test2.js"

--script-grep

Sets a text or regular expression to filter the files to execute

Alias: -G

concordia --script-grep "Sales"

--target

Sets target browsers or platforms to execute

Alias: -T

Browser or platforms must be separated by comma.

concordia --target "chrome,firefox,edge"

Plug-in

You can omit the prefix concordialang- from plug-in names. For instance, concordialang-codeceptjs-playwright becomescodeceptjs-playwright.

--plugin

Uses the given plug-in (if installed)

Alias: -p

concordia --plugin <plugin>

You can use it with -x to avoid running test scripts and reading their output:

concordia -p <plugin> -x

--plugin-about

Shows information about an installed plug-in

Alias: --plugin-info

concordia --plugin-info <plugin>

--plugin-install

Installs a plug-in

concordia --plugin-install <plugin>

--plugin-list

Lists installed plug-ins

concordia --plugin-list

--plugin-serve

Starts a testing server for a plug-in

Alias: -S

concordia --plugin-serve <plugin>

The testing server will keep running. Thus, it's a good idea to open a separate terminal/console for it. To stop it later, type Ctrl + C.

--plugin-uninstall

Uninstalls a plug-in

concordia --plugin-uninstall <plugin>

Database

See Using Databases for the list of available databases.

--db-install

Installs a database driver

concordia --db-install <database>

--db-list

Lists installed databases

concordia --db-list

--db-uninstall

Uninstalls a database driver

concordia --db-uninstall <database>

Random generation

--random-max-string-size

Maximum random string size to generate, when free values are allowed.

The default value is 500 .

concordia --random-max-string-size 100

--random-min-string-size

Minimum random string size to generate, when free values are allowed.

The default value is 0 .

concordia --random-min-string-size 1

--random-tries

Random tries to generate invalid values.

When there is a set of valid values and any value different from those in the set is considered an invalid, random generation is used to produce an invalid value. This parameter defines how many tries to take. Usually it gets on the first try.

The default value is 5 .

concordia --random-tries 10

--seed

Sets a random seed

concordia --seed="example"

Concordia Compiler can use random selection in its algorithms. By default, it generates the seed using the current date and time. Using the same seed makes the algorithms produce the same output (e.g., same values and paths). While that's interesting for reproducing a past behavior, we don't recommend it for finding new defects. Using new seeds, Concordia Compiler will select different test data, test oracles, and test paths over time.

You can also set the algorithms to use, in order to avoid random selection. Full combination (therefore full coverage of the requirements) can be achieved and it is recommend for complete checking before a new release. However, it may take some time to execute.

Combination strategies

--comb-data

--comb-invalid

--comb-state

--comb-variant

File formats and extensions

You probably don't need to use them, unless you're facing problems to read files.

--line-breaker

Sets the character(s) used for breaking lines.

Since by default the line breaker is detected automatically, this command may not be useful for you in most cases.

concordia --line-breaker "\n"

Note on line breakers:

  • Linux uses "\n"

  • MacOS uses "\r"

  • Windows uses "\r\n"

--encoding

Sets the expected file encoding

Alias: -e

The default is utf8. Possible values are:

  • ascii

  • latin1

  • ucs2 or ucs-2

  • utf16le or utf-16le

  • utf8 or utf-8

concordia --encoding latin1

Information

--about

Shows information about the compiler.

concordia --about

--help

Shows the available commands

concordia --help

--newer

Verify if there is a newer version.

concordia --newer

--version

Shows the current version.

concordia --version

Migration Guide

Migrations are only needed when upgrading to a major version. See Versions and Upgrade for more information.

To upgrade to a major version:

  1. Uninstall the current version, e.g.: npm uninstall -D concordialang

  2. Install the new version, e.g.: npm install -D concordialang

  3. Now proceed as described below (depending on your current version).

Note: For a global installation, replace -D with -g.

From 1.x to 2.x

1. Update your plug-in

Concordia 2 has a new plugin API, not compatible with plug-ins for Concordia 1. So uninstall your current plug-in and install a new one. Example:

npx concordia --plugin-uninstall codeceptjs-webdriverio
npx concordia --plugin-install codeceptjs-webdriverio

Alternatively, you can install one of the new plug-ins then change your configuration file to use it. Example:

npx concordia --plugin-uninstall codeceptjs-webdriverio
npx concordia --plugin-install codeceptjs-playwright
npx concordia --plugin codeceptjs-playwright --save-config

2. Install database drivers

Whether your Concordia specification access a database, you have to install the corresponding database driver. Concordia 2 does not install them by default anymore, as Concordia 1 did, aiming to reduce the amount of downloaded dependencies.

Concordia 2 has a new CLI option --db-install to help with that. Example:

npx concordia --db-install mysql

See Database Drivers to install the proper driver(s) for your application.

From 0.x to 1.x

1. Update your configuration file, if needed

Whether you project has a configuration file .concordiarc, open it with a text editor. If the file has a property "plugin" with the value "codeceptjs", you must change it to "codeceptjs-webdriverio".

2. Install the new plug-in

You can install any of the available plug-ins, currently codeceptjs-webdriverio or codeceptjs-appium. Example:

 concordia --plugin-install codeceptjs-webdriverio

See also

  • Information about the breaking changes

  • Concordia's version numbering

How to Upgrade

Versioning

Concordia Compiler's versions are based on Semantic Versioning.

Although Semantic Versioning is conceived for APIs instead of for applications, we adopt a very similar convention. Thus, changes become predictable and you can know, from the version numbers, when a version is no more compatible with a previous version.

Given a version MAJOR.MINOR.UPDATE:

  • MAIOR is increased when the Compiler or the Language is no more compatible with the previous version.

  • MINOR is increased when adding functionality in a backwards-compatible manner.

  • UPDATE is increased when there are fixes, little changes or little novelties - all of them backwards-compatible.

Examples:

  • 0.2.0 is compatible with 0.1.0

  • 0.1.1 is compatible with 0.1.0

  • 1.0.0 is not compatible with 0.2.0

Upgrade

NPM upgrades without breaking compatibility (when MINORorUPDATE changes).

For migrating a MAJOR version (e.g., 1.x to 2.x) please read our Migration Guide.

To upgrade a local installation:

npm upgrade concordialang

To upgrade a global installation:

npm upgrade -g concordialang

Actions vs APIs

This page presents Concordia actions and their corresponding commands for some frameworks.

Help us improving this page. Send us a message on Slack or open an Issue at GitHub. 💖

👉 Under construction.

Concordia

Action [+target]

Appium

CodeceptJS

Cypress

Playwright

Puppeteer

TestCafé

amOn

amOnPage

goto

check

checkOption

check

clear + element

clearField

N/A

clear + cookie

clearCookie

clearCookies

click

click

doubleClick

doubleClick

dblclick

fill

fill

N/A

focus

move

moveTo

moveCursorTo

trigger

hover

hover

hover

press

press

refresh

refreshPage

reload

resize

resizeWindow

setViewportSize

rightClick

rightClick

saveScreenshot

saveScreenshot

screenshot

scrollTo

scrollTo

scrollTo

select

selectOption

selectOption

switch + element

switchTo

N/A

switch + next tab

switchToNextTab

N/A

switch + previous tab

switchToPreviousTab

N/A

tap

tap

N/A

type

type

wait + seconds

wait

N/A

wait + element

waitForElement

waitForElement

uncheck

uncheckOption

uncheck

Breaking Changes

Information about breaking changes.

From 1.x to 2.x

Please read Issue #56.

From 0.x to 1.x

Concordia Compiler

  1. It changed the way that all the plug-in operations are handled. See Issue #34 for details.

  2. The behavior of the following plug-in commands were affected:

COMMAND

NOW

BEFORE

plugin-list

It lists all the plug-ins installed for the application.

It listed all the plug-ins available in the compiler.

plugin-install

It installs a plug-in and its dependencies.

Only the plugin's dependencies were installed, since the plug-in was embedded in the compiler.

plugin-uninstall

It uninstalls a plug-in and its dependencies using npm.

Only the plugin's dependencies were uninstalled, since the plug-in was embedded in the compiler.

plugin-info

It shows information about a plug-in installed for the application.

It shows information about a plug-in available in the compiler.

plugin-serve

It starts a testing server using a plug-in installed for the application.

It started a testing server available in the compiler.

👉 See the Command Documentation to know the commands' syntax.

Concordia Language

No compatibility breaks.

Other relevant changes

External tools used by plug-ins are now installed locally, per project, instead of installed globally. Their direct execution (without using Concordia) is now possible through NPX. For instance, the command codeceptjs run test.js must now be executed as npx codeceptjs run test.js. This change also allows the installation of different versions of external tools, when needed.

FAQ

  1. Were there any changes in commands' syntaxes?

    No, there were not.

  2. Is my configuration file still compatible?

    It depends. All the properties are still compatible, except for "plugin". Whether your configuration file has that property, you should update it.

  3. Is it possible now to install or uninstall a plug-in with NPM ?

    Yes, it is possible to do both now.

What's Next

Ideas and proposals

Work in progress and issues:

  • Kanban Board (GitHub)

  • Issues (GitHub)

Logo

Yes, this project does not have a logo yet 😱. Designers interested in helping us (for free 🙏), please contact us on our Slack Channel or open an Issue.

The logo should reflect the idea behind the language:

Concordia is the name of a roman goddess who was the personification of "concord" or "agreement". The idea is that the metalanguage may help users, stakeholders, and the software team to discuss and to reach an agreement about the software requirements. This shared understanding is essential to the software construction.

The tool generates test cases and test scripts that verify if the application under test meets the specified functional requirements. Therefore, the idea of "verification" or "testing" could be in the logo.

Plug-ins

Interested? See how to create a plug-in.

👉 Our next goal is a plugin for Cypress.

Suggestions:

  • JavaScript and friends: Cypress (web), MacacaJS (web, mobile, desktop)

  • PHP: Codeception (web)

  • Java: Selenium (web), Robotium (android), AssertJ Swing (desktop)

  • Ruby: Capybara (web), Calabash (mobile applications developed with Xamarin)

  • Python: Selenium (web)

  • C++: QtTest (desktop), DUnit (desktop)

  • Delphi: DUnitX (desktop), DUnit (desktop)

  • Other programming languages or frameworks are welcome! 💖

Language

Variant Background

This language construction is part of Concordia Language since the first version, but it was not implemented yet.

A Variant Background defines steps that must be executed before all the Variants of a certain Scenario. Example:

Feature: Search

  Scenario: Simple Search
  
    Variant Background:
      Given that I visit the [Search Page]
      When I fill {Search} with "Hello"
      
    Variant: Search by clicking on Go
      When I click on {Go}
      Then I see "Hello World!"
      
    Variant: Search by hitting Enter
      When I press "Enter"
      Then I see "Hello World!"      

MOTIVATION: It allows to keep initial, repeated steps in a common place.

Constant names without quotation marks

Like this:

Constants:
  - Net Price is 10.0
  - hello is "hello"

MOTIVATION: Simpler syntax.

Visual comparison

Please see Issue #27.

MOTIVATION: It allows to perform visual comparison and detect related bugs.

File content comparison

To use the characters """ (three quotation marks) to denote a text content to be compared. Example:

  ...
  Then I see the file "out.txt" with
"""
This is some text to be compared.
  It will probably
  be compared to a
  text file.
"""

MOTIVATION: It facilitates comparisons with text files or multiple-line strings.

Table matching

To allow a given UI Element or UI Literal to match a certain Table.

Example 1:

Then I see the table {MyTable} as [Some Table]

Example 2:

Then I see the table <myTable> as [Some Table]

In which Some Table is declared like this:

Table: Some Table
| Name  | Age |
| Bob   | 21  |
| Suzan | 25  |

It should make target table's rows to match the declared ones.

MOTIVATION: It facilitates the verification of expected data in tables from a user interface.

NOTES: Probably it requires to convert the Concordia Action to many abstract commands that verify every table row independently. Usually testing frameworks do not provide such kind of verification (for many rows at once).

Date and time expressions inside tables

Use Concordia 2 data and time expressions inside table rows. They must be written between ` or some other character. Example:

Table: Some Table
| Name | Age            |
| Bob  | `18 years ago` |

MOTIVATION: Concordia Language allows date and time expressions inside UI Properties. Using them inside tables can be useful.

Dynamic states

States that vary according to some generated value. Example:

...
    Given that I fill {User}
    and I fill {Pass}
    and I click  on {OK}
  Then I see "Welcome"
    and I have ~{User Type} is logged in~

UI Element: User
  - value comes from "SELECT user FROM [Users]"

UI Element: Pass
  - value comes from "SELECT pass FROM [Users] WHERE user = {User}"

UI Element: User Type
  - value comes from "SELECT user_type FROM [Users] WHERE user = {User}"

Table: Users
  | user  | pass    | user_type |
  | bob   | 123456  | admin     |
  | joe   | 654321  | guest     |
  | alice | 123456  | admin     |

According to the selected user, it will produce a different State. For example, when "bob" is selected, the produced state will be admin is logged in and when "joe" is selected, the produced state will be guest is logged in .

Thus, Features could depend on static or dynamic states.

MOTIVATION: Making states more flexible.

Alternative states

To provide a Given sentence that requires one - and only one - of the provided states. Example:

Variant: Example 1
  Given that I have either ~x~ or ~y~
 ...
    
Variant: Example 2
  Given one of ~x~, ~y~
  ...

MOTIVATION: It allows to perform a XOR operation with the given states using natural language, aiming at choosing one and only one of the given states.

Annotations to parameterize combination strategies

To provide annotations parameterize a test combination strategy for a specific Feature.

For instance, to configure the combination of invalid values for a specific Feature:

@comb-invalid(1)
Feature: Example

The annotations should correspond to the CLI parameters.

MOTIVATION: Increase the flexibility of the test generation procedure.

Multi-line queries

Currently:

- value comes from "SELECT name FROM [MyDB].profession"

Proposal (to accept as valid):

- value comes from "SELECT name
                   FROM [MyDB].profession"`

Alternative proposal:

- value comes from
"""
SELECT name
FROM [MyDB].profession
"""

MOTIVATION: Make it easier to write/read SQL statements.

Compiler

Selection Options

  • Select a Feature for Test Case generation, without having to include its dependencies:

    • by importance value

  • Select a Scenario for Test Case generation:

    • by importance value (tag @importance)

  • Test Case for test script generation;

    • by importance value (tag @importance)

Watch Mode

  • Provide the option --watch to generate .testcase files when their corresponding .feature file changes or an imported .feature file changes. A new seed must be produced, except when explicitly provided (using --seed or configuration file).

Language Support

Concordia has language constructions that the Compiler does not support yet. Examples:

  • Variant Background: Implement Variant Background, which is part of the Concordia Language but was not implemented yet by the Concordia Compiler.

  • Support the tag @ignore in Features and Scenarios. Currently it is supported inVariants and Test Cases. Whether added to a Feature or a Scenario, it would not generate Test Cases.

  • Consider global UI Elements

    Make the tool processing UI Elements tagged with @global.

    Allow inheritance of UI Elements

    Use @extends( <name> ) to extend another UI Element.

    Example:

    UI Element: Name
    - min length is 2
    - max length is 100
    
    @extends( Name )
    UI Element: Emergency Contact Name
    
    # Emergency Contact Name inherits the properties from Name
  • Multiple declared Tables per query: Allow a query to reference more than one table declared in the specification.

  • Multiple declared Databases per query: Allow a query to reference more than one database declared in the specification.

New Test Cases

  • Test cases that explore SQL Injection: Using declared Databases and Queries to formulate Test Cases that generate strings with SQL Injection commands.

  • Test cases that use naughty strings as test data: Using a list of naughty strings as test data.

UI and Report

It is already possible to generate HTML or even PDF reports using the available plug-ins. However, these reports indicate the frameworks' results, not necessarily the ones from Concordia.

To provide the CLI parameter --report for indicating the corresponding plug-in. Example:

npx concordia --report html

which should be equivalent to

npx concordia --report concordialang-report-html

Tool integration

Integration with text editors

  • Create new projects for auto-completion plug-ins for text editors such as VS Code, Sublime Text, Atom, etc. Example for VS Code: gherkin-autocomplete.

  • Be able to run test scripts using Concordia from the IDE.

Integration with reporting tools

  • Create integration with Allure. Other reporters (e.g., Macaca Reporter) can be added further.

Performance improvements

Avoid generating test scripts when their Test Case files did not change

Keep some hash control or use Git information when available. Hashes can be stored in a .json or .yml file. Example:

{
  "hashes": {
    "feature1.testcase": "ox10JBprHtu5c8822XooloNKUfk=",
    "subdir/feature2.testcase": "DMcj5b67Albe4KhpzyvphC5nVDHn1oCO",
  }
}

Generate unrelated files in parallel

NodeJS has made considerable progress since version 10.5 adding support to Worker Threads. Stable support for Worker Threads was added in version 12 LTS. Although, it would increase minimum requirements to install Concordia Compiler - currently it requires NodeJS 8.0.

Concordia Language

Informal specification

Line comments

Common line comment

It makes the compiler to ignore a piece of text. Example:

# This is a comment

Feature: Pay with Credit Card  # This is also a comment

Special line comment

  • Local declaration.

  • At most one declaration per file.

  • Take precedence over a CLI option or configuration file option.

They are:

  • #language: <value> defines the document's language, where <value> is an available language such as en (English) or pt (Portuguese).

  • #locale: <value> defines document's locale, where <value> is an available local such as en-US (USA English) or pt-BR (Brazilian Portuguese). NOT AVAILABLE YET.

Example:

#language: pt

Funcionalidade: Pagar com Cartão de Crédito

Tag

A tag adds metadata to a declaration.

  • Local declaration.

  • Allowed more than one tag per language construction.

A tag starts with @. Multiple tags can be declared in a single line. Examples:

...

@critical @slow
Feature: Print Coupon
  
  ...

  @gui
  Variant: Print to PDF
    ...
  
  @device
  Variant: Print to Plotter
    

Some tags can receive parameters. Examples:

@importance( 6 )
Feature: Register Employee
  ...
  

@extends( Date )
UI Element: Birth Date
  ...

Special tag

A special tag changes the compiler's behavior. These are special tags:

  • @scenario( <number> ): references a Scenario by its index, starting at 1.

  • @variant( <number> ): references a Variant by its index, starting at 1.

  • @importance( <number> ): indicates the importance of a declaration. The importance is as high as its number.

  • @generated: indicates that a Test Case was computer-generated.

  • @fail: indicates that a Test Case should fail.

  • @ignore: whether applied to a Variant, the Variant will not produce Test Cases; whether applied to a Test Case it will not produce test scripts.

  • @generate-only-valid-values: avoids that a UI Element's property be used for generating values considered invalid. This is specially useful for using with masked input fields, in which the system does not let a user to type invalid characters on it. For instance:

      UI Element: Year
        - data type is integer
        @generate-only-valid-values
        - format is "/^[0-9]{1-3}$/"
        Otherwise I must see "Year must be a number."

    The above example will avoid generating invalid input values (e.g., "A") for testing the format of the Year.

Reserved for future use:

  • @global makes a UI Element globally accessible. Global UI Elements must not have the same name. Local UI Elements (the default) overrides global UI Elements.

  • @extends( <name> )

Common tag

A common tag is ignored by the compiler and aims to provide meaningful metadata for a declaration. Any tag that is not a special tag is considered a common tag. Examples:

  • @critical may indicate that the current feature is critical for the project;

  • @issue(20) may indicate that a feature (or scenario or variant) is being implemented in the Issue 20 from the Issue control system.

Feature

Desired behavior of a software system

  • Global declaration with unique name, at most one declaration per file.

  • Sentences are optional and are not used for generating test cases.

  • Business-oriented sentences, written as a User Story.

A Feature can be a piece of functionality or some needed, wished or distinguish characteristic of a system.

Example:

Feature: Administrator Login

Feature sentences should try to describe the contribution that the Feature brings to the business addressed by the software system. They are optional, but recommended. Example:

Feature: Login
  As a registered user
  I would like to access to the system using my credentials
  So that the system prevents unauthorized access

In the above example the benefit to the business is to prevent unauthorized access.

Concordia adopts a wide-spread template for describing them: User Story. A User Story template goes like this:

As a <role>
I would like to <capability>
So that <benefit>

The order of the sentences can vary. A <role> is usually a type of user or stakeholder. A <capability> is what the role wants to perform in order to achieve the <benefit>, which often is the contribution to the business.

State

A certain state of the system

  • Local declaration, only accepted insideVariantsentences.

  • Used for generating test cases.

A State is denoted by a text between tilde (~), such as ~a state~, and must be written inside Variant sentences. Example:

Then I have a ~user logged in~

A Variant can both produce or require states. A State is produced by a Then sentence, like in the prior example. A State is required by a Given or a When sentence. For instance:

Given that I have ~user logged in~

By declaring a required State, you're establishing a dependency among the current Variant and the ones that can produce it. Since that State is often produced by a Variant from another Feature, you have to import the corresponding Feature file. Concordia Compiler will only search for states from imported Feature files.

When transforming Variants into Test Cases, Concordia Compiler will:

  • Remove any (Then) sentences with a produced State; and

  • Replace any (Given or When) sentences with a required State by sentences from the Variant that can produce it.

Whether there are different Variants that can produce a (same) required State, Concordia Compiler will be able to combine each of them with the current Variant, aiming to produce Test Cases that explore different execution paths. For more information, please read the section Test Coverage and Techniques.

Let's say that we have a simple Login feature like this:

Feature: Login

Scenario: Sucessful login

  Variant: Login with username and password
    Given that I am on the [Login Screen]
    When I enter with "bob" in {Username}
      and I enter with "123456" in {Password}
      and I click on {OK}
    Then I see "Welcome"
      and I have ~user logged in~


Constants:
  - "Login Screen" is "/login"
  
UI Element: Username

UI Element: Password

UI Element: OK
  - type is button

Now let's suppose that a user has to be logged in to access its account details:

import "login.feature"

Feature: My Account

  Scenario: See my account data
  
    Variant: Show basic data by default
      Given that I have ~user logged in~
        and I am on the [Account Screen]
      Then I see {User} with "bob"
        and I see {Name} with "Robert Downey Jr"


Constants:
  - "Account Screen" is "/account"
        
UI Element: User

Concordia Compiler will produce my-account.testcase with a Test Case like the following, that includes sentences from both the features:

import "my-account.feature"

@scenario(1)
@variant(1)
Test Case: See my account data - 1
  Given that I am on the "/login"
  When I enter with "bob" in <username>
    and I enter with "123456" in <password>
    and I click on <ok>
  Then I see "Welcome"
  Given that I am on the "/account
  Then I see <user> with "bob"
    and I see <name> with "Robert Downey Jr"

Scenario

High-level, business-focused, usage scenario of a Feature.

  • Local declaration with a unique name.

  • One or more declarations per Feature.

  • Sentences are optional and are not used for generating test cases.

  • Business-oriented sentences that follow the template Given-When-Then.

Example:

Feature: Sales Report

  Scenario: Daily sales report
    Given that I am authenticated as a manager
    When I open the sales report
      and I choose the option "Daily report"
    Then I see a list with all the today's sales 
      and the total value

Template:

Given <some context or precondition>
  and <other context or precondition>
  and <other context or precondition>
  ... 
When <some action is carried out>
  and <other action is carried out>
  and <other action is carried out>
  ...
Then <a result or postcondition is observed>
  and <another result or postcondition is observed>
  and <another result or postcondition is observed>
  ...

Variant

Test-oriented declaration that describes a possible interaction between a user and the system in order to accomplish a Scenario.

  • Local declaration, one or more per Scenario.

  • Sentences are used for generating test cases.

  • Test-oriented sentences that follow the template Given-When-Then and first-person singular ("I").

A Variant must use the Given-When-Then template (see Scenario) and first person singular ("I") in its sentences. Concordia Compiler uses Natural Language Processing (NLP) techniques to understand them.

See the Actions that you can write in Variant sentences.

Example:

Feature: New User

Scenario: Successful registration

  Variant: Register with a new account
    Given that I am on the [New Account Screen]
    When  I fill {Name}
      and I fill {Date of Birth}
      and I enter with "bob@example.com" in <#email>
      and I inform 123 in <#pass>    
      and I type 123 in <#confirmation>
      and I click <#ok>
    Then I have a ~registered user~
      and I see "Welcome, Bob" 

...

Things that can be part of Variant sentences:

  1. References to Constants, such as [New Account Screen]

  2. References to UI Elements, such as {Name} or {New User:Name}.

  3. Widgets, such as <#ok>

  4. States, such ~registered user~

  5. Values such as "bob@example.com"

  6. Numbers such as 123

Best practices

  • Make sure that your preconditions are part of the group with Given sentences.

  • Make sure that your actions are part of the group with When sentences.

  • Make sure that your post-conditions are part of the group with Then sentences.

  • Whenever possible, use a single Given , a single When and a single Then sentence. Useand for the other sentences.

  • Write a single action per sentence.

  • Do not use andin the middle of a sentence (break it, instead).

  • Use an additional indentation for and sentences.

Widgets

Variant sentences can have widgets (of the user interface) denoted between < and >. Example:

When I fill <#firstName> with "Alice"

Concordia adopts the well-known CSS query selectors to locate widgets. Plugins convert these selectors to the format adopted by the testing framework.

Available locators:

Locator

Purpose

Example

#

To find a widget by its id.

When I click on <#save>

.

To find a widget by its class.

When I click on <.btn-primary>

@

To find a widget by its name.

When I click on <@save>

~

To find a widget by its mobile name.

When I click on <~save>

//

To find a widget by its .

When I click on <//form/div/button[1]>

(none)

To find a widget by its type.

When I click on <button>

Whether you are testing a web application, you may find Katalon-Concordia useful. It's a browser extension - available for Google Chrome and Mozilla Firefox - that extends Katalon Recorder to save a recorded interaction as Variant sentences. Using it may reduce the time needed to locate the widgets of an existing application.

Constants

Declaration block with constant values

  • Global declaration (can be used by other files).

  • At most one declaration per file.

  • Constants cannot have the same name of a Table or a Database.

A Constants block can define one or more constants, preceded by a dash sign (-). Both constant names and values are declared between quotes, except for numeric values - that can be declared without quotes. Example:

Constants:
  - "Home" is "/home"
  - "App Name" is "Acme"
  - "Mininum Age" is 18
  - "Pi" is 3.1416

Constant values are accessible by their names between [ and ]. Examples for the constants above:

Variant: Example
  Given that I visit [Home]
    and I see [App Name]
  # ...
  
UI Element: Age
  - minimum value is [Minimum Age]
    Otherwise I see "Invalid age."
    
UI Element: Some Math Value
  - maximum value is [Pi]

Table

Defines a data table that can be used by UI Elements' properties.

  • Global declaration (can be used by other files).

  • Zero, one or many declarations per file.

  • Tables cannot have the same name of a Constant or a Database.

A table must have a unique name. Their rows are denoted between pipe (| ). The first row must provide the column names. Other rows must provide the corresponding data. Example:

Table: professions
  | name      | min_salary |
  | Magician  | 100000.00  |
  | 

Table declarations are transformed into in-memory tables that can be queried by UI Element properties for selecting test data. Tables can be queried using SQL. Like Constants, their names must be referenced between [ and ]. Example:

UI Element: Profession
  - value comes from "SELECT name FROM [professions]"

UI Element: Salary
  - minimum value comes from "SELECT min_salary from [professions] WHERE name = {Profession}"

Database

Declares a database connection that can be used for test data selection

  • Global declaration.

  • Names are shared with Constants and Tables.

  • Allowed more than one declaration per file.

  • Property values must be declared between quotes (").

Example 1:

Database: My DB
  - type is "mysql"
  - host is "http://127.0.0.1"
  - name is "mydb"
  - username is "admin"
  - password is "p4sss"

Example 2:

Database: Another DB
  - type is "json"
  - path is "C:\path\to\db.json"

Database support needs installation of the corresponding drives. See Using Databases for more information on how to install them.

Properties:

Property
Description
Required

type

Database type. Examples: "adodb", "csv", "firebase", "ini", "json", "mysql", "mssql", "postgres", "sqlite", "xlsx". See for all supported types.

Yes

host

URL that indicates where the database is hosted.

Vary

port

Network communication port used to connect to the database. Whether not defined, the default database port will be used, according to the property type.

No

name

Database name. Used when there is a database server (whose location is defined by the property host) and the database is accessible by its name.

Vary

path

Database path. Used when the database is accessed through the file system, such as the types csv, ini, json, sqlite and xlsx.

Vary

username

Username used to connect to the database. When not defined, the database's default user will be used, according to the property type.

No

password

Password used to connect to the database. When not defined, the database's default password will be used, according to the property type.

No

options

Database-specific connection options.

No

UI Element

Import

Imports declarations from a .feature file

  • Local declaration.

  • Give access to the declarations from the imported file.

Examples:

import "file1.feature"
import "path/to/file2.feature"

Test Case

Test Events

A Small Example

This example covers the generation of test data and oracles and the combination of features using states.

Let's suppose that we have to create two simple features for a web application: "Login" and "Add Product". After discussing them with stakeholders and the team, we created the following Concordia specification (see the two tabs):

Feature: Login
  As a user
  I would like to authenticate myself
  In order to access the application

Scenario: Successful login
  Given that I can see the login screen
  When I enter with valid credentials
  Then I can access the application's main screen
  
  Variant: Login with username and password
    Given that I visit the [Login Screen]
    When I fill {Username}
      And I fill {Password}
      And I click on {OK}
    Then I see "Welcome"
      And I have a ~user logged in~

Table: Users
  | username | password  |
  | bob      | 123456    |
  | alice    | 4l1c3pass |

UI Element: Username
  - required
    Otherwise I must see "Please inform the username."
  - value comes from "SELECT username FROM [Users]"
    Otherwise I must see "Invalid username."    

UI Element: Password
  - required
    Otherwise I must see "Please inform the password."
  - value comes from "SELECT password FROM [Users] WHERE username = {Username}"
    Otherwise I must see "Invalid password."

UI Element: OK
  - type is button
  
Constants:
  - "Login Screen" is "/login"  
  
import "login.feature"

Feature: Add Product
  As an employee
  I would like to add a product
  In order to manage its data and sale it
  
Scenario: Add a new product with basic data
  Given that I am logged in
  When I add a product with SKU, description, department, price, and quantity
  Then I am able to register it
  
  Variant: Basic data
    Given that I have a ~user logged in~
      and I visit the [Product Screen]
    When I fill {SKU}
      and I fill {Description}
      and I fill {Price}
      and I fill {Quantity}
      and I click on {Save}
    Then I have ~product registered~
      and I see "Saved."

UI Element: SKU
 - required
   Otherwise I see "Please inform the SKU."
 - format is "/[A-Z]{3}\-[0-9]{3}/"
   Otherwise I see "Invalid SKU format. Please use 3 letters, dash, 3 numbers." 
    
UI Element: Description
  - minimum length is 2
    Otherwise I see "Description needs at least 2 characters."
  - maximum length is 100
    Otherwise I see "Description must have at most 100 characters."    
    
UI Element: Price
  - required 
    Otherwise I see "Please inform the price."  
  - minimum value is 0.01
    Otherwise I see "Minimum price is one cent."
    
UI Element: Quantity
  - data type is integer

UI Element: Save
  - type is button    

Constants:
  "Product Screen" is "/products/new"

These features could correspond to the following sketches:

There is an experimental application that can generate User Interface Prototypes (UIP) from a Concordia specification. The current version has a plug-in to create HTML-based UIPs and it's really easy to adapt it for other technologies.

The specification helps stakeholders, analysis, testers and developers to create a shared understanding about the application and its business rules. It helps with the requirements validation, knowledge documentation, project design, implementation and testing.

Different from Use Cases and other requirements specification formats, with Concordia you probably don't need to define different scenarios for validation. Instead of having to manually define a set scenarios for validation, you just need to define how the UI elements should behavior - in their declaration - and the compiler will generate different scenarios for you in the form of Test Cases. Whether your application has a lot of such rules, your team will certainly benefit from it.

<TO-DO (UNDER CONSTRUCTION)>

Remember that a Variant express a possible interaction between a user and the application in order to complete its (business-focused) Scenario. lt follows the GWT syntax and always uses the word "I" to represent the user or user role denoted in the Feature's description.

Let's run Concordia Compiler with a seed to produce the same results over and over again:

npx concordia --seed="example" --no-run --no-result

It will generate login.testcase with the following content:

<TO-DO (UNDER CONSTRUCTION)>
<TO-DO (UNDER CONSTRUCTION)>

If a seed is not given, Concordia Compiler assumes the current date and time. The seed is always printed in the console so that you or your team can reproduce the same paths, test data, and test oracle that were able to expose a bug in your application. Here we are giving it for a sake of reproduction.

Using the same seed over and over again will make Concordia Compiler produce the same results. Options no-run and no-result avoid running the test scripts and getting execution results.

Execution without generation

This will not generate test cases or test scripts, but it will execute them and get their results:

$ concordia --plugin=codeceptjs --no-test-case --no-script

Output

login.testcase:

# Generated with ❤ by Concordia
#
# THIS IS A GENERATED FILE - MODIFICATIONS CAN BE LOST !

import "login-en.feature"

@generated
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 1
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with "*RM)O,"  # invalid: inexistent element
    And i fill <password> with ""  # valid: last element
    And I click on <ok>  # {OK}
  Then I must see "Invalid username"  # from <username>

@generated
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 2
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with "bob"  # valid: filled
    And i fill <password> with -8655972838932479  # invalid: inexistent element
    And I click on <ok>  # {OK}
  Then I must see "Invalid password"  # from <password>

@generated
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 3
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with "alice"  # valid: random element
    And i fill <password> with "4l1c3pass"  # valid: random element
    And I click on <ok>  # {OK}
  Then I see "Welcome"

@generated
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 4
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with "alice"  # valid: last element
    And i fill <password> with "4l1c3pass"  # valid: filled
    And I click on <ok>  # {OK}
  Then I see "Welcome"

@generated
@fail
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 5
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with ""  # invalid: not filled
    And i fill <password> with ""  # invalid: not filled
    And I click on <ok>  # {OK}
  Then I see "Welcome"

@generated
@scenario(1)
@variant(1)
Test case: Successful login with valid credentials - 6
  Given that I am in the "http://localhost/login"  # [Login Screen]
  When i fill <username> with "bob"  # valid: first element
    And i fill <password> with 123456  # valid: first element
    And I click on <ok>  # {OK}
  Then I see "Welcome"

test/login.js:

// Generated with ❤ by Concordia
// source: c:\code\tmp\concordia-test-pt\login-en.testcase
//
// THIS IS A GENERATED FILE - MODIFICATIONS CAN BE LOST !

Feature("Login");

Scenario("Successful login | Successful login with valid credentials - 1", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", "*RMO,"); // (11,5)  invalid: inexistent element
    I.fillField("password", ""); // (12,7)  valid: last element
    I.click("ok"); // (64,7)  {OK}
    I.see("Invalid username"); // (14,5)  from <username>
});

Scenario("Successful login | Successful login with valid credentials - 2", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", "bob"); // (21,5)  valid: filled
    I.fillField("password", "-8655972838932479"); // (22,7)  invalid: inexistent element
    I.click("ok"); // (64,7)  {OK}
    I.see("Invalid password"); // (24,5)  from <password>
});

Scenario("Successful login | Successful login with valid credentials - 3", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", "alice"); // (31,5)  valid: random element
    I.fillField("password", "4l1c3pass"); // (32,7)  valid: random element
    I.click("ok"); // (64,7)  {OK}
    I.see("Welcome"); // (65,5)
});

Scenario("Successful login | Successful login with valid credentials - 4", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", "alice"); // (41,5)  valid: last element
    I.fillField("password", "4l1c3pass"); // (42,7)  valid: filled
    I.click("ok"); // (64,7)  {OK}
    I.see("Welcome"); // (65,5)
});

Scenario("Successful login | Successful login with valid credentials - 5", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", ""); // (52,5)  invalid: not filled
    I.fillField("password", ""); // (53,7)  invalid: not filled
    I.click("ok"); // (64,7)  {OK}
    I.see("Welcome"); // (65,5)
});

Scenario("Successful login | Successful login with valid credentials - 6", (I) => {
    I.amOnPage("http://localhost/login"); // (61,5)  [Login Screen]
    I.fillField("username", "bob"); // (62,5)  valid: first element
    I.fillField("password", "123456"); // (63,7)  valid: first element
    I.click("ok"); // (64,7)  {OK}
    I.see("Welcome"); // (65,5)
});

3. Analyze the results

Whether you ran the test scripts above, you probably saw they fail. That's because they didn't find a web application running at http://localhost/login or because the application was found but it did not match the expected behavior. You may adapt your application and run the tests again.

Concordia shows a report that indicates the failures' locations. They help you to decide if a failure was caused by the application under test (e.g., it did not behave as expected) or because of the requirements specification (e.g., it is outdated in relation to the application).

Now keeping your specification updated has a new clear benefit: you can use it to generate tests and discover existing defects in your application!

See also

  • Language syntax

  • Available actions

Overview

To cite Concordia in a paper, please cite its PhD Thesis:

PINTO, Thiago Delgado. Unifying Agile requirements specification quality control and implementation conformance assurance. 2018. Doctoral Thesis. Pontifical Catholic University of Rio de Janeiro, Informatics Department, 2018.

Concordia Compiler infers test cases, test data and test oracles from specification files written in Concordia and tries to cover a large number of paths that can expose defects in your application. Its approach keeps the specification relevant, up-to-date and more useful for stakeholders, testers, and developers than other documentation formats.

Usage cycle

We recommend the following usage cycle:

  1. Write or update your requirements specification with the Concordia Language and validate them with users or stakeholders;

  2. Use Concordia Compiler for generating functional tests from the specification and running them;

  3. If the tests failed, there are some possibilities:

    a) You still haven't implemented the corresponding behavior in your application. In this case, just implement it and run the tests again.

    b) Your application is behaving differently from the specification. In this case, it may have bugs or you or your team haven't implemented the behavior exactly like described in the specification.

    • Whether the application has a bug, we are happy to have discovered it! Just fix it and run the tests again to make sure that the bug is gone.

    • Otherwise, you can decide between changing your application to behave exactly like the specification describes, or changing the specification to match your application behavior. In the latter case, back to step 1.

  4. If the tests passed, great job! Now you can write new requirements or add more test cases, so just back to step 1.

Process

When you type concordia, the compiler performs the following process:

Process
  1. It reads your .feature and .testcase files, and uses a lexer and a parser to identify and check documents' structure.

  2. It uses Natural Language Processing (NLP) to identify sentences' intent, which increases the chances of recognizing different writing styles.

  3. It performs semantic analysis to check recognized declarations.

  4. It uses the specification to infer the most suitable test cases, test data, and test oracles, and then generates .testcase files in Concordia Language.

  5. It transforms all the test cases into test scripts (that is, source code) using a plug-in.

  6. It executes the test scripts with the plug-in. These test scripts will check your application's behavior through its user interface.

  7. It reads and presents execution results. These results relate failing tests to the specification, in order to help you understanding the possible reasons of a failure.

Creating a Plug-in

Introduction

Concordia Compiler uses plug-ins for generating test scripts, running them and reading their results.

A plug-in can...

  • be coded in JavaScript or , such as (recommended), , or .

  • generate code (test scripts) for any programming language or testing framework able to perform for web, desktop or mobile applications.

Requirements for a plug-in

  1. Its name must start with concordialang-, for example: concordialang-my-awesome-plugin.

  2. It must be installable with . We recommend you to publish it at NPM too.

  3. It must implement the interface from .

  4. Its package.json file must contain the property concordiaPlugin, like in the following example:

Properties of concordiaPlugin:

  • file: string: Relative path of the file that contains an implementation of the Plugin interface.

  • class: string: Class (name) that implementsPlugin.

  • serve: string: Multi-platform console command to execute in order to start the testing server. Whether the testing framework does not need running a testing server, you can set something like echo \"Running a testing server is not needed.\".

Tasks to perform

A plug-in must deal with three tasks:

  1. Transforming into test scripts (i.e., source code).

  2. Executing the produced test scripts, regarding some .

  3. Transforming test execution results (produced by the testing framework) to .

Let's get into the details on how to accomplish them.

Transforming Abstract Test Scripts into test scripts

Think of an Abstract Test Script (ATS) as an object to transform into source code. Basically, it contains a structure that represents the actions to be converted into commands of your preferred programming language.

For instance, consider the following action:

That could be converted to the following command in , for PHP:

Or to the following command in , for JavaScript:

Let's consider a more realistic example, starting with a Test Case in the hypothetical file feature1.testcase:

That would probably produce an Abstract Test Script like this:

A plug-in for Cypress could generate the following code from the above object:

To help generating such commands, you can use some template library such as (recommended) or .

You can observe that after every command there is a line comment containing the corresponding location in the .testcase file. These comments will help to track the specification in case of test script failures.

Executing the test scripts

To execute the produced test scripts, you can use the target framework API or run the tool. Your call.

For example, whether you chose to run Cypress through npx and generate a report using the command to run could be the following:

Transforming execution results

Now the plug-in needs to read the report and transform it into an object of the class that will be returned to Concordia Compiler.

For instance, the reads the report from a JSON file generated by using with . The current implementation is available in the class .

A plug-in must be able to track back the location of failures or errors in the corresponding .testcase file from a test script. When a test script has a failure or an error, the report saves the stack trace where it occurred. For instance, tests/feature1.js:20:4 indicates, respectively, the file, line and column where the problem happened. You can use these data to read the line of the test script file and retrieve the line comment that contains the corresponding line in the .testcase file.

You can use a regular expression to extract the data from the stack trace, like did in the method extractScriptLocationFromStackTrace. Then you can use the class from to retrieve the location from the line comment. Example:

You can read these locations in the examples described earlier. Whether tests/feature1.js:7:8 is...

Retrieving the line 10 and column 4 fromfeature1.testcase would give us:

In , both test failures and errors are represented as an exception which includes the properties scriptLocation and specLocation.

Basic guide

We recommend you to follow these steps when creating a plug-in:

1. to indicate that you are interested in developing a new plug-in for a certain testing framework or programming language. That is good way to make others aware of your work.

2. Choose a good name for your plug-in and check whether it registered at . Remember that it must start with concordialang-. We recommend that it includes the target framework, tools or language. Example: concordialang-selenium-python to create a plug-in that generates test scripts for the Selenium framework and the Python language. You may use the opened issue (step 1) to get feedback about the name, if you wish.

3. Create a repository for it (e.g., at GitHub, GitLab, BitBucket) and clone the repository.

4. Create a NPM package with npm --init.

5. Add the property concordiaPlugin to your package.json file.

6. Install as a dependency:

7. Add your files. We recommend the following structure, but you can adapt it as you wish. For example, if you use , you will probably add a tsconfig.json file. If you use , your test folder will probably be named __tests__. We also recommend you to add a file and a file (the latter should include the folder node_modules).

8. Implement the interface . We recommend you to and encourage you to unit test all your code.

9. Test it with the Concordia Compiler before publishing it. Create a simple project that uses your plug-in. You can use NPM to install your plug-in from a directory in your computer or your remote repository. For example:

10. Publish your plug-in at after making sure that you are using . Congratulations! Tell everybody and ask for feedback! ✌

Quick Start

Welcome to the Concordia 2 documentation! This page will help you to get started fast. If you run into problems, you can find help on our .

See in case you don't know it yet.

System Requirements

Concordia Compiler requires only version 12.20 (or above) and works on Linux, MacOS and Windows.

In this Quick Start, we'll create a simple specification of an interaction with a search page and use . Therefore, download it before continuing.

Step 0: Initialize

If you are starting a new project or whether your project does not have a file named package.json, then run:

You can use NPM, Yarn or PNPM.

Step 1: Install

Install Concordia Compiler :

It will install version 2 that is in alpha stage, although stable.

Note that the needed package name is concordialang (with lang). After installing it, we'll always use npx concordia to execute it.

Step 2: Configure

Concordia Compiler will ask you about some preferences. Press Enter to answer every question with their default values. It will create a configuration file named .concordiarc and install the selected and .

Step 3: Create a feature

Create the folderfeatures :

Now create the file search.feature withinfeatures, with the following content:

About the file:

  • Feature and Scenario are high-level, business-focused descriptions about the problem to solve. Their sentences are not used to generate test cases. The above example does not describe them.

  • A Variant describes the expected interaction with the application's user interface (UI) in order to perform a Scenario. Thus, a Variant uses technological vocabulary.

  • In Concordia, all the interactions with the UI use first person singular ("I"). That "I" represents the actor that is interacting with the application (in the example above, a visitor).

Step 4: Execute

Finally, run

✨ That's it. Congratulations!✨

It will:

  • set the testing environment up (once);

  • generate a test case file and transformed it into a test script file;

  • execute the test script file; and

  • report the test script results.

Your browser should open automatically during this process and the console will report the execution results.

Your directory should now look like this:

The directory node_modules contains installed dependencies, like tools and frameworks, whose versions are managed with package.json and package-lock.json. The file codecept.json has a basic configuration to run CodeceptJS with Google Chrome and you can to fit your needs.

The file features/search.testcase should look like this:

The Test Case above was produced from the Variant declared in features/search.feature. Some notes about it:

  • The import clause (line 5) imports the declared file's content.

  • The tag @generated (line 7) indicates that the Test Case was produced automatically.

  • The tag @scenario(1) (line 8) indicates that the Test Case belongs to the first Scenario (1).

  • The tag @variant(1) (line 9) indicates that the Test Case belongs to the first Variant (1) of the Scenario declared previously.

  • The Test Case (line 10) is named using the Variant's name plus dash (-) and some (incremental) number. Its content is basically the same as the Variant's, since we did not use any other declarations.

The file test/search.js contains the test script produced from features/search.testcase using the selected plug-in. It also contains line comments with references to their corresponding lines and columns in the .testcase file:

Concordia Compiler can also generate and for you. All the test cases and test scripts receive line comments that detail the and reference declarations used to produce oracles and test data.

Notes on installation options

You can opt to install Concordia Compiler locally (per project) or globally.

Local installation (recommended)

  • does not require administrative privileges (i.e., using sudo on Linux or MacOS) to install;

  • allows every project to have its own, independent installation;

  • demands using before every command.

Follow the for a install installation.

is included in NodeJS 8.2.0 or above.

Global installation

  • requires administrative privilegies (i.e., using sudo on Linux or MacOS) to install;

  • lets you execute the compiler direcly from any folder;

  • needs more attention when upgrading, especially for plug-ins.

Example:

Note: On Windows, you must omit sudo.

Additional tips:

  • .

  • Whether Windows requires administrative privileges to install, right click Windows (Start) menu, click "Command Prompt (Admin)" or alternatively "Windows PowerShell (Admin)", and then proceed with the installation command.

  • To upgrade Concordia later, change the installation command from install to upgrade.

XPath
Using Databases
{
   ...
   
   "concordiaPlugin": {
      "file": "dist/index.js",
      "class": "MyAwesomePlugin",
      "serve": "npx command-to-start-my-testing-server"
   }
}
{
    "action": "click",
    "targets": ["#ok"]
}
I->click("#ok");
cy.get('#ok').click();
import "feature1.feature"

@generated
@scenario(1)
@variant(1)
Test Case: Scenario 1 | V1
  Given that I am on "https://myapp.com/register"
  When I fill <#email> with "john.doe@example.com"
    and I fill <#nome> with "John Doe"
    and I click on <#register>
  Then I see "Welcome, John Doe"
{
    "feature": { "name": "Feature 1" },
    "scenario": { "name": "Scenario 1" },
    "testcases": [
        {
            "scenario": "V1",
            "commands": [
                {
                    "action": "amOn",
                    "values": [ "https://myapp.com/register" ],
                    "location": { "line": 7, "column": 2 }
                },
                {
                    "action": "type",
                    "targets": [ "#email" ],
                    "values": [ "john.doe@example.com" ],
                    "location": { "line": 8, "column": 2 } 
                },            
                {
                    "action": "type",
                    "targets": [ "#name" ],
                    "values": [ "John Doe" ],
                    "location": { "line": 9, "column": 4 }                  
                },                
                {
                    "action": "click",
                    "targets": [ "#register" ],
                    "location": { "line": 10, "column": 4 } 
                },
                {
                    "action": "see",
                    "values": [ "Welcome, John Doe" ],
                    "location": { "line": 11, "column": 2 }
                }                                         
            ]
        }
    ]
}
context("Feature 1", function() {

    it("Scenario 1 | V1", function() {
        cy.visit("https://myapp.com/register"); // (7,2)
        cy.get("#email").type("john.doe@example.com"); // (8,2)
        cy.get("#name").type("John Doe"); // (9,4)
        cy.get("#register").click(); // (10,4)
        cy.get("body").should("contain", "Welcome, John Doe"); // (11,2)
    });

});
npx cypress run --reporter junit
const scriptLocation = /* extract from stack trace */;

// Suppose that `failureLocation` is:
// {
//    path: "tests/feature1.js",
//    line: 7,
//    column: 8
// }

// Retrieve the comment with the reader:
const specLocation = reader.retrieveSpecLocation(
    scriptLocation
    );
    
// `specLocation` would be:
// {
//    path: "features/feature1.testcase",
//    line: 10,
//    column: 4
// }
cy.get("#register").click(); // (10,4)
  and I click on <#register>
npm install --save concordialang-plugin
 ┃
 ┣ src/            🡐 your source code
 ┣ test/           🡐 your tests
 ┣ .editorconfig
 ┣ .gitignore
 ┗ package.json
cd path/to/your/test-project/
npm install /path/to/your-plugin
npm publish
any language that "transpiles" to JavaScript
TypeScript
Dart
CoffeeScript
functional tests
NPM
Plugin
concordialang-plugin
Abstract Test Scripts
execution options
the expected resulting format
Codeception
Cypress
Mustache
Handlebars
Mocha JUnit Reporter,
TestScriptExecutionResult
core of the plug-in for CodeceptJS
CodeceptJS
Mocha Multi Reporters
ReportConverter
ReportConverter
FileInstrumentationReader
concordialang-plugin
TestScriptExecutionResult
Open an issue
NPM
concordialang-plugin
TypeScript
Jest
.editorconfig
.gitignore
Plugin
take a look at other plugins that did a similar job
NPM
Semantic Versioning
npm init --yes
npm i -D concordialang
npx concordia --init
mkdir features
Feature: Search

Scenario: Shows results that correspond to the term

  Variant: Search by pressing Enter
    Given that I am on "https://google.com"
    When I type "concordialang" in <q>
      And I press "Enter"
      And I wait for 2 seconds
    Then I see "npm"
npx concordia
 ┃
 ┣ features/          
 ┃ ┣ search.feature
 ┃ ┗ search.testcase     🡐 generated test case
 ┣ node_modules/
 ┣ test/              
 ┃ ┗ search.js           🡐 generated test script
 ┣ .concordiarc
 ┣ codecept.json
 ┣ package.json  
 ┗ package-lock.json
# Generated with ❤ by Concordia
#
# THIS IS A GENERATED FILE - MODIFICATIONS CAN BE LOST !

import "search.feature"

@generated
@scenario(1)
@variant(1)
Test Case: Search by pressing Enter - 1
  Given that I am on "https://google.com"
  When I type "concordialang.org" in <q>
    And I press "Enter"
    And I wait for 2 seconds
  Then I see "npm"
// Generated with ❤ by Concordia
// source: search.testcase
//
// THIS IS A GENERATED FILE - MODIFICATIONS CAN BE LOST !

Feature("Search");

Scenario("Shows results that correspond to the term | Search by pressing Enter - 1", (I) => {
    I.amOnPage("https://google.com"); // (11,2)
    I.fillField("q", "concordialang.org"); // (12,2)
    I.pressKey("Enter"); // (13,4)
    I.wait(2); // (14,4)
    I.see("npm"); // (15,2)
});
sudo npm install -g concordialang
concordia --version
Slack channel
Understanding Concordia
NodeJS
Google Chrome
locally
plug-in
database drivers
change it
test data
test oracles
kind of data test case being explored
NPX
Quick Start
NPX
How to install globally with NPM on Linux or MacOS without sudo

Language Additions

This page tries to identify in which version of the Compiler a certain language construction became available.

👁‍🗨 "Planned" and "Available" refer to versions of the Compiler.

Construction

Planned

Available

#

0.1

0.x

#language

0.1

0.x

#locale

2.1

Not released yet.

@*

0.1

0.x

@scenario

0.1

0.x

@variant

0.1

0.x

@ignore

0.1

0.x

@importance

0.1

0.x*

@generated

0.1

0.x

@fail

0.1

0.x

@global

0.1

Not released yet.

@extends

0.1

Not released yet.

@category

0.1

Not released yet.**

@issue

0.1

Not released yet.**

@generate-only-valid-values

1.0

1.1

Feature

0.1

0.x

Scenario

0.1

0.x

Background

0.1

Not released yet.**

Variant

0.1

0.x

Variant Background

0.1

Not released yet.

~state~

0.1

0.x

Constants

0.1

0.x

Table

0.1

0.x

Database

0.1

0.x

UI Element

0.1

0.x

UI Element property locale

1.4

2.0

UI Element property locale format

1.4

2.0

UI Element properties with date and time expressions

1.4

2.0

Test Case

0.1

0.x

Before All

0.1

0.x

After All

0.1

0.x

Before Feature

0.1

0.x

After Feature

0.1

0.x

Before Each Scenario

0.1

0.x

After Each Scenario

0.1

0.x

*=Not used yet. **=It may not be released, since it is not needed.