TypeScript Operators β€” Complete Guide with Playwright Examples

Operators are the building blocks of every TypeScript program. Whether you’re writing Playwright test automation or building applications, understanding operators is essential. This guide covers every operator type in TypeScript with practical examples you can use in your Playwright projects.

πŸ“– What You’ll Learn: Arithmetic, Comparison, Logical, Assignment, Ternary, Nullish Coalescing, and Type operators β€” all with real Playwright examples.


βž• Arithmetic Operators

Arithmetic operators perform mathematical calculations on numbers.

let a: number = 10;
let b: number = 3;

console.log(a + b);   // 13  β€” Addition
console.log(a - b);   // 7   β€” Subtraction
console.log(a * b);   // 30  β€” Multiplication
console.log(a / b);   // 3.33 β€” Division
console.log(a % b);   // 1   β€” Modulus (remainder)
console.log(a ** b);  // 1000 β€” Exponentiation

// Increment and Decrement
let count: number = 5;
count++;   // 6 (post-increment)
count--;   // 5 (post-decrement)
++count;   // 6 (pre-increment)

βš–οΈ Comparison Operators

Comparison operators compare two values and return a boolean (true or false). These are essential in Playwright assertions.

let x: number = 5;
let y: string = "5";

// Loose equality (compares value only, allows type coercion)
console.log(x == y);    // true β€” NOT recommended in TypeScript

// Strict equality (compares value AND type)
console.log(x === 5);   // true β€” ALWAYS use this
console.log(x === y);   // Error! TypeScript catches this at compile time

// Not equal
console.log(x != y);    // false (loose)
console.log(x !== 10);  // true (strict)

// Greater / Less than
console.log(x > 3);     // true
console.log(x >= 5);    // true
console.log(x < 10);    // true
console.log(x <= 4);    // false

⚠️ Golden Rule: Always use === (strict equality) and !== in TypeScript. The loose operators == and != can cause subtle bugs that are hard to debug in test automation.


🧠 Logical Operators

Logical operators combine multiple conditions. You'll use these constantly in test automation for complex validations.

let isLoggedIn: boolean = true;
let isAdmin: boolean = false;
let hasPermission: boolean = true;

// AND (&&) β€” ALL conditions must be true
console.log(isLoggedIn && isAdmin);         // false
console.log(isLoggedIn && hasPermission);    // true

// OR (||) β€” at least ONE must be true
console.log(isAdmin || hasPermission);       // true

// NOT (!) β€” reverses the boolean
console.log(!isLoggedIn);                    // false
console.log(!isAdmin);                       // true

// Combining multiple operators
if (isLoggedIn && (isAdmin || hasPermission)) {
  console.log("Access granted");  // This runs
}

πŸ“ Assignment Operators

let num: number = 10;

num += 5;   // num = num + 5  β†’ 15
num -= 3;   // num = num - 3  β†’ 12
num *= 2;   // num = num * 2  β†’ 24
num /= 4;   // num = num / 4  β†’ 6
num %= 4;   // num = num % 4  β†’ 2
num **= 3;  // num = num ** 3 β†’ 8

❓ Ternary & Nullish Coalescing Operators

These are shorthand operators that make your code cleaner and more readable.

// Ternary Operator: condition ? valueIfTrue : valueIfFalse
let age: number = 20;
let status: string = age >= 18 ? "Adult" : "Minor";
console.log(status);  // "Adult"

// Nullish Coalescing (??) β€” returns right side if left is null/undefined
let username: string | null = null;
let displayName = username ?? "Guest";
console.log(displayName);  // "Guest"

// Optional Chaining (?.) β€” safely access nested properties
interface User {
  name: string;
  address?: { city?: string };
}
let user: User = { name: "Deepesh" };
console.log(user.address?.city);  // undefined (no error!)

πŸ” Type Operators (TypeScript-Specific)

// typeof β€” check runtime type
let value: unknown = "hello";
if (typeof value === "string") {
  console.log(value.toUpperCase());  // "HELLO"
}

// instanceof β€” check if object is an instance of a class
class Animal { name: string = "dog"; }
class Dog extends Animal { breed: string = "lab"; }

let pet = new Dog();
console.log(pet instanceof Dog);     // true
console.log(pet instanceof Animal);  // true

// keyof β€” get union of object keys (compile-time only)
interface Config {
  baseURL: string;
  timeout: number;
}
type ConfigKey = keyof Config;  // "baseURL" | "timeout"

