DEV Community

Mangai Ram
Mangai Ram

Posted on

How I Found a Hidden Login Bug in a Predictive Dialer Using Playwright — And What It Taught Me

Testing a complex telephony platform revealed something unexpected: not all user agents are created equal.


First, What Even Is a Predictive Dialer?

If you're not from a contact center or sales tech background, you might be wondering — what exactly is a predictive dialer?

I'll give you the short version before we get into the QA story.

A predictive dialer is a system used in call centers that automatically dials phone numbers from a contact list and connects answered calls to available agents — all in real time. The "predictive" part means it uses algorithms to predict when an agent will be free and starts dialing the next number before the current call ends, minimizing idle time.

Modern predictive dialers — like the ones built on platforms such as ClearTouch — have evolved far beyond simple auto-dialing. Today's AI-powered dialers:

  • Rank leads by likelihood to answer
  • Detect voicemail vs live humans in real time
  • Adjust dialing pace dynamically based on agent availability
  • Feed context to agents before the call even begins
  • Learn from every call outcome to improve future decisions

Essentially, the platform is a decision engine, not just a phone dialer.

Now imagine testing that.


My QA Assignment: Automated Login Testing for a Dialer Platform

As a QA Specialist, I was tasked with setting up automated end-to-end login tests for a web-based predictive dialer application. The goal was straightforward:

Verify that the login flow works reliably across different browsers and user environments.

Simple enough, right? I reached for Playwright — my go-to for browser automation — and got started.


The Setup

Here's how I structured the test suite:

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

const USER_AGENTS = [
  {
    name: 'Chrome Windows',
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  },
  {
    name: 'Firefox Linux',
    userAgent: 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/121.0',
  },
  {
    name: 'Safari macOS',
    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15',
  },
  {
    name: 'Chrome Android (Mobile)',
    userAgent: 'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.144 Mobile Safari/537.36',
  },
  {
    name: 'Legacy Edge (Old)',
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763',
  },
  {
    name: 'Headless Chrome (Bot-like)',
    userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.0.0 Safari/537.36',
  },
];

for (const ua of USER_AGENTS) {
  test(`Login should succeed - ${ua.name}`, async ({ browser }) => {
    const context = await browser.newContext({ userAgent: ua.userAgent });
    const page = await context.newPage();

    await page.goto('https://dialer-app.example.com/login');
    await page.fill('#username', 'testuser@qa.com');
    await page.fill('#password', 'SecurePass@123');
    await page.click('#login-btn');

    await expect(page).toHaveURL(/.*dashboard/, { timeout: 10000 });
    await expect(page.locator('.agent-panel')).toBeVisible();

    await context.close();
  });
}
Enter fullscreen mode Exit fullscreen mode

Clean, readable, scalable. I ran it and... most tests passed.

But not all.


The Bug: Certain User Agents Silently Blocked Login

Two specific user agents were failing:

  1. Legacy Edge (EdgeHTML 18)
  2. Headless Chrome (the raw HeadlessChrome/ string in the UA)

The behavior was strange. The tests weren't throwing errors. The login form was submitting. But instead of redirecting to the dashboard, the page was either:

  • Refreshing back to the login screen silently, OR
  • Showing a blank white page with no error message

No toast. No 401. No console error visible to the user. Just... nothing.

Here's the Playwright assertion that caught it:

// This was FAILING for the two problematic UAs
await expect(page).toHaveURL(/.*dashboard/, { timeout: 10000 });

// Error output:
// Error: Timed out 10000ms waiting for expect(page).toHaveURL()
// Expected pattern: /.*dashboard/
// Received string:  "https://dialer-app.example.com/login"
Enter fullscreen mode Exit fullscreen mode

I added a screenshot capture to understand what the user was actually seeing:

// Added to the test for debugging
await page.screenshot({ path: `screenshots/login-fail-${ua.name}.png`, fullPage: true });
const bodyText = await page.locator('body').innerText();
console.log(`[${ua.name}] Page body text:`, bodyText.substring(0, 300));
Enter fullscreen mode Exit fullscreen mode

The screenshots confirmed it: the login page was re-rendering, credentials cleared, no feedback given to the user. A real user in those environments would simply think the app was broken — or worse, assume their credentials were wrong and get locked out.


Digging Deeper: Why Were These UAs Blocked?

I added network request logging to trace what was happening at the API level:

page.on('response', response => {
  if (response.url().includes('/api/auth')) {
    console.log(`[${ua.name}] Auth API → Status: ${response.status()}`);
  }
});
Enter fullscreen mode Exit fullscreen mode

Output for the failing cases:

[Legacy Edge (Old)] Auth API → Status: 403
[Headless Chrome (Bot-like)] Auth API → Status: 403
Enter fullscreen mode Exit fullscreen mode

