Intelligence Community Design System ICDS Get started Accessibility Styles Components Patterns Community
Show navigation section

Testing with Cypress

About Cypress

Cypress is a developer-friendly, JavaScript-based front-end testing tool. It comes bundled with popular libraries like Mocha and Chai, allowing for swift adoption.

Advantages include snapshots at the time of test execution, implicit wait commands, multiple browsers in which to test and real-time command execution with visual feedback.

Cypress allows for end-to-end testing, replicating how "users interact with your app by using a real browser", and component testing, also known as unit testing, which tests a component's functionality, styling and appearance in isolation.

Cypress and the Shadow DOM

Cypress gives two ways in which to test@ukic components in the shadow DOM .

Configuring at test level

AddincludeShadowDom: true to thecy.get query.

// cypress/e2e/test.cy.js
it("has an app bar with title link", () => {
  cy.get("ic-top-navigation", { includeShadowDom: true })
    .shadow()
    .find(".title-link")
    .should("have.attr", "href", "/")
    .should("have.text", "My App Title");
});

This allows traversing the shadow DOM by chaining the.shadow() method.

Configuring at global level

AddincludeShadowDom: true to thecypress.config.js .

// cypress.config.js
const { defineConfig } = require("cypress");

module.exports = defineConfig({
  includeShadowDom: true,
  component: {
    devServer: {
      framework: "create-react-app",
      bundler: "webpack",
    },
  },
});

This allows traversing the shadow DOM using assertions without having to explicitly chain the.shadow() method.

Example: Component testing

Below are examples of component tests on the@ukic/react componentsIcTextfield andIcButton . Component tests are normally located adjacent to the component they are testing and are rendered on a development server.

// Textfield.tsx
import { IcTextField, IcButton } from "@ukic/react";
import React, { useState } from "react";

function Textfield() {
  const [favouriteCoffee, setFavouriteCoffee] = useState<String>("");

  const handleChange = (event) => {
    event.preventDefault();
    setFavouriteCoffee(event.detail.value);
  };

  const handleClick = () => {
    console.log("This is the best coffee going:", favouriteCoffee);
  };

  return (
    <form><IcTextField
        label="What is your favourite coffee?"
        placeholder="Placeholder"
        helperText="Such as Arabica, Robusta or Liberica"
        onIcChange={(ev) => handleChange(ev)}
      /><IcButton variant="primary" onClick={() => handleClick()}>
        Send
      </IcButton></form>
  );
}

export default Textfield;
// Textfield.cy.tsx
import React from "react";
import Textfield from "./Textfield.tsx";

describe("<Textfield />", () => {
  it("renders", () => {
    cy.mount(<Textfield />).should("have.property", "component");
  });
  it("takes a value in the textfield and prints to console when the button is clicked", () => {
    // Render the component
    cy.mount(<Textfield />);
    // Capture the log to check later
    cy.stub(window.console, "log").as("consoleLog");

    // Check the IcComponents have finished rendering
    cy.get("ic-text-field").should("have.class", "hydrated");
    cy.get("ic-button").should("have.class", "hydrated");

    // Interact with the components and provide assertions
    cy.get("#ic-text-field-input-1").type("Black");
    cy.get("ic-button").click();
    cy.get("@consoleLog").should(
      "be.calledWith",
      "This is the best coffee going:",
      "Black"
    );
  });
});

Example: End-to-end testing

Below is an example of end-to-end tests written against a ‘test app’ that has been created using ICDS components.

cypress.cy.tsx Component.tsx types.ts constants.ts methods.ts
// StackBlitz cannot currently run Cypress tests
it("should fill the form with no errors/validation",()=>{
mount(<Subscription/>);
// checkHydrated will wait until the component is hydrated and ensures it is ready to test
checkHydrated(IC_PAGE_HEADER);
// Check the first step is visible
cy.get(IC_STEPPER).should(BE_VISIBLE);
checkCurrentStep(0);
// Select a radio option
cy.get(IC_RADIO_OPTION).find(RADIO+'[value="house"]').check({force:true});
cy.get(IC_RADIO_OPTION+'[label="House Blend"]').should(HAVE_ATTR,SELECTED);
// Select a select option using mouse
clickOnShadowEl(IC_SELECT,IC_INPUT_CONTAINER);
clickOnShadowEl(IC_SELECT,IC_MENU_OPTION+'[data-value="aeropress"]');
// Select a select option using keyboard
clickOnShadowEl(IC_SELECT,IC_INPUT_CONTAINER,1);
cy.realPress([ARROW_DOWN_KEY,ESCAPE_KEY]);
// Go to next step, check the stepper and the logged formValues so far
cy.get(IC_BUTTON).contains("Add to order").click();
checkCurrentStep(1);
cy.get(CONSOLE_LOG).should(HAVE_BEEN_CALLED_WITH,filledForm());
// Fill out the text fields
clickOnShadowEl(IC_TEXT_FIELD,IC_INPUT_CONTAINER);
cy.realType("Java the Hutt")
.realPress(TAB_KEY)
.realType("javadahutt@tattooine.com")
.realPress(TAB_KEY)
.realType("1234567890");
// Check both options in the checkbox group
findShadowEl(IC_CHECKBOX,CHECKBOX).eq(0).check();
findShadowEl(IC_CHECKBOX,CHECKBOX).eq(1).check();
cy.get(IC_CHECKBOX).eq(0).should(HAVE_ATTR,CHECKED);
cy.get(IC_CHECKBOX).eq(1).should(HAVE_ATTR,CHECKED);
// Go to next step, check the stepper and the logged formValues so far
cy.get(IC_BUTTON).contains("Add to order").click();
cy.get(CONSOLE_LOG).should(HAVE_BEEN_CALLED_WITH,filledForm("details"));
checkCurrentStep(2);
// Select a date using the date picker
findShadowEl(IC_DATE_PICKER,IC_DATE_INPUT)
.shadow()
.find(CALENDAR_BUTTON_ID)
.click();
findShadowEl(IC_DATE_PICKER,FOCUSSED_DAY_BTN_CLASS).click();
checkDateInputValue(newDate());
// Agree to terms
cy.get(IC_RADIO_OPTION).find(RADIO+'[name="agree"]').check({force:true});
cy.get(IC_RADIO_OPTION+'[name="agree"]').should(HAVE_ATTR,SELECTED);
// Submit and check the logged formValues
cy.get(IC_BUTTON).contains("Submit order").click();
let date =newDate();
cy.get(CONSOLE_LOG).should(HAVE_BEEN_CALLED_WITH,filledForm("checkout"));
});

Last reviewed 29 August 2024 .
Navigated to Testing with Cypress - Intelligence Community Design System