// as β€” type assertion
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;

🎭 Operators in Playwright β€” Real Examples

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

test('using operators in Playwright tests', async ({ page }) => {
  await page.goto('https://sqatools.in');
  
  // Comparison: check element count
  const links = await page.locator('a').count();
  expect(links > 0).toBeTruthy();
  
  // Logical: multiple conditions
  const title = await page.title();
  const isCorrectPage = title.includes('SQA') && links > 10;
  expect(isCorrectPage).toBe(true);
  
  // Nullish coalescing: safe text extraction
  const headerText = await page.locator('h1').first().textContent() ?? '';
  expect(headerText.length > 0).toBeTruthy();
  
  // Ternary: conditional actions
  const env = process.env.ENV ?? 'staging';
  const timeout = env === 'production' ? 30000 : 10000;
  
  // typeof: type guards for safe handling
  const attribute = await page.locator('body').getAttribute('class');
  if (typeof attribute === 'string') {
    console.log('Body classes:', attribute);
  }
});

❓ FAQ

πŸ€” What is the difference between == and === in TypeScript?

== compares values with type coercion (loose equality), while === compares both value and type (strict equality). Always use === in TypeScript.


πŸ€” What is the nullish coalescing operator (??) in TypeScript?

The ?? operator returns the right-hand value when the left-hand value is null or undefined. Unlike ||, it doesn't treat 0, "", or false as "empty".


πŸ€” How do I use typeof in Playwright tests?

Use typeof to check the runtime type of values returned from page methods. For example, typeof (await page.title()) === 'string' ensures you're working with a string before calling string methods.

🎯 Next Steps

Now that you understand TypeScript operators, continue your learning journey:

🎬 Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

✎ Practise what you learned: 30 TypeScript operators programs with solutions →

How to Test Passkey Login with Playwright β€” WebAuthn Automation Guide

Passkeys are replacing passwords across the web, and if your test automation framework can’t handle WebAuthn flows, you’re already falling behind. Playwright 1.61 introduced browserContext.credentials β€” a virtual authenticator that lets you register, store, and use passkeys entirely in code. This guide walks you through everything you need to automate passkey login testing, with ready-to-use TypeScript examples.


πŸ” What Is WebAuthn and Why Should QA Engineers Care?

WebAuthn (Web Authentication) is the W3C standard behind passkeys. Instead of passwords, users authenticate with biometrics (fingerprint, face recognition) or hardware security keys.

Major platforms β€” Google, Apple, Microsoft, and most modern SaaS products β€” now support passkey login. As a QA engineer or SDET, you’ll increasingly encounter apps that use WebAuthn, and your automation framework needs to test these flows reliably.

⚠️ The Problem: Traditional test tools couldn’t interact with hardware authenticators. You’d have to skip those tests or test them manually. Playwright 1.61 solves this completely with a built-in virtual authenticator!


πŸ“‹ Prerequisites

Before we start, make sure you have:

  • βœ… Node.js 18 or later
  • βœ… Playwright 1.61+ installed
  • βœ… Basic knowledge of TypeScript and Playwright
# Install or upgrade Playwright
npm install @playwright/test@latest
npx playwright install

# Verify version
npx playwright --version

βš™οΈ Setting Up the Virtual Authenticator

Playwright’s virtual authenticator is available through browserContext.credentials. No additional setup is required β€” it’s built into the browser context.

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

test('virtual authenticator is available', async ({ context }) => {
  // The credentials API is ready to use immediately
  const credentials = await context.credentials.list();
  expect(credentials).toEqual([]);
  console.log('Virtual authenticator is active!');
});

πŸ’‘ Key Insight: The virtual authenticator behaves like a FIDO2-compliant security key. When a website triggers a WebAuthn ceremony (registration or login), Playwright’s authenticator responds automatically β€” no user interaction needed!


πŸ”‘ Registering a Passkey in Your Tests

Here’s how to automate passkey registration:

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

test('register a new passkey', async ({ context, page }) => {
  // Navigate to your app's registration page
  await page.goto('https://your-app.com/settings/security');

  // Click the "Add Passkey" button
  await page.getByRole('button', { name: 'Add Passkey' }).click();

  // Playwright's virtual authenticator handles the WebAuthn ceremony
  // Wait for confirmation
  await expect(page.getByText('Passkey added successfully')).toBeVisible();

  // Verify the credential was stored
  const credentials = await context.credentials.list();
  expect(credentials.length).toBe(1);
  console.log('Credential ID:', credentials[0].id);
});

