{
  "id": 18051815,
  "title": "Your Playwright test is green. Your checkout is broken",
  "url": "https://urgent.news/2026/11/04/your-playwright-test-is-green-your-checkout-is-broken",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-04T01:51:54.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/arun_kt_bb670b3a571f5efd8/your-playwright-test-is-green-your-checkout-is-broken-5hef"
  },
  "original_language": "en",
  "account": "In many codebases, a Playwright test often appears: \"test (places an order, async ({ page })) => { await page.goto('/'); await page.getByLabel('Name').fill('Ada'); await page.getByRole('button',{name:'Place order'}).click(); await expect(page.getByRole('status')).toContainText('Order placed'); }\". This test passes despite the order API returning a 500 error and no data being saved. The test fails to detect the issue because the page displays a success message even if the server does not agree.\n\nFrontend patterns like optimistic UI, error swallowing, and checking response arrival, but not success, lead to this problem. These patterns display a success message, such as \"Order placed\", while the order never exists in the system.\n\nTo catch this issue, three methods can be used: fixing the response, reading the data back, and implementing a safety net for the entire suite.\n\nThe first fix involves asserting on the response, waiting for the request triggered by the click, and checking its status. This ensures the exact endpoint and status are verified, but requires remembering this check on every test that writes data.\n\nThe second approach reads the data back using a 201 status code from the API. It checks if the order was stored by calling a list endpoint and verifying if the order with name 'Ada' exists. This method catches when the server answers 200 and silently drops the write.\n\nFinally, the third option is a safety net for the entire suite. By using an automatic fixture, any test that encounters a server error (status code 500) will fail. This approach protects all tests, not just the ones added with the fix.",
  "summary": "Here is a Playwright test I've seen in almost every codebase I've worked on: test ( \" places an order \" , async ({ page }) => { await page . goto ( \" / \" ); await page . getByLabel ( \" Name \" ). fill ( \" Ada \" ); await page . getByRole ( \" button \" , { name : \" Place order \" }). click (); await expect ( page . getByRole ( \" status \" )). toContainText ( \" Order placed \" ); }); Good locators, a…",
  "key_points": [
    "Playwright test passes despite API returning 500 error",
    "Optimistic UI and error swallowing cause issue",
    "Fix response, read data back, or implement safety net"
  ],
  "editors_take": "Relying on superficial UI feedback rather than verifying backend responses creates a false sense of security that allows critical API failures to bypass automated testing suites.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}