On this page10 sections

Playwright — Automate a Login Flow

Write a Playwright + TypeScript test suite for a login page: happy path, wrong credentials, lockout, session persistence, and a Page Object Model structure.

Role

Automation QA engineer

Difficulty

Intermediate

Time limit

90–120 min

Category

ui automation

PlaywrightTypeScriptNode.js 18+

Scenario

You have been given access to the Sauce Demo application (https://www.saucedemo.com) — a purpose-built demo site for automation practice. Your task is to write a Playwright + TypeScript test suite for the login flow that a real team could drop into a CI pipeline on day one. You must structure the code using the Page Object Model; the suite must pass `npx tsc --noEmit` with no type errors.

Requirements

  • 1.Create a LoginPage class with locators and action methods (no locators or clicks inside test files)
  • 2.Write at least 5 test cases: standard_user login (success), locked_out_user (error message), wrong password (error message), empty email (validation), empty password (validation)
  • 3.Assert the exact error message text for failure cases — not just that an error element exists
  • 4.After a successful login, assert that the URL changes to /inventory.html or a named element confirming the user is logged in
  • 5.Tests must run headlessly with `npx playwright test` and produce a passing HTML report
  • 6.The suite must have zero TypeScript errors: `npx tsc --noEmit` must exit 0
  • 7.Store the base URL and test credentials in a config object or .env — do not hardcode them in test files

Starter data

  • Target app: https://www.saucedemo.com
  • standard_user / secret_sauce — logs in successfully
  • locked_out_user / secret_sauce — shows 'Sorry, this user has been locked out.'
  • problem_user / secret_sauce — logs in but with broken UI elements (useful for extension task)
  • Login page URL: https://www.saucedemo.com/
  • Post-login URL: https://www.saucedemo.com/inventory.html
  • Error element selector (for reference, prefer role-based): [data-test='error']

Expected deliverables

  • A TypeScript Playwright project that can be cloned and run with `npm install && npx playwright test`
  • A LoginPage class in a pages/ or page-objects/ directory
  • A login.spec.ts file with at least 5 test cases
  • A playwright.config.ts configuring at minimum: baseURL, headless mode, HTML reporter
  • Output of `npx playwright test` showing all tests passing
  • Output of `npx tsc --noEmit` showing zero errors

Evaluation rubric

DimensionWhat reviewers look for
Page Object Model correctnessAre all locators and browser interactions encapsulated in LoginPage? Do test files contain only assertions and high-level action calls (loginPage.login(email, pass))? Are locators using role-based selectors (getByRole, getByLabel) rather than CSS classes?
Test case qualityAre assertions specific? Does the successful login test assert the URL or a page-level element, not just 'no error was shown'? Do error-case tests assert the exact message text?
TypeScript qualityIs strict mode respected? Are there any implicit `any` types? Are Playwright types used correctly (Locator vs ElementHandle, Page vs Browser)?
Playwright idiomsDoes the suite use auto-wait locators rather than manual waitForTimeout() calls? Is each test independent (no shared page state from a previous test)? Are fixtures used if multiple tests share setup?
ConfigurationIs the base URL set in playwright.config.ts rather than hardcoded in test files? Are credentials sourced from environment variables or a config object?
RunnabilityDoes `npm install && npx playwright install && npx playwright test` succeed without manual intervention? Is there a README with setup instructions?

Sample solution outline

  • playwright.config.ts: baseURL = process.env.BASE_URL || 'https://www.saucedemo.com', use: { headless: true }, reporter: 'html'
  • pages/LoginPage.ts: constructor(private page: Page); usernameInput = page.getByLabel('Username'); passwordInput = page.getByLabel('Password'); loginButton = page.getByRole('button', { name: 'Login' }); errorMessage = page.getByTestId('error'); async login(u, p) { await this.usernameInput.fill(u); await this.passwordInput.fill(p); await this.loginButton.click(); }
  • tests/login.spec.ts: import { test, expect } from '@playwright/test'; import { LoginPage } from '../pages/LoginPage'; test.beforeEach(async ({ page }) => { await page.goto('/'); })
  • TC-01: new LoginPage(page).login('standard_user', 'secret_sauce'); expect(page).toHaveURL('/inventory.html');
  • TC-02: LoginPage.login('locked_out_user', 'secret_sauce'); expect(loginPage.errorMessage).toHaveText('Epic sadface: Sorry, this user has been locked out.');
  • TC-03: LoginPage.login('standard_user', 'wrong_password'); expect(loginPage.errorMessage).toContainText('Epic sadface: Username and password do not match');
  • TC-04: LoginPage.login('', 'secret_sauce'); expect(loginPage.errorMessage).toHaveText('Epic sadface: Username is required');
  • TC-05: LoginPage.login('standard_user', ''); expect(loginPage.errorMessage).toHaveText('Epic sadface: Password is required');

Common mistakes

  • Putting `page.goto()`, `page.fill()`, or `page.click()` directly inside test files instead of in the Page Object — this is the most common structural error and immediately signals that the candidate doesn't understand POM
  • Using `page.waitForTimeout(2000)` to wait for navigation instead of `await expect(page).toHaveURL(...)` — Playwright auto-waits; explicit timeouts create flakiness
  • Asserting `expect(errorDiv).toBeVisible()` without checking the text — two different error conditions could both show a visible error, making the assertion too weak
  • Hardcoding `https://www.saucedemo.com` in test files — the base URL must come from playwright.config.ts so it is overridable per environment
  • A single test that runs all 5 scenarios sequentially — tests must be independent; a single `test()` block with 5 sets of actions is not 5 tests
  • No `await` on Playwright actions — TypeScript and the Playwright ESLint plugin catch this, but missing awaits cause tests to pass spuriously

Submission checklist

  • Project has a package.json, playwright.config.ts, and a pages/ directory
  • LoginPage class is in pages/ with all locators and no test assertions
  • login.spec.ts has at least 5 independent test cases (separate test() calls)
  • All tests pass: `npx playwright test` exits 0
  • No type errors: `npx tsc --noEmit` exits 0
  • Base URL and credentials are not hardcoded in test files
  • README explains how to install and run

Extension ideas

  • +Add a test for problem_user login and assert that at least one product image on /inventory.html is broken (src contains 'sl-404')
  • +Refactor to use Playwright fixtures: a `loggedInPage` fixture that skips the login UI by using storageState
  • +Add a data-driven test using test.each() covering all 4 user types and their expected post-login state