-
Notifications
You must be signed in to change notification settings - Fork 1
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
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. | ||
|
||
## Getting Started | ||
|
||
### Prerequisites | ||
|
||
- Node.js (>=14.x) | ||
- npm (>=6.x) | ||
Comment on lines
+9
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
+19
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
||
|
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"); | ||
} | ||
} |
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"); | ||
} | ||
} |
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(); | ||
} | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 😎