Strings
should().string(x) verifies a string. Two families of checks live here: content checks and occurrence counting with the Times helpers.
Content and case
should().string('Any content').equals('Any content'); // ok — case-sensitive
should().string('Any content').equalsIgnoreCase('any content'); // ok
should().string('Any content').hasLength(11); // ok
should().string('').empty(); // ok — same as hasLength(0)
should().string(' ').whitespace(); // ok — spaces only (or empty)
should().string('ANY').upperCased(); // ok
should().string('any').lowerCased(); // ok
whitespace() accepts an empty string and strings consisting solely of space characters — tabs and other whitespace characters are not included (see Caveats).
Prefix and suffix
should().string('#header').startsWith('#'); // ok — case-sensitive
should().string('report.pdf').endsWith('.pdf'); // ok
should().string('header').startsWith('Header'); // throws "'header' doesn't start with 'Header'."
should().string('report.pdf').not.endsWith('.pdf'); // ok
Both checks are case-sensitive and run the definedness guard: a null/undefined entry throws The entry is not defined. regardless of not. When the substring may sit anywhere in the string, use contains with the Times helpers instead.
Occurrence counting with Times
contains accepts an optional counter — a predicate over the number of occurrences. The Times helper covers the common shapes:
should().string('any any content').contains('any'); // at least once
should().string('any any content').contains('any', Times.once()); // throws — found twice
should().string('any any content').contains('any', Times.twice()); // ok
should().string('any any content').contains('any', Times.exactly(2)); // ok
should().string('any any content').contains('any', Times.moreThan(2)); // throws
should().string('any any content').contains('any', Times.lessThan(3)); // ok
A custom predicate works too — any (count: number) => boolean:
should().string('a b a b a').contains('a', (count) => count % 2 === 1); // ok — found 3 times
Case-insensitive and any-of variants follow the same shape:
should().string('Any content').containsIgnoreCase('any'); // ok
should().string('Any content').containsAny('nope', 'any'); // ok — at least one matches
should().string('Any content').containsAnyIgnoreCase('any'); // ok
Regular expressions
should().string('order-42').match(/order-\d+/); // ok
should().string('order-42').match(/^order-\d+$/); // ok
should().string('order-42').match(/invoice-/); // throws "'order-42' does not match /invoice-/."
match delegates to JavaScript's String.match — it is a partial match. Anchor the expression (^…$) when the whole string must match.
Negation
should().string('Any content').not.contains('nope'); // ok
should().string('ANY').not.lowerCased(); // ok
The null/undefined rules from Concepts apply to every check.
16 September 2026