When the browser triggers navigator.credentials.create(), the virtual authenticator generates a key pair and responds with the public key credential β€” exactly as a real hardware key would.


πŸš€ Automating Passkey Login

Once a passkey is registered, testing the login flow is straightforward:

test('login with passkey', async ({ context, page }) => {
  // Step 1: Register a passkey
  await page.goto('https://your-app.com/register');
  await page.getByRole('button', { name: 'Register with Passkey' }).click();
  await expect(page.getByText('Passkey registered')).toBeVisible();

  // Step 2: Navigate to login
  await page.goto('https://your-app.com/login');

  // Step 3: Sign in with passkey
  await page.getByRole('button', { name: 'Sign in with Passkey' }).click();

  // The virtual authenticator uses the stored credential
  await expect(page.getByText('Welcome back')).toBeVisible();
  await expect(page).toHaveURL(/dashboard/);
});

βœ… No mocking, no bypassing β€” you’re testing the REAL WebAuthn implementation end to end. This is the biggest advantage over traditional approaches!


♻️ Reusing Credentials Across Tests with Storage State

Registering a passkey in every test is wasteful. Use Playwright’s storage state to authenticate once and reuse:

// auth.setup.ts
import { test as setup } from '@playwright/test';

setup('register and authenticate with passkey', async ({ context, page }) => {
  await page.goto('https://your-app.com/register');
  await page.getByRole('button', { name: 'Register with Passkey' }).click();
  await expect(page.getByText('Passkey registered')).toBeVisible();

  // Save authenticated state
  await context.storageState({ path: '.auth/passkey-user.json' });
});
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  projects: [
    { name: 'setup', testMatch: /.*\.setup\.ts/ },
    {
      name: 'tests',
      dependencies: ['setup'],
      use: { storageState: '.auth/passkey-user.json' },
    },
  ],
});

🚨 Common Mistakes and How to Avoid Them

❌ Mistake 1: Credentials don’t persist across browser contexts.

Each browserContext has its own virtual authenticator. If your test creates a new context, previously registered passkeys won’t be available. Solution: register and login within the same context, or use storage state.

❌ Mistake 2: Not waiting for the WebAuthn ceremony to complete.

The registration and authentication ceremonies are asynchronous. Clicking the next button before the ceremony finishes causes flaky tests. Always wait for a visible confirmation element.

❌ Mistake 3: Forgetting to await credentials API calls.

context.credentials.list() returns a Promise. Missing await leads to empty results and confusing test failures.


❓ FAQ

πŸ€” Can I test passkeys without a real WebAuthn-enabled app?

Yes! You can use demo sites like webauthn.io to practice. For other Playwright interactions, practise on our automation practice pages.


πŸ€” Does Playwright’s virtual authenticator work with all browsers?

The virtual authenticator works with Chromium-based browsers. Firefox and WebKit support may vary β€” check the Playwright 1.61 release notes for the latest compatibility.


πŸ€” Can I export and import passkey credentials between test runs?

Yes, context.credentials.list() returns credential objects that can be serialized. However, using storage state (shown above) is the recommended approach for persisting authenticated sessions.


πŸ€” What’s the difference between passkeys and FIDO2 security keys?

Passkeys are discoverable FIDO2 credentials synced across devices (through iCloud Keychain, Google Password Manager, etc.). Hardware security keys are physical devices. Playwright’s virtual authenticator simulates both.


πŸ€” Do I need to modify my app’s code to test with the virtual authenticator?

No. The virtual authenticator intercepts standard WebAuthn API calls at the browser level. Your app’s code doesn’t need any changes.


🎯 Next Steps

Now that you can automate passkey testing, try these:

  • πŸ”§ Add passkey tests to your CI/CD pipeline
  • πŸ§ͺ Test error scenarios (expired credentials, wrong authenticator)
  • πŸ“ Combine passkey auth with your existing Page Object Model β€” see our Playwright POM tutorial
  • πŸ’Ύ Explore the new page.localStorage and page.sessionStorage APIs in Playwright 1.61

🎬 Want to see this in action? Watch the full video tutorial!

Subscribe to SqaToolsByDY on YouTube for weekly QA automation tutorials

🌐 Practice on sqatools.in β€” free automation practice pages!