Skip to content

Commit c19bbb8

Browse files
committed
doc: extend best practices for tests
1 parent e533067 commit c19bbb8

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

e2e_tests/BEST_PRACTICES.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
11
# E2E Tests Best Practices
22

3-
## Page Object Navigation Patterns
3+
## Page Object Model Usage
4+
5+
Page objects should always be used where possible, as recommended by the [Playwright Page Object Model documentation](https://playwright.dev/docs/pom). Page objects represent parts of your web application and encapsulate common operations, element selectors, and assertions into a higher-level API. This simplifies test authoring, improves maintainability, and reduces code duplication.
6+
7+
### What Should Go into a Page Function
8+
9+
Page functions should encapsulate actions, assertions, and navigation logic related to a specific page or component. Examples include:
10+
11+
- **Actions**: Methods that perform user interactions, such as filling forms, clicking buttons, or navigating.
12+
```typescript
13+
async addProvider(name: string, baseUrl: string, apiKey: string) {
14+
await this.page.getByText("Add Provider", { exact: true }).click();
15+
await this.page.getByLabel("Provider Name", { exact: true }).fill(name);
16+
await this.page.getByLabel("Base URL", { exact: true }).fill(baseUrl);
17+
await this.page.getByLabel("API Key", { exact: true }).fill(apiKey);
18+
await this.page.getByText("Create Provider", { exact: true }).click();
19+
}
20+
```
21+
22+
- **Assertions**: Methods that verify expected states or elements on the page.
23+
```typescript
24+
async assertProviderExists(providerName: string, baseUrl?: string) {
25+
await expect(this.page.getByText(providerName, { exact: true })).toBeVisible();
26+
if (baseUrl) {
27+
await this.page.getByText(providerName, { exact: true }).click();
28+
await expect(this.page.locator(`input[value="${baseUrl}"]`)).toBeVisible();
29+
}
30+
}
31+
```
32+
33+
- **Navigation**: Methods for navigating to the page, either directly or through the UI.
34+
```typescript
35+
async goto() {
36+
await this.page.goto("/settings/global/llm-providers");
37+
}
38+
39+
async navigateTo() {
40+
await this.page.getByText("Global Settings", { exact: true }).click();
41+
await this.page.getByText("LLM Providers", { exact: true }).click();
42+
await expect(this.page).toHaveURL("/settings/global/llm-providers");
43+
}
44+
```
45+
46+
### How Tests Should Use Page Objects
47+
48+
Tests should instantiate the page object and call its methods instead of directly interacting with the `page` object. This promotes reusability and keeps tests focused on high-level behavior.
49+
50+
```typescript
51+
test("should save llm provider", async ({ page }) => {
52+
const llmProviderPage = new LLMProvidersPage(page);
53+
54+
await llmProviderPage.goto();
55+
await llmProviderPage.addProvider("Test Provider", "http://localhost:3001", "test-api-key");
56+
await llmProviderPage.assertProviderAddedSuccessfully("Test Provider");
57+
});
58+
```
459

560
### goto() vs navigateTo()
661

@@ -27,3 +82,5 @@ await chatPage.navigateTo(); // Clicks through the application to reach the chat
2782
- **goto()**: Fast, direct navigation - good for isolated page testing
2883
- **navigateTo()**: Tests actual user navigation paths - better for integration testing
2984
- **Consistency**: Always use the appropriate method based on your testing goals
85+
86+
By following this pattern, tests become more readable, easier to maintain, and less prone to breaking when UI changes occur.

0 commit comments

Comments
 (0)