Sparround

Regex basics for testers

A regular expression (regex) is a text pattern. JavaScript has two forms: the literal /pattern/flags, or new RegExp('pattern', 'flags') when the pattern is built dynamically.

The essentials:

  • \d a digit, \w a letter/digit/underscore, \s whitespace; the uppercase variants (\D, \W, \S) mean the opposite
  • + one or more, * zero or more, ? zero or one
  • {3} exactly three, {2,4} two to four
  • ^ start of string, $ end — the main tool for tightening a check
  • [a-z] a character set, [^abc] an exclusion
  • ( ) a capture group, (?<name>...) a named group, | alternation

Flags: i — case-insensitive, g — all matches, m — multiline mode.

PatternWhat it matchesUse in tests
/^\d+$/a whole string of digits onlyvalidating an ID or count field
/\d+/the first digit group INSIDE the textpulling a number out of 'Order #1042'
/^[^\s@]+@[^\s@]+\.[a-z]{2,}$/ia simple email shapethe format of a generated email
/^[0-9a-f]{8}-[0-9a-f]{4}/ithe beginning of a UUIDthe shape of an id returned by the API
/\s+/gruns of whitespace and line breaksnormalising UI text (with replace)
/(?<id>\d+)/a named capture groupreadable extraction via match().groups.id

`test()` or `match()`?

  • regex.test(text)true/false. Pick this when you only need the "does it match?" answer.
  • text.match(regex) → an array on a match, `null` otherwise. Without the g flag: [0] is the whole match, [1], [2] are the capture groups, .groups holds the named ones. With g: just the list of whole matches, no groups.
  • text.matchAll(regex) (with g) → an iterator giving each match together with its groups.

Because match() can return null, reading [1] without checking is the classic Cannot read properties of null error. The safe form: text.match(re)?.[1] ?? null.

Playwright accepts regexes directly, and that is the cleanest way to deal with variable text: await expect(page).toHaveURL(/\/dashboard/), await expect(badge).toHaveText(/^\d+ items?$/), page.getByRole('button', { name: /sign in/i }).

When is regex overkill? When the value is fixed (toHaveURL('https://stage.example.com/dashboard')), when a simple includes/startsWith would do, or when the pattern grows so complex that it needs its own explanatory comment. The principle: use regex when it improves readability, not to show off — because when it fails, a teammate has to read it.

📚 Sources and documentation