Skip to main content

BorderlineData

Currency Input Field Validation

BLOG

Currency Input Field Validation with Playwright and TypeScript

Automating currency input field validation is an essential process for engineering teams building secure, production-ready fintech applications. Without robust automated checks, dynamic financial fields remain highly susceptible to formatting injection, floating-point rounding errors, and cross-border locale validation failures. To catch these discrepancies early in your continuous integration pipelines, software testers and developers must look beyond basic end-to-end user journeys and implement explicit boundary validation scripts.

 

Leveraging Playwright with TypeScript provides a highly reliable framework for targeting these critical financial edge cases directly within simulated browser contexts. By configuring programmatic network interception alongside localized browser instances, automation engineers can cleanly isolate how frontend inputs respond to multi-currency symbols, decimal masks, and extreme numeric limits. This technical guide walks through practical automation patterns to verify that your UI components sanitize user text safely before passing calculations downstream to your backend APIs.

Setting Up the Test Strategy

To properly automate currency field validations, your framework needs to handle three distinct states:

  1. The Native Formatting Layer: How the input captures text under different browser locales (e.g., US . vs. German ,).
  2. The Sanitisation Layer: Ensuring invalid characters (letters, symbols, multiple decimals) are dropped instantly.
  3. The Backend Payload: Confirming that the parsed string converts perfectly into a safe data format (like an integer representing minor units/cents) before submission.
Advertisement

Emulating Regional Locales in Playwright

If your frontend changes its validation rules or masks based on user location, you shouldn’t rely on whatever locale happens to be running on your CI/CD server. Playwright lets you hardcode the locale inside test.use().

 

Here is how you isolate a test suite to validate a European comma-decimal mask versus a US dot-decimal mask:

TypeScript




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




// Test Suite configured specifically for German locale format (1.234,56 €)

test.describe('Currency Input - German Locale Context', () => {

  test.use({

    locale: 'de-DE',

    geolocation: { longitude: 13.404954, latitude: 52.520008 },

    permissions: ['geolocation']

  });




  test('should accept comma as a decimal separator', async ({ page }) => {

    await page.goto('/checkout');

    const input = page.locator('#amount-input');




    // Type using the regional format

    await input.fill('1234,56');

   

    // If your app applies a visual mask on blur, trigger it

    await input.blur();




    // Verify the UI mask formatted it correctly for Germany

    await expect(input).hasValue('1.234,56');

  });

});




// Test Suite configured for US locale format ($1,234.56)

test.describe('Currency Input - US Locale Context', () => {

  test.use({ locale: 'en-US' });




  test('should accept dot as a decimal separator', async ({ page }) => {

    await page.goto('/checkout');

    const input = page.locator('#amount-input');




    await input.fill('1234.56');

    await input.blur();




    await expect(input).hasValue('1,234.56');

  });

});

 

Data-Driven Boundary Testing

Instead of writing individual tests for every single financial edge case, clean up your test suite using a data-driven array matrix. This ensures your coverage mirrors robust boundary conditions effortlessly.

TypeScript




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




const currencyEdgeCases = [

  { input: '-100.00', expected: '0.00', description: 'Should reject negative values' },

  { input: '0.00', expected: '0.00', description: 'Should accept absolute zero boundary' },

  { input: '10.005', expected: '10.01', description: 'Should round fractional cents half-up' },

  { input: 'abc12.50xyz', expected: '12.50', description: 'Should strip non-numeric characters' },

  { input: '999999.99', expected: '999,999.99', description: 'Should format upper boundary clusters safely' },

];




test.describe('Currency Input Boundary Tests (en-US)', () => {

  test.use({ locale: 'en-US' });




  for (const edgeCase of currencyEdgeCases) {

    test(`Edge Case: ${edgeCase.description}`, async ({ page }) => {

      await page.goto('/checkout');

      const input = page.locator('#amount-input');




      // Clear any default value and fill the test payload

      await input.clear();

      await input.fill(edgeCase.input);

      await input.blur();




      // Assert the frontend handles or corrects the data cleanly

      await expect(input).hasValue(edgeCase.expected);

    });

  }

});

 

Validating the API Interception Payload

A green light on the frontend input box is only half the battle. The ultimate validation test is ensuring that the frontend sanitises the text value into an un-corrupted numeric payload before hitting your backend API.

 

If your backend expects an integer in cents (1250 for $12.50) to avoid floating-point errors, use Playwright’s network interception to intercept and inspect the actual JSON request.

TypeScript




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




test('should sanitise string input to integer cents in API payload', async ({ page }) => {

  await page.goto('/checkout');

  const input = page.locator('#amount-input');

  const submitButton = page.locator('#submit-payment');




  // Fill input with currency symbols and messy spacing

  await input.fill(' $ 1,234.56 ');




  // Set up an API waiter to intercept the outgoing POST request

  const apiRequestPromise = page.waitForRequest(request =>

    request.url().includes('/api/pay') && request.method() === 'POST'

  );




  await submitButton.click();




  // Resolve the intercepted request object

  const request = await apiRequestPromise;

  const jsonPayload = request.postDataJSON();




  // Assert that the string "$ 1,234.56" was safely transformed

  // into an integer unit count ($1234.56 * 100 = 123456)

  expect(jsonPayload.amountInCents).toBe(123456);

});

Automation Best Practices for Financial Fields

  • Avoid .type() for baseline inputs: Use locator.fill() to clear and replace whole values rapidly. Only use locator.pressSequentially() if you are explicitly testing custom frontend keypress interception scripts, as legacy .type() methods are deprecated in modern Playwright standards.

 

  • Don’t forget the clipboard: Test copy-paste events. You can evaluate a script execution using page.evaluate() to trigger a mock paste event containing malicious strings or invalid currency symbols directly into the input container.

 

  • Decouple Currency from Locales if needed: Remember that a user in Germany (de-DE) might choose to execute a checkout transaction completely in US Dollars (USD). Ensure your formatting tests switch the underlying currency schema independently from the browser’s regional formatting rules.

Summary

Automating your financial validation scripts guarantees that subtle backend calculation bugs or localized parsing errors never compromise your software’s integrity. By shifting away from happy-path manual workflows and embracing structured, context-driven testing scripts in Playwright, you protect your fintech software from regressions at scale.

To scale up your boundary testing coverage without spending hours writing manual payload permutations, explore how to pair your automation architecture with specialized testing frameworks. You can read a complete architectural deep-dive on How to Automate Boundary Value Testing with Selenium WebDriver and Python to compare cross-browser automation strategies. For a closer look at implementing mathematical guards directly at the interface level, review the technical breakdown on How to Test Numeric Boundaries to ensure your systems remain entirely bulletproof under every localized runtime parameter.