DEV Community

98IP Proxy
98IP Proxy

Posted on

Build a Cancellable Proxy Test Harness with Playwright 1.62

Proxy tests need two clocks: a technical timeout for each operation and a business deadline for the workflow. Playwright 1.62 makes that distinction easier because most operations and web-first assertions can now accept an AbortSignal.

This tutorial builds a small pattern that cancels late work, records the reason, and keeps cleanup predictable. It then shows how the new isolated retry strategy can separate concurrency failures from persistent route failures.

1. Create a workflow-level deadline

import { test, expect } from '@playwright/test';

function workflowDeadline(ms: number) {
  const controller = new AbortController();
  const timer = setTimeout(
    () => controller.abort(new Error('workflow_deadline')),
    ms,
  );

  return {
    signal: controller.signal,
    dispose: () => clearTimeout(timer),
  };
}

test('regional route stays inside the useful window', async ({ page }) => {
  const deadline = workflowDeadline(20_000);

  try {
    await page.goto(process.env.TEST_URL!, {
      waitUntil: 'domcontentloaded',
      timeout: 15_000,
      signal: deadline.signal,
    });

    await expect(page.locator('body')).toBeVisible({
      timeout: 5_000,
      signal: deadline.signal,
    });
  } finally {
    deadline.dispose();
  }
});
Enter fullscreen mode Exit fullscreen mode

The operation timeout and the signal are intentionally different. The navigation timeout identifies a slow navigation. The signal says the complete result is no longer useful.

2. Keep credentials out of the test

Load proxy settings from environment variables or a secret manager:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    proxy: {
      server: process.env.PROXY_SERVER!,
      username: process.env.PROXY_USERNAME,
      password: process.env.PROXY_PASSWORD,
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Never include credentials in test titles, screenshots, trace attachments, console messages, or published examples.

3. Classify an abort as its own outcome

Your result model should separate at least these states:

type Outcome =
  | 'passed'
  | 'workflow_deadline'
  | 'operation_timeout'
  | 'proxy_auth_failure'
  | 'target_policy_response'
  | 'unexpected_error';
Enter fullscreen mode Exit fullscreen mode

Also capture the route label, elapsed time, last completed phase, retry number, and a session identifier that contains no credential material.

Do not automatically retry every abort. A deadline abort can mean the work has already lost its value. Retry only idempotent operations when the failure policy says another attempt is useful.

4. Isolate retries from normal traffic

Playwright 1.62 adds retryStrategy: 'isolated':

import { defineConfig } from '@playwright/test';

export default defineConfig({
  retries: 1,
  retryStrategy: 'isolated',
  workers: 6,
});
Enter fullscreen mode Exit fullscreen mode

The first run still measures the concurrent workload. Failed tests are retried at the end, one at a time in one worker.

Interpret the result carefully:

  • Fails concurrently, passes alone: investigate quotas, shared sessions, connection pools, and destination throttling.
  • Fails concurrently and alone: inspect route health, target compatibility, DNS/TLS, configuration, and deterministic test bugs.
  • Passes first try: do not mix it with recovered retries in the same success metric.

Isolation is a diagnostic control, not proof of root cause.

5. Report metrics that buyers can use

For each provider and route cohort, report:

  • first-attempt success rate;
  • retry recovery rate;
  • final success rate;
  • p50 and p95 latency;
  • workflow-deadline cancellations;
  • unexpected exit changes;
  • bytes transferred by successful, failed, and aborted attempts;
  • cost per usable workflow.

This prevents a high final success rate from hiding an expensive retry dependency.

Cleanup checklist

  • Clear deadline timers in finally.
  • Close pages and contexts after cancellation.
  • Confirm background requests stop.
  • Release session leases explicitly.
  • Keep abort reasons stable and machine-readable.
  • Preserve operation timeouts for diagnosis.
  • Respect per-account, per-region, and per-destination concurrency limits.

Only test systems and data you are authorized to access. Respect destination terms, rate limits, privacy obligations, and regional requirements.

Disclosure: I work with 98IP. We publish practical proxy testing and operations guidance at https://en.98ip.com/?k=dev

Top comments (0)