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:
\da digit,\wa letter/digit/underscore,\swhitespace; 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.
| Pattern | What it matches | Use in tests |
|---|---|---|
| /^\d+$/ | a whole string of digits only | validating an ID or count field |
| /\d+/ | the first digit group INSIDE the text | pulling a number out of 'Order #1042' |
| /^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i | a simple email shape | the format of a generated email |
| /^[0-9a-f]{8}-[0-9a-f]{4}/i | the beginning of a UUID | the shape of an id returned by the API |
| /\s+/g | runs of whitespace and line breaks | normalising UI text (with replace) |
| /(?<id>\d+)/ | a named capture group | readable 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 thegflag:[0]is the whole match,[1],[2]are the capture groups,.groupsholds the named ones. Withg: just the list of whole matches, no groups.text.matchAll(regex)(withg) → 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
- Regular expressionsofficialdeveloper.mozilla.org