Best practices

Testing your application is a powerful tool in improving the quality of your Hub applications. Good storytelling test descriptions increase the comprehension of your application's codebase, user flow coverage ensures your application is fulfilling its requirements, and all types of tests increase the release confidence.

Our Suggestions#

First concentrate on high level E2E tests and move to more specific test types as you see fit. This approach is outlined in Approach, the testing pyramid from the top!

E2E/UI Testing#

While E2E tests give you the highest confidence type of tests, we recognize they can be complicated, slower and more brittle than other tests. How Cypress solves UI testing and E2E with Cypress can help you successfully implement E2E tests for your application.

describe("Set future prices for products", () => {
it("Load product details", () => {
cy.get("iframe").then($element => {
const $body = $element.contents().find("body");
cy.wrap($body).find(".PreviewProductsList__products-table tbody>tr>td").last().should("contain", "Jabra");
cy.wrap($body).find(".FilterProductsPage__submit-filters").click();
});
});
it("Switch to the second page to update prices", () => {
cy.get("iframe").then($element => {
const $body = $element.contents().find("body");
cy.wrap($body)
.find(".ant-page-header-heading-title")
.last()
.should("contain", "Set one regular price at all locations");
cy.wrap($body).find(".PricingTable__select-another-date-button").click();
cy.wrap($body).find(".ant-modal-title").should("contain", "Add New Date");
cy.wrap($body).find(".ant-calendar-today").next().click();
cy.wrap($body).find(".ant-btn-primary").last().click();
});
});
it("Update product price", () => {
cy.get("iframe").then($element => {
const $body = $element.contents().find("body");
cy.wrap($body).find(".FuturePricingCell__Input").first().find("input.ant-input").type("20 {Enter}");
cy.wrap($body).find(".MemoizedTable").click();
cy.wrap($body).find(".ant-page-header-heading-extra .ant-btn-primary").last().click();
cy.wrap($body).find(".ant-message-success").should("contain", "Your changes have been saved!");
});
});
});

Integration Testing#

Integration test runs the whole app in a real browser without hitting a real server, which is opposite to E2E testing where app interacts with the real server. Those tests are blazing fast and less exposed to random failures or false negatives. Cypress is perfect for UI Integration tests.

import React from "react";
import { render } from "@testing-library/react";
import { mockData } from "../../shared/testUtils/locationFixture";
import { LocationTable } from "./LocationTable";
describe("LocationTable tests", () => {
test("Renders correctly with data", async () => {
const { findByTestId, container } = render(
<LocationTable data={mockData.LocationConfigurations} isLoading={false} key="testKey" />
);
const locationTable = await findByTestId("locationTable");
expect(locationTable).toBeVisible();
const locationRowToTest = container.querySelector('[data-row-key="Cornwall Centre"]');
const nameField = await findByTestId("locationTableNameFieldCornwall Centre");
expect(locationRowToTest).toContainElement(nameField);
});
});

Unit Testing#

Unit Tests tend to be the simplest and most granular types of tests. The downside of unit tests lies in their low level focus which can often result in testing external dependencies more so than the Hub application itself.

Jest allows you to write tests with an approachable, familiar and feature-rich API. Jest is well-documented, requires little configuration, and can be extended when needed. With Jest, you can conduct snapshot, parallelization, and async method tests, mock first and thrid-party functions, execute myriad assertion methods, and view code coverage report.

describe("Filter function", () => {
test("it should filter by a search term (link)", () => {
const input = [
{ id: 1, url: "https://www.url1.dev" },
{ id: 2, url: "https://www.url2.dev" },
{ id: 3, url: "https://www.link3.dev" },
];
const output = [{ id: 3, url: "https://www.link3.dev" }];
expect(filterByTerm(input, "link")).toEqual(output);
});
});

Writing tests when the app is wrapped in <Auth>#

When writing tests for React apps that use <Auth> and AuthContext , you can mock the context to enable tests to run outside of a host like the Hub shell.

import { AuthContext, IUserModel } from "@iqmetrix/auth";
import * as React from "react";
import { App } from "./App";
import { render } from "@testing-library/react";
const userContext = {
isLoading: false,
isLoaded: true,
hasLoggedIn: true,
user: {
id: "100",
parentEntityId: 100,
userName: "test@test",
isExternal: false,
firstName: "Test",
} as IUserModel,
env: "int",
error: "",
envSuffix: "int",
};
describe("Examples", () => {
it("renders without crashing", async () => {
const { container } = render(
<AuthContext.Provider value={userContext}>
<App />
</AuthContext.Provider>
);
const user = container.getElementsByClassName("user-data");
expect(user[0].textContent).toBe("Hello Test (test@test)");
});
});
Last updated on by Paulo Andrade