Luciole
An API for writting Cypress tests in Gleam and a CLI for compiling those tests in JavaScript.
Luciole is the french word for firefly, but contrary to other bugs, this one will illuminate the night and help you find bugs in your app. This program is composed of a Gleam API for writting Cypress tests, and a CLI to transpile them to JavaScript with Cypress syntax.
Requirements
- Node.js >= 24.x
- Gleam >= 1.9.x
- Cypress >= 14.x
- Any package manager (ex: yarn >= 1.22)
Installation
CLI installation:
# depending on your package manager
yarn add luciole
npm install luciole
API installation:
gleam add luciole
Run the CLI
Run this command to transpile the Cypress-for-Gleam files to Cypress-for-JavaScript files, by replacing <project-path>
with the path to your Gleam project:
yarn luciole transpile <project-path>
Tests are generated in cypress/e2e/luciole/
.
Get started with the API
Go to your Gleam project and create a directory cy
under the test
directory.
Create a file named example.gleam
inside test/cy/
. You can copy the following code for a minimal test example. This test goes to the Cypress example page and checks that the body of the page contains the word “Kitchen”.
import luciole.{describe, it}
import luciole/cypress as cy
import luciole/should
pub fn example_cy() {
describe("my awesome project", [
it("goes to Cypress example page", fn() {
cy.visit("https://example.cypress.io")
cy.get("body") |> should.contain("Kitchen")
}),
])
}
Then run the CLI to transpile every files of test/cy/
to JavaScript files. After that, you can simply open Cypress and check that your test e2e/luciole/example.cy.js
runs correctly.
yarn luciole transpile <project-path>
yarn cypress open
More test examples are available at api/test/cy.
More about the API
File tree
Your tests should be written in Gleam files located in the folder test/cy
at the root of your Gleam project.
Each test file should contain one test function at top-level ending in “_cy”. This is the function that will be transpiled by Luciole.
The file may contain other functions and others as well, but only the function ending in “_cy” will be transpiled. You can use the API’s functions in any function of your test file, except the functions of the base module luciole.gleam
that should only be called in the “_cy” function. See api/test/cy/nesting/multiple_fun.gleam for a test example using multiple functions.
If functions of the base module
luciole.gleam
are used in functions not ending in_cy
, the transpilation will have unexpected behaviours.
By default, the CLI will compile the Gleam project to JavaScript, create the AST of each compiled test, edit it to follow Cypress syntax, and generate code from it in a Cypress directory. To do so, the program will look for the name of the Gleam project in the first gleam.toml
file found by searching up in the file tree. It will also look for the first directory named cypress
when searching up the file tree.
If you specify the option --buildDest <new-path-to-build>
, the Gleam build will be copied to a new path and generated files’ imports will be updated based on its new location. Otherwise, generated files’ imports will import files from the origin location of the build.
Files in
cypress/e2e/luciole/
will be overwritten by the new generated tests. You can avoid this by specifying another test destination using:yarn luciole transpile <project-path> <test-destination>
Test file
The test function has a name ending in “_cy”. Its body is composed of any number of describe
, it
and hooks
blocks. A describe
can contain any number of these blocks. An it
and a hook
can only contain a test body. A test body is made of multiple ordered expressions that will check the state of your DOM. You can write these expressions using the functions of the API.
Those function bodies are correct: ✅
it(body)
: oneit
at top-leveldescribe([ it(body) ])
: anit
in adescribe
describe([ it(body), it(body) ])
: multipleit
in adescribe
describe([ describe([ describe([ it(body) ]) ]) ])
: nesteddescribe
describe([ it(body), describe([ it(body) ]) ])
: switching betweendescribe
andit
in adescribe
Those function bodies are not correct: ❌
describe([ body ])
: a test body outside ofit
it([ it(body) ])
: nestedit
it([ describe( it(body) ) ])
: anit
containing adescribe
Modules organisation
Blocks functions like describe
, it
and hooks
are located in the base module luciole.gleam
.
Fonctions that can be called at the begining of a chain are located in the luciole/cypress.gleam
module.
Fonctions that can be chained after a Chainable object returned by another fonction are located in the luciole/chain.gleam
module.
The should()
fonction of Cypress is implemented in the luciole/should.gleam
module. Each fonction of the API corresponds to one of its options in Cypress, like should.equal(x)
in Gleam correspond to should('equal', x)
in JavaScript.
The location()
function of Cypress is implemented in the luciole/location.gleam
module. Each fonction of the API corresponds to one of its options in Cypress, like location.port(x)
in Gleam correspond to location('port', x)
in JavaScript.