Write WebDriver tests
Learn how to write Cypress and Playwright tests against your classic apps.
WebDriver tests are a great way to ensure that your classic app is working as expected. They can be run on your local machine, against a staging instance, or in a CI/CD pipeline against your development branch to ensure that your classic app is working as expected.
The instance on which to run your tests depends on your use case. Since these tests use your Retool resources, you should not run them against your production instance.
To write your tests in the same repository as your classic app, put the tests and all WebDriver setup
code in a directory called user/ in the root of your repository.
Prerequisites
Before you get started, follow the setup instructions in the Cypress or Playwright documentation.
Set up a testing account
Retool recommends that you configure a test account with limited permissions. Navigate to Settings > User in Retool to configure these permissions.
To use 2FA for this account, you need to use a library such as otplib at the login step.
You might want to disable SSO for this account so that it's easier for your WebDriver to log in. To use SSO, you need to use a library that works with your SSO provider to log in such as the Cypress Okta library.
If you are concerned about increased costs associated with the additional test account, you can choose to run tests on an existing account.
Log in
- Visit the login page at
<your-subdomain>.retool.com/auth/loginto programmatically log in. If you self-host Retool, use<your-domain>/auth/login. - Using your WebDriver, find the username and password inputs by placeholder text.
- You may want to persist the session between tests so that you don't need to login for every test. See below for examples.
- Cypress
- Playwright
// Add Cypress Testing Library commands (https://testing-library.com/docs/cypress-testing-library/intro/)
import "@testing-library/cypress/add-commands";
Cypress.Commands.add("login", (username, password) => {
cy.visit("http://localhost:3000/auth/login"); // Adjust this to your local app's login URL
cy.get('input[placeholder="name@company.com"]').type(username); // Adjust the placeholder to match your username field
cy.get('input[placeholder="*******************"]').type(password); // Adjust the placeholder to match your password field
cy.contains(/^Sign in$/).click(); // Click the Sign in button
});
describe('Login Test', () => {
it('should log in successfully and navigate to the home page', () => {
cy.login("name@company.com", "password"); // Replace with actual username and password
cy.url().should('eq', "http://localhost:3000/auth/login");
});
});
In Playwright, you can configure a global setup function to programmatically log in. The function should set an environment variable process.env.COOKIES containing the cookies from the authenticated session.
import { chromium } from "@playwright/test";
export default async function globalSetup() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("https://<your-domain>/auth/login");
await page
.getByPlaceholder("name@company.com")
.fill(`${process.env.PLAYWRIGHT_USERNAME}`);
await page
.getByPlaceholder("*******************")
.fill(`${process.env.PLAYWRIGHT_PASSWORD}`);
await page.getByText(/^Sign in$/).click();
await page.getByText("Welcome to Retool").click();
const cookies = await page.context().cookies();
process.env.COOKIES = JSON.stringify(cookies); // set this env var to store the authed page session
await browser.close();
}
Then, create a fixture that extends the base test by providing authedPage.
import { test as base } from "@playwright/test";
export const test = base.extend({
authedPage: async ({ page }, use) => {
const deserializedCookies = process.env.COOKIES
? JSON.parse(process.env.COOKIES)
: undefined;
if (deserializedCookies) {
await page.context().addCookies(deserializedCookies);
}
await use(page);
},
});
This new authedPage can be used in multiple test files, and will be already logged into Retool.
import { test } from "../fixtures/authedPage";
test("example test", async ({ authedPage }) => {
authedPage.goto(url);
// do things
});
In Playwright, tests run in parallel so having a single shared account for all tests may result in flakiness or unexpected behavior. You can use a single account for testing if you're positive your tests won't impact each other.
If your tests affect server-side state (for example, one test runs a query that updates a table, while another test checks the values of that table), or if you aren't sure that tests won't impact each other, then you may need multiple testing accounts. See Playwright's documentation for more information on setting up multiple testing accounts.
Writing E2E Tests
A solid Retool E2E test generally has 3 steps:
- Visiting an app
- Querying for elements on the page and interacting with them
- Making assertions about the state of the app
Each of these steps map to Retool-specific code.
1. Visit an app
After setting up your WebDriver and logging into your testing account, navigate to the classic app that you want to test. We will use our User Management app as an example.
To visit a page, we pass the URL we want to visit to the WebDriver-appropriate function.
- Cypress
- Playwright
describe("User Management", () => {
it("opens the app", () => {
cy.login("<your-username>", "<your-password>");
cy.visit(
"https://docsdemos.retool.com/embedded/public/b4889e10-bead-4f30-876e-905e51b1616a"
);
});
});
import { expect } from "@playwright/test";
import { test } from "../fixtures/authedPage";
test.describe("User Management", () => {
test("opens the app", async ({ authedPage }) => {
await authedPage.goto(
"https://docsdemos.retool.com/embedded/public/b4889e10-bead-4f30-876e-905e51b1616a"
);
});
});