Skip to Content
QA Docs & Abangku 0.1.0 is released. Read more →
QA EngineerFrontend Testing (Playwright)

Frontend Testing (Playwright)

We use Playwright for Python, run through pytest, so frontend and backend tests share one runner and one Kiwi sync.

4.1 Manual first: inspect in the browser

Run the test case by hand first, with the browser’s developer tools open, and record it in the Excel run sheet (section 2.6).

Open developer tools with F12, or right-click an element and choose Inspect.

What to look at

TabUse it to check
ElementsThe element really is what it looks like: <button> vs a styled <div>, type="password" on the password field, disabled, and the visible label
ConsoleNo JavaScript errors while you use the page. Red errors are findings, even when the screen looks fine
NetworkThe request behind a button: its status (4xx/5xx show in red), how long it took, and whether clicking twice sends it twice

Also switch on the device toolbar (Ctrl+Shift+M) to check the page on a narrow screen.

Note the locator while you inspect

In the run sheet’s Notes column, write how the element can be identified: its role and visible label, its name, or a data-testid. That note becomes the locator when you automate the case later (section 4.4), and it’s the moment to ask developers for a data-testid if an element has nothing stable to grab.

What goes in the run sheet

Expected result (before)Actual result (after)
Login button visible and clickableVisible, enabled, label “Log in”
Password is maskedinput[name="password"] has type="password"
Wrong password keeps the user on the login pageStayed on /accounts/login/, error message shown
No console errorsConsole clean

Evidence: a screenshot (Win+Shift+S), plus a screenshot of the Console or Network tab if something failed there.

4.2 Setup

py -3.11 -m venv .venv .venv\Scripts\activate.bat python -m pip install pytest pytest-playwright requests

On company laptops, use the Edge already installed instead of downloading a browser. Put this in pytest.ini:

[pytest] testpaths = tests addopts = -v -rA --browser-channel msedge --screenshot only-on-failure --tracing retain-on-failure --output test-results

4.3 Finding elements: use codegen first

playwright codegen --channel msedge https://<your app>/

Hover over any element to see the locator Playwright suggests, and click around to generate code. Start every new UI test from here, using the locator you noted during the manual run (section 4.1).

Pick locators in this order:

  1. By role and name: page.get_by_role("button", name="Log in")
  2. By label: page.get_by_label("Email")
  3. By form field name or test ID: page.locator('input[name="username"]'), page.get_by_test_id("submit")

Never use CSS classes or positions (div > div:nth-child(3) > button). They break on the next redesign.

4.4 How a test looks

@pytest.mark.kiwi_case(4) def test_WEB_KIWILOGIN_003_unknown_user_stays_on_login_page(login_page): login_page.locator('input[name="username"]').fill("qa-user-that-does-not-exist") login_page.locator('input[name="password"]').fill("wrong-password-123") login_page.get_by_role("button", name="Log in").click() expect(login_page).to_have_url(re.compile(r"/accounts/login/"))
  • Steps are Playwright actions: .fill(), .click().
  • Expected results are expect(...) checks. expect waits automatically until the page is ready, so never use sleep().

4.5 What to check on every screen

  • The main action works (happy path).
  • Wrong input shows a clear error message.
  • Buttons are disabled or hidden for users who can’t use them.
  • Empty state: what shows when there’s no data.
  • Error state: what shows when the backend fails.

4.6 Running and debugging

What you wantCommand
Run everythingpytest
Watch it in the browserpytest --headed --slowmo 1000
Step through one testset PWDEBUG=1 then pytest -k 003
Look at a failed testplaywright show-trace test-results\<test folder>\trace.zip

A failed test leaves a screenshot and a trace in test-results\. Attach the screenshot to the failed execution in Kiwi.