Bridge Exercise · Junior → Mid-Level SDET

Bridge Exercise: Junior Tester to SDET

You’ve found a bug manually. Now automate the regression test that would catch it next time. Part 1 is manual testing. Part 2 is writing the Playwright test.

Bridge Exercise ~45 min · Practical exercise
Scenario: Resync Store — NZ E-commerce Checkout

You are testing the guest checkout flow for Resync Store — a fictional NZ e-commerce site selling safety equipment. During exploratory testing, you discover a defect in the coupon code field.

The bug: When a customer leaves the “Coupon code” field blank and clicks “Apply coupon”, the page shows a JavaScript error (TypeError: Cannot read properties of undefined) instead of the expected validation message “Please enter a coupon code.”

Part 1 — Write the Bug Report

Document this defect as a formal bug report. Include all required fields: title, severity, environment, steps to reproduce, expected result, actual result, and any evidence you would attach.

Think about: what severity is this? Why? What environment details matter? How do you word “expected” vs “actual” precisely?

Model Bug Report

TITLE: Blank coupon code input causes JavaScript TypeError on checkout page instead of validation message SEVERITY: Medium — functional defect visible to users, no data loss, workaround exists (enter any text then clear) PRIORITY: High — checkout is a critical user journey; JS errors reduce customer confidence and may affect conversion rate ENVIRONMENT: Browser: Chrome 125.0.6422.76 (Windows 11) Also reproduced: Firefox 126, Edge 125 URL: https://store.resync.nz/checkout User type: Guest (not logged in) Account: Not required (guest checkout) STEPS TO REPRODUCE: 1. Navigate to https://store.resync.nz/checkout with at least one item in cart 2. Scroll to the "Coupon code" section 3. Leave the coupon code field EMPTY (do not type anything) 4. Click the "Apply coupon" button EXPECTED: Validation message displays: "Please enter a coupon code." No JavaScript errors in the browser console. ACTUAL: Page displays: "TypeError: Cannot read properties of undefined (reading 'trim')" Error appears inline on the page (not just in console). No validation message shown. EVIDENCE: - Screenshot: checkout-blank-coupon-error.png - Browser console log: checkout-console-error.txt (Attach both to this report) NOTES: - Entering any text (even a space) in the coupon field and clicking Apply shows the correct "Invalid coupon code" message — workaround exists - Defect introduced in release v2.3.1 (coupon field validation refactor) - Suggest: add null/empty check before calling .trim() on coupon input value

Part 2 — Write the Playwright Regression Test

Now write the Playwright test that would catch this bug in regression. The test should navigate to checkout, leave the coupon field blank, click Apply, and assert the correct validation message appears — not a JS error.

Consider: which assertion confirms the bug is fixed? Which assertion confirms the JS error is not showing? Use role-based selectors.

Model Playwright Test

import { test, expect } from '@playwright/test'; test.describe('Checkout coupon validation', () => { test('blank coupon code shows validation message, not JS error', async ({ page }) => { // Arrange: navigate to checkout with an item in cart await page.goto('/checkout'); // Ensure the coupon section is visible (it may be collapsed by default) const couponToggle = page.getByRole('button', { name: /coupon/i }); if (await couponToggle.isVisible()) { await couponToggle.click(); } // Act: leave coupon field empty and click Apply // Field is already empty — do not type anything await page.getByRole('button', { name: 'Apply coupon' }).click(); // Assert: correct validation message is shown await expect( page.getByText('Please enter a coupon code') ).toBeVisible(); // Assert: no JS error text is present anywhere on the page await expect(page.locator('body')).not.toContainText('TypeError'); await expect(page.locator('body')).not.toContainText('Cannot read properties of undefined'); }); });
Key learning: This is the shift-left automation loop. The manual investigation defines what to test. The automation makes it repeatable. Notice the two assertions: one positive (validation message appears) and one negative (error text does not appear). Both are necessary — you could pass the first assertion while still showing the error if your validation message also appeared. The negative assertion is the one that directly catches this specific bug.

Senior engineer insight

The hardest mental shift from junior tester to SDET isn’t learning Playwright syntax — it’s accepting that your test code is production code. In NZ teams I’ve worked with, junior testers often treat automation scripts as “good enough if it passes”, but when that script is running in CI for 18 months and blocking deployments, every brittle selector and missing wait is a debt the whole team pays. The day I rewrote a colleague’s 400-line test file into 80 lines using a Page Object Model was the day I understood what SDET actually means: you’re an engineer who tests, not a tester who codes.

Most common mistake: treating the Playwright test as a recording of clicks rather than a specification of behaviour. Scripts that hardcode CSS selectors or assert on pixel coordinates fail the moment a designer updates the UI — role-based selectors and semantic assertions are the difference between a test suite that helps you and one that haunts you.

From the field

A Wellington-based fintech I worked with wanted to upskill three junior testers into SDETs over six months. The team assumed the blockers would be JavaScript syntax and async/await patterns — they were wrong. The real blockers were test design thinking: the testers kept writing tests that described what they clicked rather than what the system should guarantee. When a checkout test failed because a button moved 10px to the left, no one could explain whether the product behaviour had actually broken. We introduced a rule: every test must have a one-sentence statement of the invariant it protects, written as a comment above the test. That single practice — naming the guarantee, not the steps — transformed how those three engineers thought about their work, and within two months all three were contributing confidently to the team’s Playwright suite. The generalised lesson is that SDET is a thinking role before it is a coding role: teach people to reason about system contracts first, syntax second.

Why teams fail here

  • Promoting testers to SDET titles without giving them protected time to build coding fluency — they end up copy-pasting scripts they don’t understand, and the suite rots within a release cycle.
  • Skipping the manual-first discipline: new SDETs jump straight to writing automation without understanding the failure modes, so their tests pass against bugs because they never explored the edge cases that would expose them.
  • No code review culture for test code — in many NZ teams test files are invisible to senior engineers, so bad patterns (thread sleeps, fragile selectors, shared global state) compound unchecked until the suite takes 40 minutes and flakes 30% of runs.
  • Treating the transition as a one-off training event rather than a six-to-twelve month supported journey with paired reviews, deliberate mentorship on Page Object architecture, and explicit checkpoints on CI pipeline ownership.

Key takeaway

The bridge from junior tester to SDET is crossed the moment you stop thinking about what you clicked and start thinking about what the system is obligated to guarantee — everything else, including the Playwright API, is just vocabulary for expressing that guarantee in code.

Next Bridge: Mid-Level → Senior → Bridge Exercises Hub