-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(tests): Improve E2E Documentation (#16909)
* chore(tests): Improve E2E Documentation * Update libs/testing/e2e/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
- Loading branch information
Showing
1 changed file
with
194 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,215 @@ | ||
# E2E Testing | ||
# E2E Testing Library | ||
|
||
This library was generated with [Nx](https://nx.dev). It contains utility functions and configuration files that assist with end-to-end (E2E) testing in Playwright for various apps. | ||
This library contains utility functions, shared configuration, and documentation to assist with end-to-end (E2E) testing for all apps using Playwright. | ||
|
||
## Overview | ||
## 📚 Overview | ||
|
||
This library includes: | ||
### Contents | ||
|
||
- **Helper Functions:** Utility functions designed to streamline E2E testing with Playwright. These functions cater to different applications across the project and help automate common testing workflows. | ||
- **Global Playwright Configuration:** The `createGlobalConfig` function provides a shared Playwright configuration used across multiple applications. It standardizes the testing environment. | ||
- **🔧 Helper Functions**: Utility functions to simplify and standardize E2E testing across apps. | ||
- **⚙️ Shared Playwright Configuration**: A common configuration used as the base for all app-specific Playwright configurations. | ||
- **🌍 Multi-Environment Testing**: Support for running tests in `local`, `dev`, `staging`, and `prod` environments. | ||
|
||
## Mockoon Usage Guide for E2E Tests | ||
## 🚀 How to Use This Library | ||
|
||
This section explains how to use [Mockoon](https://mockoon.com/) to set up mock APIs for end-to-end (e2e) testing. | ||
### Importing Helper Functions | ||
|
||
### What is Mockoon? | ||
To use helper functions in your tests, import them directly from this library: | ||
|
||
[Mockoon](https://mockoon.com/) is an open-source tool for creating mock APIs quickly and easily. It allows developers to simulate backend servers without relying on live backend services. This is especially useful for e2e testing, where consistency and repeatability of backend responses are important. | ||
```typescript | ||
import { myHelperFunction } from '@island.is/testing/e2e' | ||
``` | ||
|
||
### Extending the Common Playwright Config | ||
|
||
Each app should create its own `playwright.config.ts` file that extends the shared configuration: | ||
|
||
```typescript | ||
import { createPlaywrightConfig } from '@island.is/testing/e2e' | ||
|
||
const playwrightConfig = createPlaywrightConfig({ | ||
webServerUrl: '<web-server-url>', | ||
command: '<command>', | ||
// Add any app-specific configurations here | ||
}) | ||
|
||
export default playwrightConfig | ||
``` | ||
|
||
## 🏃 Running Tests | ||
|
||
Use the following command structure to run tests for any app: | ||
|
||
```bash | ||
yarn e2e <app-name> | ||
``` | ||
|
||
### Useful Playwright Commands and Flags | ||
|
||
Mockoon provides both a graphical user interface (GUI) for managing API mock files and a command-line interface (CLI) for running these mock APIs in various environments, such as pipelines. | ||
- **Run with UI Mode**: Launch the tests with a UI to select and debug tests interactively. | ||
|
||
### Opening an Existing Mock File in Mockoon | ||
```bash | ||
yarn e2e <app-name> --ui | ||
``` | ||
|
||
To view or modify an existing mock file: | ||
- **Run Tests Without Caching**: Ensure a fresh run of tests without using cached results. | ||
|
||
1. Open Mockoon. | ||
2. Click on **+** and then click on **Open Local Environment**. | ||
3. Choose the desired mock file, such as `apps/<my-app>/e2e/mocks/<my-app-mock>.json`. | ||
```bash | ||
yarn e2e <app-name> --skip-nx-cache | ||
``` | ||
|
||
This will load the mock configuration into the Mockoon UI, allowing you to inspect and edit the mock endpoints. | ||
- **Run a Specific Project**: Run only the tests defined under a specific project in your Playwright config: | ||
|
||
### Creating a Mock File with Mockoon UI | ||
```bash | ||
yarn e2e <app-name> -- --project=smoke | ||
yarn e2e <app-name> -- --project=acceptance | ||
yarn e2e <app-name> -- --project=everything | ||
``` | ||
|
||
To create or modify a mock file: | ||
- **View the Test Report**: After running tests, use this command to view the generated report: | ||
|
||
1. Download and install [Mockoon](https://mockoon.com/download/) if you haven't already. | ||
2. Open Mockoon and create a new environment: | ||
- Click on **+** and then click on **New Local Environment**. | ||
- Nema your mock file and choose a location for it e.g. `apps/<my-app>/e2e/mocks/<my-app-mock>.json`. | ||
- Add endpoints, routes, and response details as needed. | ||
```bash | ||
yarn playwright show-report | ||
``` | ||
|
||
### Running a Mockoon Server with the CLI | ||
- **Run Specific Tests**: Use `--grep` to run tests matching a specific pattern: | ||
|
||
To run a mock server with the cli, use the following command: | ||
```bash | ||
yarn e2e <app-name> --grep "Home Page Test" | ||
``` | ||
|
||
- **Debug Mode**: Run tests in debug mode for better visibility: | ||
|
||
```bash | ||
yarn e2e <app-name> --debug | ||
``` | ||
|
||
## ✍️ Writing Tests | ||
|
||
Run `yarn playwright codegen <url-to-your-app> --output <path/to/your/app/spec.ts>` and modify the output. The selectors need special attention; they should be transformed to use roles or `data-testid` attributes for stability (see below on how to). | ||
|
||
### 🤔 What to Test | ||
|
||
Writing tests for every possible combination is time-consuming for you and the CI pipeline, with diminishing value beyond the most common cases. | ||
|
||
You should therefore aim to write test for: | ||
|
||
- Most common usage patterns | ||
- Usage/patterns that MUST NOT break | ||
- Problematic cases likely to cause an error/bug | ||
|
||
### 🏗️ Test structure | ||
|
||
Test cases are written in spec files. Tests that do not modify anything (e.g., _create_ an application, _change_ the user’s name, etc.) and verify basic functionality are called **smoke tests**. Tests that are more detailed and/or make any changes at all, are called **acceptance tests**. Test cases are put into folders by what app they are testing, smoke/acceptance test, and each file tests some aspect of an app. Here is an example of the folder layout for testing the search engine and front-page of the `web` project (within the system-e2e app): | ||
|
||
```shell | ||
web/ (app name) | ||
├── smoke/ (test type) | ||
│ └── home-page.spec.ts (feature name, kebab-case) | ||
└── acceptance/ | ||
└── search.spec.ts | ||
``` | ||
|
||
### 🗃️ Spec files | ||
|
||
A spec file should have only one description (`test.describe`) of what part of an app is being tested. Therein can be one or more test cases (`test`) with a description of what scenario each test case is testing. Setup and tear down can be done in `test.beforeAll`, `test.beforeEach`, `test.afterAll`, and `test.afterEach`. You should not _rely_ on `after*` ever running, and you should prepare your environment every time _before_ each test. For example: | ||
|
||
```jsx | ||
test.describe('Overview part of banking app', () => { | ||
test.beforeAll(() => { | ||
// Create/clear database | ||
// Seed database | ||
}) | ||
|
||
/* NOTE: there is no guarantee this will run */ | ||
test.afterAll(() => { | ||
// Tear down database | ||
// Log out | ||
}) | ||
|
||
test.beforeEach(() => { | ||
// Log in | ||
// Basic state reset, e.g. clear inbox | ||
}) | ||
|
||
test('should get paid', () => { | ||
// Make user get money using page.selector, page.click, etc. | ||
// Verify money is present | ||
}) | ||
}) | ||
``` | ||
|
||
Each test case (`test`) should test a specific scenario from end-to-end. If your test is getting long and complicated consider breaking it up within a `test` with `test.step`; each step will run in succession and the failure/success report is easier to read. Let’s take the operating licence application as an example; test various routes/cases: | ||
|
||
- Hotel permit with food, but no alcohol | ||
- Hotel permit with food and alcohol | ||
- Bar with only alcohol | ||
- Home accommodation (AirBnB style), no food, no alcohol | ||
|
||
### 🧰 Using Fixtures and Mocking Server Responses | ||
|
||
Fixtures are essential for setting up controlled test data to ensure predictable test behavior. Mocking server responses can help simulate specific backend scenarios without relying on live data. Use the following approach to mock server responses: | ||
|
||
```typescript | ||
await page.route('/api/endpoint', (route) => | ||
route.fulfill({ | ||
status: 200, | ||
body: JSON.stringify({ key: 'mockData' }), | ||
}), | ||
) | ||
``` | ||
|
||
### 😬 Tricky element searching | ||
|
||
Some apps, like service-portal and application-system-form, load their components _very_ asynchronously. This can be an issue when targeting some elements, but they do not appear on the first page load, but instead load after the basic page has loaded. | ||
|
||
In such cases you can wait for the elements to exist with `page.waitFor*` ([docs](https://playwright.dev/docs/api/class-page#page-wait-for-event)): | ||
|
||
```jsx | ||
// Wait for there to be at least 3 checkboxes | ||
await page.waitForSelector(':nth-match("role=checkbox", 3') | ||
// Wait for any arbitrary function | ||
await page.waitForFunction(async () => { | ||
const timer = page.locator('role=timer') | ||
const timeLeft = await timer.textContent() | ||
return Number(timeLeft) < 10 | ||
}) | ||
``` | ||
|
||
## 🤖 Mockoon Usage Guide for E2E Tests | ||
|
||
### ❓ What is Mockoon? | ||
|
||
[Mockoon](https://mockoon.com/) is a tool for creating mock APIs, useful for simulating backend services during E2E testing. | ||
|
||
### 📂 Opening and Creating Mock Files | ||
|
||
- **To open an existing mock file**: Navigate to `apps/<app>/e2e/mocks/<app-mock>.json` in the Mockoon UI. | ||
- **To create a new mock file**: | ||
1. Download [Mockoon](https://mockoon.com/download/). | ||
2. Create a new environment and save it to `apps/<app>/e2e/mocks/`. | ||
|
||
### 🖥️ Running Mockoon Server with CLI | ||
|
||
To start a mock server: | ||
|
||
```bash | ||
yarn mockoon-cli start --data ./apps/<my-app>/e2e/mocks/<my-app-mock>.json --port <port> | ||
yarn mockoon-cli start --data ./apps/<app>/e2e/mocks/<app-mock>.json --port <port> | ||
``` | ||
|
||
## 🛠️ Troubleshooting and FAQs | ||
|
||
### 🔄 Common Issues | ||
|
||
- **500: Internal Server Error**: If not related to your code, contact the DevOps team. | ||
- **💀 ESOCKETTIMEDOUT**: Likely an infrastructure issue. Reach out to DevOps if persistent. | ||
- **⌛ Tests Timing Out**: Increase the timeout if known network issues exist: | ||
|
||
```typescript | ||
await page.goto('/my-url', { timeout: Timeout.medium }) | ||
``` | ||
|
||
## 📖 Additional Resources | ||
|
||
- Refer to each app directory's `README.md` for app-specific details and usage instructions. | ||
- Check out the [Playwright Documentation](https://playwright.dev) for further information. |