Back

šŸ§Ŗ E2E tests made easy with Cypress + Cucumber

Takshak Ramteke

If youā€™re a developer Iā€™m pretty sure end to end testing is something youā€™ve heard about a lot

While it may ā€œsoundā€ like daunting task at first what if i tell you that there is a relatively easy way to implement itā€¦

Feature : Test redirection
Scenario : Test the redirect
    Given that im on "Home" page
    When i click "#redirect"
    Then i should see "Redirected" as "h1"

What you read just now is a fully functional test written in what is called a Gherkin syntax used by Cucumber which is a BDD testing tool and its open source ofcourse

But Cucumber on itā€™s own isnā€™t really capable of doing E2E tests And Thatā€™s where Cypress comes in to save the day

Now, thatā€™s fine and all but

How exactly do we do it you may ask

Well apparantly its quite the simple process thanks to the magicāœØ thatā€™s open source and the hardwork of badeball **who created the

cypress-cucumber-preprocessor šŸ”„ which if you couldnā€™t guess already allows us to use cucumber along side cypress

now as you might expect (almost) nothing in the tech industry works without a bit of configuration and this tool is no exception, though the good thing is that it is pretty simple to configure and as a matter of fact it can be done in 3 super easy steps

Step 1 : Install all the dependencies

ofcoure šŸ¤· duh weā€™d have to do this one & itā€™s kinda self explanatory, you only need to install a few things i.e cypress, @badeball/cypress-cucumber-preprocessor, esbuild and lastly cypress-esbuild-preprocessor

To do so simply run the following command and watch it complete

yarn add --dev cypress @badeball/cypress-cucumber-preprocessor esbuild cypress-esbuild-preprocessor typescript

OR

npm install --save-dev cypress @badeball/cypress-cucumber-preprocessor esbuild cypress-esbuild-preprocessor typescript if thatā€™s your thing

now you can throw in Typescript (šŸ’œ) into this if you want to which I obviously did, but itā€™s totally optional & upto you

Step 2 : Generating the basic configuration

Now that we have all what we need letā€™s start the actual configuration but hereā€™s the plot twist,

Initially though you will not have the basic cypress configuration, to generate it simply run

yarn cypress open or npx cypress open if npmā€™s your thing

And follow the dialogs to configure the e2e testing and that should give you a basic configuration that we need

Step 3 : The Actual Configuration

Okay this time for sure

Now that we have all the basic configuration we need lets start by telling cypress to use the .feature files (thatā€™s the extension for a test written with cucumber), To do that all we need to do is specify the ā€œspecPatternā€ property in the cypress.config.ts (or .js if youre using js)

import { defineConfig } from "cypress";

export default defineConfig({
    e2e: {
        setupNodeEvents(on, config) {
            //
        },
        specPattern: "**/*.feature",
    },
});

Now that thatā€™s out of the way lets focus on the other part which is actually using the preprocessor to do that weā€™ll have to use a bundler to process these .feature files, there are many bundlers out there so you can use any bundler you want to, I personally prefer using esbuild because it is fast and easy to configure

And so to do this all we have to do setup an on() event handler and configure our cypress-cucumber-preprocessor plugin and the bundler inside of the setupNodeEvents function that allows us to tap into, modify, or extend the internal behavior of Cypress

import { defineConfig } from "cypress";
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
import createBundler from "@bahmutov/cypress-esbuild-preprocessor";
import createEsbuildPlugin from "@badeball/cypress-cucumber-preprocessor/esbuild";

export default defineConfig({
	e2e:{
		setupNodeEvents(on, config){
			addCucumberPreprocessorPlugin(on, config);
			on("file:preprocessor",createBundler({
          plugins: [createEsbuildPlugin(config)],
        });
			)
		},
		specPattern: "**/*.feature",
	}
})

And Thatā€™s all weā€™re done with the configuration all thatā€™s left is to take it for a spin and write some tests

Writing your First Test

To write a test just add a .feature file inside of the ā€œ cypress/e2e/ ā€ folder and creative a respective spec file for it

what is a spec file? you may ask well its a file that tells cypress how to process the statements inside of the feature file, youā€™ll see what i mean in just a sec

So lets quickly write a feature file first

Feature: Google.com
Scenario: visting the frontpage
    When I visit google.com
    Then I should see Google as the Title

And thatā€™s it, all this test does is navigate to google.com and check whether the title for the website is google or not, simple as that šŸ™ƒ

Now obviously you can do more complex stuff with this but for the sake of demo and simplicity letā€™s keep it to that for now

And letā€™s move on to writing the actual spec file for this test, to do that just create a file ending in .ts (or .js) with the same name as that of the feature file e.g. google.ts if you called it google.feature

import { When, Then } from "@badeball/cypress-cucumber-preprocessor";

When("I visit google.com", () => {
    cy.visit("<https://google.com>");
});
Then("I should see Google as the Title", () => {
    cy.get("title").should("Google");
});

Now to run this test just run yarn cypress run or npx cypress run and if you followed through correctly then youā€™ll see the test pass šŸ˜Œ

Common Step Definitions

You donā€™t have to actually write a spec file for each .feature file what you can do is use a common spec file and define all the reoccurring step definitions inside of it to do so add the following line inside of your package.json

"cypress-cucumber-preprocessor": {
    "stepDefinitions": [
      "cypress/e2e/common/index.ts"
    ]
  }

and now you can define all the common step definitions inside of the index.ts and yes you can call this file whatever you want i call it index.ts because i kinda like it šŸ¤·ā€ā™‚ļø

Reusable Step definitions

YES, you read it right you can actually write reusable step definitions for the feature statements that you will probably use multiple times e.g.

Feature: Google.com
  Scenario: visting the frontpage
    When I visit "google.com"
		Then I should see "Google" as the "title"

Notice the double quotes on google.com, Thats what weā€™re going to use to make this statement reusable

The main part is tho happens in the spec file

import { When, Then } from "@badeball/cypress-cucumber-preprocessor";

When(`I visit {string}`, (url: string) => {
    cy.visit(`https://${url}`);
});
Then(`I should see {string} as the {string}`, (text, target) => {
    cy.get(location).should("contain", text);
});

What we do here is take arguments from the feature statements inside the double quotes and then we use them as parameters in the callbacks

And thus, We can now use these two statements as many times as we want to by just changing the values inside the double quotes

And That is How you can make End to End Testing much more easy and Fun for beginners on your team

Hello there šŸ‘‹, Thank you for reading to the bottom, Hope you liked this blog and that it was Helpfull to you in some way or the other, This is the first blog post i ever wrote so please feel free to point out some short commings if you find any constructive criticism is always welcomed

Thank you for Reading, and I hope to see you on next one