There it was. The backend was returning HTTP 403 Forbidden for both — but the frontend was swallowing that response and silently redirecting back to login instead of displaying an error.

Two bugs in one:

  1. Bug #1 (Backend): The server-side logic was blocking login requests based on user agent string pattern matching — likely an anti-bot or browser compatibility check that was too aggressive.

  2. Bug #2 (Frontend): The application wasn't handling 403 responses from the auth API correctly. It should have shown a meaningful error message, but it was silently failing.


How I Documented and Reported the Bug

I raised two separate tickets with the dev team — one for backend, one for frontend:

Bug Report #1 — Backend

Title: Login API returns 403 for Legacy Edge and Headless Chrome user agents

Severity: High

Steps to Reproduce:

  1. Send POST to /api/auth/login with valid credentials
  2. Set User-Agent header to: Mozilla/5.0 (Windows NT 10.0...) Edge/18.17763
  3. Observe 403 response

Expected: 200 with auth token

Actual: 403 Forbidden — no descriptive response body

Impact: Any agent or supervisor using Legacy Edge cannot log in at all. Automated integration tools and certain CI pipelines using headless Chrome may also be blocked.

Bug Report #2 — Frontend

Title: Login form silently reloads on 403 — no error shown to user

Severity: Medium

Steps to Reproduce:

  1. Trigger a 403 from the auth API (see Bug #1)
  2. Observe frontend behavior

Expected: Display message: "Login failed. Please check your credentials or contact support."

Actual: Page refreshes silently. No error, no toast, no redirect explanation.

Impact: Users experience a confusing dead end. No guidance to resolve the issue.


Why This Matters for Predictive Dialer Platforms Specifically

This wasn't just a generic web app login bug. The context here matters.

Predictive dialer platforms are used in high-pressure, real-time environments. A contact center agent starts their shift, opens the dialer, and needs to be connected and ready within minutes. They're not developers. They don't check browser consoles.

If login silently fails:

  • Calls don't get made. The dialer can't pace outbound calls without agents marked as available.
  • SLAs are missed. Outbound campaigns have timing windows — miss them and you lose the opportunity.
  • Supervisors can't monitor. Real-time dashboards depend on agents being logged into the system.
  • The AI logic breaks. Modern dialers like the ones described by ClearTouch learn from agent availability signals. If agents can't log in, the prediction engine is working with incomplete data.

What looks like a minor auth bug has cascading effects in a telephony platform.


The Future of QA in Predictive Dialer Testing

This experience got me thinking about where QA is heading for platforms like this.

1. User Agent Testing Isn't Optional Anymore

Enterprise tools get accessed from aging hardware. Legacy browsers exist in the real world — especially in BPO environments where desktops aren't frequently upgraded. Testing a matrix of user agents should be standard, not an afterthought.

2. Silent Failures Are the Worst Failures

A crash is obvious. A silent failure hides in production until a real user is hurt by it. Playwright is exceptional at catching these because it makes assertions about final state, not just the absence of errors.

3. AI Dialers Will Demand AI-Level QA

As predictive dialers become more AI-driven — scoring leads, adapting pacing, feeding pre-call context to agents — the QA surface explodes. You're no longer just testing a UI. You're testing:

  • Model output consistency
  • Real-time API decision latency
  • CRM integration data accuracy
  • Compliance rule enforcement before calls are placed
  • Voice detection accuracy (human vs voicemail)

Playwright alone won't cut it for all of this. The future is AI-assisted QA — using ML models to generate test cases, detect anomalies in response patterns, and flag regressions in model behavior.

4. Observability Is a QA Concern

The frontend silently swallowing a 403 was partly a monitoring failure. Future QA pipelines for dialer platforms should include:

  • Structured logging of all auth events
  • Alerting on unexpected 4xx rates at the API layer
  • Real user monitoring (RUM) to catch frontend error handling gaps

5. Shift-Left on Browser Compatibility

The user agent bug should have been caught in development, not in QA. The lesson: browser/UA compatibility checks belong in PR review pipelines, not just in manual or exploratory testing.


Final Thoughts

I started this test run expecting to validate a login flow. I ended up discovering two bugs — one backend, one frontend — that would have silently blocked real users in production.

Playwright gave me the visibility to find what a human tester easily would have missed: a page that looked like it was doing something, but was actually failing quietly.

If you're working on a predictive dialer platform — or any enterprise telephony product — don't underestimate the value of testing across user agents. The platform's intelligence means nothing if the agent can't get through the front door.


Are you also doing QA on contact center or telephony platforms? I'd love to hear about the edge cases you've found. Drop them in the comments below.


Tags: #qa #playwright #testing #javascript #webdev


References:

Top comments (1)

Collapse
 
msalaz80 profile image
Melvin Salazar

Informative article. Thanks!