.agents/skills/e2e-cucumber-playwright/references/playwright-best-practices.md
Use this reference when writing or reviewing locator, assertion, isolation, or synchronization logic for Dify's Cucumber-based E2E suite.
Official sources:
Playwright's model is built around clean browser contexts so one test does not leak into another. In Dify's suite, that principle maps to per-scenario session setup in features/support/hooks.ts and DifyWorld.
Apply it like this:
DifyWorld@fresh behaviorPlaywright recommends built-in locators that reflect what users perceive on the page.
Preferred order in this repository:
getByRolegetByLabelgetByPlaceholdergetByTextgetByTestId when an explicit test contract is the most stable optionAvoid raw CSS/XPath selectors unless no stable user-facing contract exists and adding one is not practical.
Also remember:
getByTestId is acceptable when semantics are weak but the contract is intentionalPlaywright assertions auto-wait and retry. Prefer them over manual state inspection.
Prefer:
await expect(page).toHaveURL(...)await expect(locator).toBeVisible()await expect(locator).toBeHidden()await expect(locator).toBeEnabled()await expect(locator).toHaveText(...)Avoid:
expect(await locator.isVisible()).toBe(true)waitForTimeout as synchronizationIf a condition genuinely needs custom retry logic, use Playwright's polling/assertion tools deliberately and keep that choice local and explicit.
Locator actions already wait for the element to be actionable. Do not preface every click/fill with extra timing logic unless the action needs a specific visible/ready assertion for clarity.
Good pattern:
Bad pattern:
Playwright's wider ecosystem supports traces and rich debugging tools. Dify's current suite already captures:
Use the existing artifact flow by default. If a task is specifically about improving diagnostics, confirm the change fits the current Cucumber architecture before importing broader Playwright tooling.
DifyWorld + step-definition model?