IKivan-kozenko -aqa
Try yourself as a QA tester
All topics·Intermediate·7 / 27

Configuration (use)

The use: {} block in playwright.config.ts is where I set defaults for every test: baseURL so I write page.goto('/orders') instead of the full URL, storageState for auth, trace and screenshot modes for CI. I can override any of these per-project, per-file, or inside a describe block.

The two options I always set

baseURL is the one I miss most when it's not set. Without it every page.goto() needs the full http://localhost:3000 prefix. With it, I write /orders, /dashboard, /login and Playwright prepends the base. storageState points to a saved auth file — so every test starts already logged in without repeating the login flow.

ts
// playwright.config.ts
export default defineConfig({
  use: {
    baseURL: 'http://localhost:3000',
    storageState: 'playwright/.auth/user.json',
  },
})

Recording options — screenshots, traces, video

My standard CI setup: trace: 'on-first-retry' records a trace only when a test retries (meaning it failed). screenshot: 'only-on-failure' grabs a screenshot when the test fails. Both go to test-results/ and get uploaded as artifacts. I never use 'on' for either in CI — storage costs add up fast.

Video is expensive (CPU and storage). I use 'retain-on-failure' rather than 'on-first-retry' for video because video is useful even on the first failure, not just retries.

ts
// playwright.config.ts
export default defineConfig({
  use: {
    screenshot: 'only-on-failure',
    trace: 'on-first-retry',
    video: 'retain-on-failure',
  },
})

Emulation — locale, timezone, viewport, color scheme

I reach for these when testing locale-specific behavior (date formats, currency display) or when I need to verify dark mode. Setting locale here means every test sees the same locale without any per-test setup.

ts
// playwright.config.ts — емуляція для тестування локалізації
export default defineConfig({
  use: {
    locale: 'uk-UA',
    timezoneId: 'Europe/Kyiv',
    colorScheme: 'dark',
    viewport: { width: 1280, height: 720 },
    geolocation: { longitude: 30.523, latitude: 50.452 },
    permissions: ['geolocation'],
  },
})

Network options

extraHTTPHeaders is useful when the app expects an internal auth header (X-Internal-Token) that the browser doesn't add automatically. ignoreHTTPSErrors I turn on for staging environments where the SSL cert isn't always valid. offline: true is for testing the 'no connection' UI path.

ts
// playwright.config.ts
export default defineConfig({
  use: {
    extraHTTPHeaders: {
      'X-Internal-Token': process.env.INTERNAL_TOKEN ?? '',
    },
    ignoreHTTPSErrors: true,  // для staging з самопідписаним cert
  },
})

Overriding use options — global, project, file, describe

The cascade: global use → project-level usetest.use() in a file. Each level overrides the previous. In practice I use this for locale testing — global config sets en-US, a specific test file overrides to fr-FR for French locale tests.

To reset an option back to the config-level value, set it to undefined. To completely unset it (so not even the config default applies), use the long-form fixture notation.

ts
// playwright.config.ts — глобальна локаль + перевизначення на рівні проєкту
export default defineConfig({
  use: { locale: 'en-US' },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'], locale: 'de-DE' },
    },
  ],
})
ts
// french-locale.spec.ts — перевизначення у файлі
test.use({ locale: 'fr-FR' })

test('date format shows DD/MM/YYYY', async ({ page }) => {
  await page.goto('/orders')
  // тест бачить fr-FR локаль
})
ts
// Перевизначення всередині describe-блоку
test.describe('french locale', () => {
  test.use({ locale: 'fr-FR' })

  test('currency shows €', async ({ page }) => {
    await page.goto('/dashboard')
  })
})
ts
// Скинути baseURL до значення конфігу для одного тесту
test.use({ baseURL: 'https://staging.example.com' })

test.describe(() => {
  test.use({ baseURL: undefined })  // повертає до конфігу

  test('uses config baseURL', async ({ page }) => {
    await page.goto('/orders')
  })
})

Other options worth knowing

actionTimeout: 0 means no timeout per action — the default. I override this to 5000 when the app is slow to respond to clicks. testIdAttribute I change when the team uses data-cy instead of data-testid — then getByTestId() works with their attribute. headless: false for local debugging runs.

ts
// playwright.config.ts
export default defineConfig({
  use: {
    actionTimeout: 5000,
    testIdAttribute: 'data-cy',  // якщо команда використовує Cypress-атрибути
    headless: !process.env.PWDEBUG,  // headed коли PWDEBUG задано
  },
})