From 28d2507722d566a8aec0b46f07e847a63f35877d Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:04:42 +0200 Subject: [PATCH 1/6] remove the demo part --- tests-examples/demo-todo-app.spec.ts | 437 --------------------------- 1 file changed, 437 deletions(-) delete mode 100644 tests-examples/demo-todo-app.spec.ts diff --git a/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts deleted file mode 100644 index 8641cb5..0000000 --- a/tests-examples/demo-todo-app.spec.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { test, expect, type Page } from '@playwright/test'; - -test.beforeEach(async ({ page }) => { - await page.goto('https://demo.playwright.dev/todomvc'); -}); - -const TODO_ITEMS = [ - 'buy some cheese', - 'feed the cat', - 'book a doctors appointment' -] as const; - -test.describe('New Todo', () => { - test('should allow me to add todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create 1st todo. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Make sure the list only has one todo item. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0] - ]); - - // Create 2nd todo. - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - - // Make sure the list now has two todo items. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[1] - ]); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); - - test('should clear text input field when an item is added', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create one todo item. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Check that input is empty. - await expect(newTodo).toBeEmpty(); - await checkNumberOfTodosInLocalStorage(page, 1); - }); - - test('should append new items to the bottom of the list', async ({ page }) => { - // Create 3 items. - await createDefaultTodos(page); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - // Check test using different methods. - await expect(page.getByText('3 items left')).toBeVisible(); - await expect(todoCount).toHaveText('3 items left'); - await expect(todoCount).toContainText('3'); - await expect(todoCount).toHaveText(/3/); - - // Check all items in one call. - await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); - await checkNumberOfTodosInLocalStorage(page, 3); - }); -}); - -test.describe('Mark all as completed', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test.afterEach(async ({ page }) => { - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should allow me to mark all items as completed', async ({ page }) => { - // Complete all todos. - await page.getByLabel('Mark all as complete').check(); - - // Ensure all todos have 'completed' class. - await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - }); - - test('should allow me to clear the complete state of all items', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - // Check and then immediately uncheck. - await toggleAll.check(); - await toggleAll.uncheck(); - - // Should be no completed classes. - await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); - }); - - test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - await toggleAll.check(); - await expect(toggleAll).toBeChecked(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Uncheck first todo. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').uncheck(); - - // Reuse toggleAll locator and make sure its not checked. - await expect(toggleAll).not.toBeChecked(); - - await firstTodo.getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Assert the toggle all is checked again. - await expect(toggleAll).toBeChecked(); - }); -}); - -test.describe('Item', () => { - - test('should allow me to mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - // Check first item. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').check(); - await expect(firstTodo).toHaveClass('completed'); - - // Check second item. - const secondTodo = page.getByTestId('todo-item').nth(1); - await expect(secondTodo).not.toHaveClass('completed'); - await secondTodo.getByRole('checkbox').check(); - - // Assert completed class. - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).toHaveClass('completed'); - }); - - test('should allow me to un-mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const firstTodo = page.getByTestId('todo-item').nth(0); - const secondTodo = page.getByTestId('todo-item').nth(1); - const firstTodoCheckbox = firstTodo.getByRole('checkbox'); - - await firstTodoCheckbox.check(); - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await firstTodoCheckbox.uncheck(); - await expect(firstTodo).not.toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 0); - }); - - test('should allow me to edit an item', async ({ page }) => { - await createDefaultTodos(page); - - const todoItems = page.getByTestId('todo-item'); - const secondTodo = todoItems.nth(1); - await secondTodo.dblclick(); - await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); - await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); - - // Explicitly assert the new text value. - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2] - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); -}); - -test.describe('Editing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should hide other controls when editing', async ({ page }) => { - const todoItem = page.getByTestId('todo-item').nth(1); - await todoItem.dblclick(); - await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); - await expect(todoItem.locator('label', { - hasText: TODO_ITEMS[1], - })).not.toBeVisible(); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should save edits on blur', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should trim entered text', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should remove the item if an empty text string was entered', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[2], - ]); - }); - - test('should cancel edits on escape', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); - await expect(todoItems).toHaveText(TODO_ITEMS); - }); -}); - -test.describe('Counter', () => { - test('should display the current number of todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - await expect(todoCount).toContainText('1'); - - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - await expect(todoCount).toContainText('2'); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); -}); - -test.describe('Clear completed button', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - }); - - test('should display the correct text', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); - }); - - test('should remove completed items when clicked', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).getByRole('checkbox').check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(todoItems).toHaveCount(2); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should be hidden when there are no items that are completed', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); - }); -}); - -test.describe('Persistence', () => { - test('should persist its data', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const todoItems = page.getByTestId('todo-item'); - const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); - await firstTodoCheck.check(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - - // Ensure there is 1 completed item. - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - // Now reload. - await page.reload(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - }); -}); - -test.describe('Routing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - // make sure the app had a chance to save updated todos in storage - // before navigating to a new view, otherwise the items can get lost :( - // in some frameworks like Durandal - await checkTodosInLocalStorage(page, TODO_ITEMS[0]); - }); - - test('should allow me to display active items', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await expect(todoItem).toHaveCount(2); - await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should respect the back button', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await test.step('Showing all items', async () => { - await page.getByRole('link', { name: 'All' }).click(); - await expect(todoItem).toHaveCount(3); - }); - - await test.step('Showing active items', async () => { - await page.getByRole('link', { name: 'Active' }).click(); - }); - - await test.step('Showing completed items', async () => { - await page.getByRole('link', { name: 'Completed' }).click(); - }); - - await expect(todoItem).toHaveCount(1); - await page.goBack(); - await expect(todoItem).toHaveCount(2); - await page.goBack(); - await expect(todoItem).toHaveCount(3); - }); - - test('should allow me to display completed items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Completed' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(1); - }); - - test('should allow me to display all items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await page.getByRole('link', { name: 'Completed' }).click(); - await page.getByRole('link', { name: 'All' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(3); - }); - - test('should highlight the currently applied filter', async ({ page }) => { - await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); - - //create locators for active and completed links - const activeLink = page.getByRole('link', { name: 'Active' }); - const completedLink = page.getByRole('link', { name: 'Completed' }); - await activeLink.click(); - - // Page change - active items. - await expect(activeLink).toHaveClass('selected'); - await completedLink.click(); - - // Page change - completed items. - await expect(completedLink).toHaveClass('selected'); - }); -}); - -async function createDefaultTodos(page: Page) { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } -} - -async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).length === e; - }, expected); -} - -async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; - }, expected); -} - -async function checkTodosInLocalStorage(page: Page, title: string) { - return await page.waitForFunction(t => { - return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); - }, title); -} From 04d10cad28e9a46874a83d0898ee5fc779cef58f Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:05:17 +0200 Subject: [PATCH 2/6] set the trace config --- playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright.config.ts b/playwright.config.ts index 390646d..cd599c8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -29,7 +29,7 @@ export default defineConfig({ // baseURL: 'http://localhost:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: process.env.CI ? 'on' : 'retain-on-failure', }, /* Configure projects for major browsers */ From 9d6d0f0fe5f81c8667c018e1ea818336532d0173 Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:05:42 +0200 Subject: [PATCH 3/6] update README.md --- README.md | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ec40cb..5aa7a79 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,192 @@ # test-automation-playwright-ts -A web test automation framework, powered by Playwright with TypeScript + +[![Playwright Tests](https://img.shields.io/badge/playwright-%20test-blue)](https://playwright.dev/) [![TypeScript](https://img.shields.io/badge/TypeScript-%5E4.0-blue)](https://www.typescriptlang.org/) ![Status](https://img.shields.io/badge/status-draft-lightgrey) + +A starter/test automation repository using Playwright with TypeScript. This project provides patterns, recommended configuration, and examples for end-to-end web testing with Playwright test runner, TypeScript, and modern CI practices. + +## Overview + +This repository demonstrates a pragmatic setup for automated UI tests using Playwright and TypeScript. It is intended as a foundation you can adapt to your own product tests. Key goals: +- Fast, reliable E2E tests using Playwright Test +- TypeScript-first developer experience +- Clear structure for tests, fixtures, and page objects +- Recommended CI integration and reproducible local runs +- Support for traces, videos, and HTML reports for debugging failures + +--- + +## Prerequisites + +- Node.js (up to v 22.20) +- TypeScript (up to 4.9.5) +- yarn (1.22.22) +- Playwright (>= 1.48.1) + +--- + +## Quick start + +1. Clone the repository + ```bash + git clone https://github.com/nickIsNotUnique/test-automation-playwright-ts.git + cd test-automation-playwright-ts + ``` + +2. Install dependencies and Playwright browsers + ```bash + yarn install + yarn playwright install + ``` + +3. Verify your installation by running the test suite + ```bash + yarn playwright test + ``` + +--- + +## Useful commands + +- Run a single test file: + ```bash + yarn playwright test tests/example.spec.ts + ``` +- Run with grep (run only tests that match a tag): + ```bash + yarn playwright test --grep @smoke + ``` +- Debug a test with Playwright inspector: + ```bash + yarn playwright test --debug + ``` + +--- + +## Project structure + +This section describes a used layout + +- .github/workflows/ — CI workflows +- node_modules/ +- playwright-report/ +- test-results/ +- tests/ — Test files (e.g., *.spec.ts) +- .gitignore +- package.json +- playwright.config.ts — Playwright test runner configuration +- README.md +- tsconfig.json +- yarn.lock + +--- + +## CI: GitHub Actions + +This project uses GitHub Actions for continuous integration. +Available pipelines: + +### `playwright.yml` - Playwright Tests + +**Triggers:** +- Push to `main` or `master` branches +- Pull Request to `main` or `master` branches + +**Functions:** +- Checks out code from repository +- Sets up Node.js (latest LTS version) +- Installs dependencies via Yarn +- Installs Playwright browsers with all dependencies +- Runs all Playwright tests (`yarn playwright test`) +- Uploads test results as artifacts + +**Results:** +- **Report**: Playwright HTML report saved as artifact named `playwright-report` +- **Retention**: artifacts stored for 30 days +- **Timeout**: maximum execution time - 60 minutes +- **Platform**: runs on Ubuntu Latest +- Artifacts uploaded even if tests are cancelled or fail + +--- + +### `auto-simple-suite.yaml` - Auto run simple suite + +**Triggers:** +- Pull Request to `main` branch +- Manual run via workflow_dispatch + +**Functions:** +This workflow consists of **3 parallel jobs**: + +#### Job 1: `run-simple-suite` +- Checks out code +- Sets up Node.js version 22 with Yarn caching +- Installs dependencies +- Installs Chromium browser only +- **Runs smoke tests**: `yarn playwright test --project=chromium --grep @smoke` +- Uploads test results + +#### Job 2: `post-slack-notification-started` +- Sends Slack notification about **test execution start** +- Message: "The simple suite pipeline started" +- Uses webhook from `SLACK_WEBHOOK_URL` secret + +#### Job 3: `post-slack-notification-results` +- Depends on `run-simple-suite` completion +- Always runs (if: always()) +- Sends Slack notification with **execution result**: + - On success: "The simple suite pipeline succeeded" + - On failure: "The simple suite pipeline failed" + +**Results:** +- **Report**: test results saved as `simple-suite-results-{run_id}` +- **Retention**: artifacts stored for 7 days +- **Timeout**: maximum execution time - 15 minutes +- **Platform**: Ubuntu Latest +- **Notifications**: automatic Slack notifications about start and results +- Artifacts uploaded even if tests are cancelled or fail + +--- + +### `run-simple-suite.yaml` - Run simple suite + +**Triggers:** +- Manual run only via workflow_dispatch + +**Functions:** +- Identical to `run-simple-suite` job from the auto-simple-suite workflow +- Checks out code +- Sets up Node.js version 22 with Yarn caching +- Installs dependencies +- Installs Chromium browser only +- **Runs smoke tests**: `yarn playwright test --project=chromium --grep @smoke` +- Uploads test results + +**Results:** +- **Report**: test results saved as `simple-suite-results-{run_id}` +- **Retention**: artifacts stored for 7 days +- **Timeout**: maximum execution time - 15 minutes +- **Platform**: Ubuntu Latest +- **No Slack notifications** +- Artifacts uploaded even if tests are cancelled or fail + +--- + +### Comparison table: + +| Feature | playwright.yml | auto-simple-suite.yaml | run-simple-suite.yaml | +|---------|----------------|------------------------|----------------------| +| **Auto-trigger** | Push/PR | PR to main | No | +| **Manual trigger** | No | Yes | Yes | +| **Tests** | All | @smoke only | @smoke only | +| **Browsers** | All | Chromium | Chromium | +| **Timeout** | 60 min | 15 min | 15 min | +| **Artifact retention** | 30 days | 7 days | 7 days | +| **Slack notifications** | No | Yes | No | +| **Node.js** | LTS | v22 | v22 | + +--- + +## Resources + +- Playwright docs: https://playwright.dev/ +- Playwright GitHub examples: https://github.com/microsoft/playwright From f4d0229f713ad440bb0e6ae8e164ff148c0085a8 Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:12:50 +0200 Subject: [PATCH 4/6] update README.md --- README.md | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5aa7a79..90b0dba 100644 --- a/README.md +++ b/README.md @@ -9,18 +9,17 @@ A starter/test automation repository using Playwright with TypeScript. This proj This repository demonstrates a pragmatic setup for automated UI tests using Playwright and TypeScript. It is intended as a foundation you can adapt to your own product tests. Key goals: - Fast, reliable E2E tests using Playwright Test - TypeScript-first developer experience -- Clear structure for tests, fixtures, and page objects - Recommended CI integration and reproducible local runs -- Support for traces, videos, and HTML reports for debugging failures +- Support for traces, and HTML reports for debugging failures --- ## Prerequisites -- Node.js (up to v 22.20) -- TypeScript (up to 4.9.5) -- yarn (1.22.22) -- Playwright (>= 1.48.1) +- Node.js (~22.20.0) +- TypeScript (~5.9.2) +- yarn (~1.22.22) +- Playwright (~1.55.0) --- @@ -59,12 +58,15 @@ This repository demonstrates a pragmatic setup for automated UI tests using Play ```bash yarn playwright test --debug ``` - +- View test report: + ```bash + yarn playwright show-report + ``` --- ## Project structure -This section describes a used layout +This section describes the project layout - .github/workflows/ — CI workflows - node_modules/ @@ -115,7 +117,7 @@ Available pipelines: - Manual run via workflow_dispatch **Functions:** -This workflow consists of **3 parallel jobs**: +This workflow consists of **3 jobs**: #### Job 1: `run-simple-suite` - Checks out code @@ -171,21 +173,6 @@ This workflow consists of **3 parallel jobs**: --- -### Comparison table: - -| Feature | playwright.yml | auto-simple-suite.yaml | run-simple-suite.yaml | -|---------|----------------|------------------------|----------------------| -| **Auto-trigger** | Push/PR | PR to main | No | -| **Manual trigger** | No | Yes | Yes | -| **Tests** | All | @smoke only | @smoke only | -| **Browsers** | All | Chromium | Chromium | -| **Timeout** | 60 min | 15 min | 15 min | -| **Artifact retention** | 30 days | 7 days | 7 days | -| **Slack notifications** | No | Yes | No | -| **Node.js** | LTS | v22 | v22 | - ---- - ## Resources - Playwright docs: https://playwright.dev/ From b7daad898752affa4d59fd1dd4a7d4f1eabd679f Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:20:51 +0200 Subject: [PATCH 5/6] update badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 90b0dba..7c081d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # test-automation-playwright-ts -[![Playwright Tests](https://img.shields.io/badge/playwright-%20test-blue)](https://playwright.dev/) [![TypeScript](https://img.shields.io/badge/TypeScript-%5E4.0-blue)](https://www.typescriptlang.org/) ![Status](https://img.shields.io/badge/status-draft-lightgrey) +[![Playwright Tests](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml/badge.svg)](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml) +![Status](https://img.shields.io/badge/status-draft-lightgrey) A starter/test automation repository using Playwright with TypeScript. This project provides patterns, recommended configuration, and examples for end-to-end web testing with Playwright test runner, TypeScript, and modern CI practices. From 14b64c4c648290761ac6a1ba1cd04bc24a35c4db Mon Sep 17 00:00:00 2001 From: Daria Domina Date: Sat, 11 Oct 2025 13:50:57 +0200 Subject: [PATCH 6/6] update README.md --- README.md | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7c081d8..08e9f47 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # test-automation-playwright-ts -[![Playwright Tests](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml/badge.svg)](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml) -![Status](https://img.shields.io/badge/status-draft-lightgrey) +[![Playwright Tests](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml/badge.svg)](https://github.com/nickIsNotUnique/test-automation-playwright-ts/actions/workflows/playwright.yml) ![Status](https://img.shields.io/badge/educational-project-green) -A starter/test automation repository using Playwright with TypeScript. This project provides patterns, recommended configuration, and examples for end-to-end web testing with Playwright test runner, TypeScript, and modern CI practices. +This repository serves as a **practical demonstration** of implementing Playwright test automation with GitHub Actions CI/CD. Created as companion code for my article series [ "Playwright testing with GitHub Actions"](https://nickisnotunique.substack.com/profile/posts). This project provides patterns, recommended configuration, and examples for end-to-end web testing with Playwright test runner, TypeScript, and modern CI practices. ## Overview @@ -15,6 +14,14 @@ This repository demonstrates a pragmatic setup for automated UI tests using Play --- +## Key Features + +- **CI/CD Workflows**: Full suite, auto smoke tests, manual smoke runs +- **Optimized Caching**: Yarn cache for faster CI runs +- **Slack Integration**: Automated notifications for test results + +--- + ## Prerequisites - Node.js (~22.20.0) @@ -89,6 +96,10 @@ This project uses GitHub Actions for continuous integration. Available pipelines: ### `playwright.yml` - Playwright Tests +#### Summary: +- Runs on every push to main/master +- Executes complete test coverage +- Ideal for: Release validation, nightly builds **Triggers:** - Push to `main` or `master` branches @@ -112,6 +123,11 @@ Available pipelines: --- ### `auto-simple-suite.yaml` - Auto run simple suite +#### Summary: +- Triggers on PRs to main +- Runs critical path tests only +- Includes Slack notifications +- Ideal for: PR validation, quick feedback loops **Triggers:** - Pull Request to `main` branch @@ -151,6 +167,10 @@ This workflow consists of **3 jobs**: --- ### `run-simple-suite.yaml` - Run simple suite +#### Summary: +- Manually triggered via GitHub UI +- No notifications (focused testing) +- Ideal for: Ad-hoc testing, debugging, demos **Triggers:** - Manual run only via workflow_dispatch @@ -174,6 +194,22 @@ This workflow consists of **3 jobs**: --- +## Author + +- GitHub: [@nickIsNotUnique](https://github.com/nickIsNotUnique) +- Articles: [Substack](https://nickisnotunique.substack.com/profile/posts) + +This project is part of my article series "Playwright testing with GitHub Actions". + +--- + +## Feedback & Contributions + +Questions or suggestions? Feel free to: +- [Open an issue](https://github.com/nickIsNotUnique/test-automation-playwright-ts/issues) +- [Start a discussion](https://github.com/nickIsNotUnique/test-automation-playwright-ts/discussions) +- ⭐ Star this repo if you find it useful! + ## Resources - Playwright docs: https://playwright.dev/