How to write Gherkin steps with ReScript ? ideas needed (vitest-bdd)

Hi everyone !

In my ongoing quest to support Behavior Driven Development at my company, I created a plugin “vitest-bdd” and I would like to support ReScript as well but do not really know how to solve some issues.

My goal with this plugin is to make it very easy for QA and devs to work together (and write tests that run in parallel with async if needed).

// TypeScript code to configure the Gherkin steps
import { expect } from "vitest";
import { Given } from "vitest-bdd";
import { makeCalculator } from "../../feature/calculator";

Given("I have a {string} calculator", ({ When, Then, And }, name: string) => {
  const calculator = makeCalculator(name);

  When("I add {number} and {number}", calculator.add);
  When("I subtract {number} and {number}", calculator.subtract);
  When("I multiply {number} and {number}", calculator.multiply);
  When("I divide {number} by {number}", calculator.divide);

  Then("the result is {number}", (n: number) => {
    expect(calculator.result.value).toBe(n);
  });
  And("the title is {string}", (s: string) => {
    expect(calculator.title).toBe(s);
  });
});

How should this be done with ReScript ?

There is a lot of weird stuff here…

  • the capital letters for functions (can this be solved with t.Given(“…”) ?)
  • these files are usually parsed by plugins for cucumber to figure out steps and help write tests with auto-completion
  • there is a proxy to support different languages in the { When, Then, …} object to the types resolving to ‘any’ for the arguments, …). Which makes it possible to write { Quand } and then Quand(“je clique sur {string}”, …).

PS: Gherkin test

Feature: Calculator

  Background:
    Given I have a "basic" calculator
    Then the title is "basic"

  Scenario: Add two numbers
    When I add 1 and 2
    Then the result is 3

  Scenario: Divide one number by another
    When I divide 1 by 2
    Then the result is 0.5
1 Like

hey, I’m not sure what’s your issue here, you could use @as and externals to bind to functions with starting with an uppercase and bind to multiple languages at the same time:

type givenUtils = {
  @as("When") when_: 'a. (string, 'a) => unit,
  @as("Then") then: 'a. (string, 'a) => unit,
  @as("And") and_: 'a. (string, 'a) => unit,
  @as("Quand") quand: 'a. (string, 'a) => unit,
}
@module("vitest-bdd")
external given: (string, (givenUtils, 'args) => unit) => unit = "Given"

If it compiles to correct js files, I guess you could parse the generated js files, couldn’t you?

1 Like

Thanks @tsnobip for the reply. I did not know about the @as argument which solves part of the problem.

The other issue is that the type and number of parameters to “When” (or other step functions) can vary from nothing to string or string and string, or table (string[][]), etc.

Current TS type is this:

type Operation = (...params: any[]) => void;

The exact parameters are extracted from the string by detecting numbers and quotes.

given that the parameter can be pretty much anything, I just defined it as 'a, which allows any type and any array of type. I think the type safety here is not that important given such errors will likely be detected by some other tools down the line.