Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding E2E Testing Automation #755

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# playwright

allure-results
test-results
playwright-report
12 changes: 0 additions & 12 deletions apps/web/e2e/app.spec.ts

This file was deleted.

86 changes: 86 additions & 0 deletions apps/web/e2e/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Playwright Tests with TypeScript

This repository contains end-to-end tests for a web application using Playwright and TypeScript. The tests are organized using the Page Object Model (POM) to enhance maintainability and readability.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should probably describe this in other words, as repository is quite a trademarked word in the git context. Also, confusing as it is, apps/web is a legacy naming we never got around to update, but (correct me if I'm wrong) it's essentially the life events web app.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On another note, a tl;dr description on POM and best practice would be cool 😎


## Getting Started

### Prerequisites

- Node.js (>=14.x)
- npm (>=6.x)
Comment on lines +9 to +10
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?


### Installation

1. Clone the repository:
```sh
git clone https://github.com/your-repo/playwright-tests.git
cd playwright-tests
```

2. Install dependencies:
```sh
npm install
```
Comment on lines +12 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?


### Running Tests

To run all tests, use the following command:
```sh
npx playwright test

npx playwright test --grep @critical
Comment on lines +25 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need two Running Tests sections?



## Playwright Configuration

The Playwright configuration is defined in the `playwright.config.ts` file. Here are some key points:

- **Timeout per test**: Each test has a timeout of 5000 milliseconds.
- **Reporters**: The tests use line, allure-playwright, and HTML reporters.
- **Test directory**: The tests are located in the `e2e` directory.
- **Retries**: Tests will be retried once if they fail.
- **Artifacts**: Test results, including screenshots and traces, are stored in the `test-results` directory.
- **Web Server**: The configuration includes a command to start the development server before running the tests.
- **Base URL**: The base URL for the application under test is set dynamically based on the port.

For more information on configuring Playwright, visit the [official documentation](https://playwright.dev/docs/test-configuration).

### Running Tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General question, is there any merit in describing (tl;dr fashion) what headed eg. means, or are we supposed to know this already (me problem)?


To run all tests, use the following command:
```sh
npm run test:e2e ```

To run tests with a visual\debug interface:
```sh
npm run test:visual ```

To run tests in headed mode:

```sh
npm run test:head```

To run only critical tests in headed mode:

```sh
npm run test:critical```

To run only blocker tests in headed mode:

```sh
npm run test:blocker```

To run a specific test file or test case:

```sh
npm run test:single ```

## Resources

- [Playwright Official Website](https://playwright.dev)
- [Playwright Documentation](https://playwright.dev/docs/intro)
- [TypeScript Documentation](https://www.typescriptlang.org/docs/)

For further details and advanced usage, please refer to the Playwright and TypeScript official documentation.


50 changes: 50 additions & 0 deletions apps/web/e2e/objects/aboutPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Page, expect } from "@playwright/test";

export class AboutPage {
readonly page: Page;

constructor(page: Page) {
this.page = page;
}

async navigateTo() {
await this.page.goto("/");
}

async clickAboutPage() {
await this.page.getByText("About Page").click();
}

async expectUrl() {
await expect(this.page).toHaveURL("/home/about");
}

async expectHeading() {
await expect(this.page.getByRole("heading", { level: 1 })).toContainText(
"About Page",
);
}

async navigateToAuth() {
await this.page.goto(
"http://localhost:3005/auth?redirectUrl=http://localhost:3000/",
);
}

async fillTextbox(text: string) {
await this.page.getByRole("textbox").click();
await this.page.getByRole("textbox").fill(text);
}

async navigateToWelcome() {
await this.page.goto("http://localhost:3000/en/welcome?redirect_url=%2Fen");
}

async clickEventsMenu() {
await this.page.getByLabel("events-menu").click();
}

async expectAboutMeInList() {
await expect(this.page.getByRole("list")).toContainText("About me");
}
}
124 changes: 124 additions & 0 deletions apps/web/e2e/objects/loginPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Page, expect } from "@playwright/test";

export class LoginPage {
readonly page: Page;

constructor(page: Page) {
this.page = page;
}

async navigateTo() {
await this.page.goto("");
}

async clickPublicServant() {
await this.page.click("text=Public Servant");
}

async expectTitle(title: string) {
await expect(this.page).toHaveTitle(title);
}

async expectPublicServantText() {
await expect(
this.page.locator("label >> text=Public Servant"),
).toContainText("Public Servant");
}

async enterPassword(password: string) {
const passwordField = this.page.locator('//input[@name="password"]');
await passwordField.click();
await passwordField.fill(password);
}

async clickSubmit() {
await this.page.click("//*[@id='submit_btn']");
}

async expectPasswordRequired() {
await expect(this.page.locator('input[name="password"]')).toHaveAttribute(
"required",
"",
);
}

async expectMyGovIdLogo() {
const mygovidLogo = this.page.locator("#mygovid-logo.icon-mygovid_logo");
await expect(mygovidLogo).toHaveCount(1);
await expect(mygovidLogo).toBeVisible();
}

async expectMainElements() {
await expect(
this.page.locator('div[style="display: flex; flex-direction: column"]'),
).toBeVisible();
await expect(
this.page.locator("label >> text=Public Servant"),
).toBeVisible();
await expect(
this.page.locator("label >> text=Public Servant"),
).toContainText("Public Servant");
await expect(
this.page.locator("label >> text=Verification level"),
).toBeVisible();
await expect(
this.page.locator("label >> text=Verification level"),
).toContainText("Verification level");

const userSelectLabel = this.page.locator(
'div.password-label label[for="user_select"]',
);
await expect(userSelectLabel).toBeVisible();
await expect(userSelectLabel).toHaveText("Select user");

const passwordLabel = this.page.locator('label[for="password"]');
await expect(passwordLabel).toBeVisible();
await expect(passwordLabel).toHaveText("Password");

const loginButton = this.page.locator("#submit_btn");
await expect(loginButton).toBeVisible();
await expect(loginButton).toHaveAttribute("id", "submit_btn");
await expect(loginButton).toHaveAttribute("type", "submit");
const buttonText = await loginButton.textContent();
expect(buttonText).toContain("Login");
}

async expectVerificationLevelOptions() {
const verificationLevelDropdown = this.page.locator(
'select[name="verificationLevel"]',
);

await expect(verificationLevelDropdown).toBeVisible();

const options = verificationLevelDropdown.locator("option");

await expect(options).toHaveCount(3);

for (let i = 0; i < 3; i++) {
const option = options.nth(i);
const optionText = await option.textContent();
const optionValue = await option.getAttribute("value");

switch (i) {
case 0:
expect(optionText).toBe("Level 0");
expect(optionValue).toBe("0");
break;
case 1:
expect(optionText).toBe("Level 1");
expect(optionValue).toBe("1");
break;
case 2:
expect(optionText).toBe("Level 2");
expect(optionValue).toBe("2");
break;
}
}
}

async expectWelcomeMessage() {
const h1Locator = this.page.locator("h1.govie-heading-l");
await expect(h1Locator).toBeVisible();
await expect(h1Locator).toHaveText("Welcome to Life Events");
}
}
21 changes: 21 additions & 0 deletions apps/web/e2e/objects/logoutPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Page, expect } from "@playwright/test";

export class LogoutPage {
readonly page: Page;

constructor(page: Page) {
this.page = page;
}

async clickLogout() {
const logoutButton = this.page.getByLabel("Logout");
await expect(logoutButton).toBeVisible();
await logoutButton.click();
}

async expectMyGovIdLogo() {
const mygovidLogo = this.page.locator("#mygovid-logo.icon-mygovid_logo");
await expect(mygovidLogo).toHaveCount(1);
await expect(mygovidLogo).toBeVisible();
}
}
Loading
Loading