The inputs that break validation, storage, search and display, grouped by what they test. Each one shows its length four different ways, because the disagreement between those numbers is exactly where field limits fail.
Runs entirely in your browser. Nothing you enter is sent to a server.
95 strings in 9 groups. Invisible and control characters are shown as labelled markers, and the copy button copies the real characters.
String length and byte counter
Paste any string to see its length four ways, and any invisible characters it contains.
–visible10code points13UTF-16 units24UTF-8 bytes
Café·👨⟨U+200D⟩👩⟨U+200D⟩👧
Custom length generator
Exactly the number of visible characters you need, in a character set that stresses how each layer counts them.
The values date handling gets wrong, usually only in production.
Leap day
2024-02-29
–visible10code points10UTF-16 units10UTF-8 bytes
Valid. Test age calculations and anniversaries in non-leap years.
Invalid leap day
2023-02-29
–visible10code points10UTF-16 units10UTF-8 bytes
Invalid. Some parsers roll it over to 1 March silently.
Unix epoch
1970-01-01T00:00:00Z
–visible20code points20UTF-16 units20UTF-8 bytes
Zero. Often a sign of a null date that was converted.
2038 overflow
2038-01-19T03:14:08Z
–visible20code points20UTF-16 units20UTF-8 bytes
One second past the limit of a signed 32-bit timestamp.
Far future
9999-12-31
–visible10code points10UTF-16 units10UTF-8 bytes
A common "no expiry" sentinel. Check it is displayed sensibly.
Zero date
0000-00-00
–visible10code points10UTF-16 units10UTF-8 bytes
Accepted by some databases, invalid everywhere else.
Ambiguous order
03/04/2025
–visible10code points10UTF-16 units10UTF-8 bytes
3 April or 4 March depending on locale.
Daylight saving gap
2025-03-30T02:30:00
–visible19code points19UTF-16 units19UTF-8 bytes
Does not exist in most of Europe: clocks skip from 02:00 to 03:00.
Timezone offset
2025-06-01T23:30:00+05:30
–visible25code points25UTF-16 units25UTF-8 bytes
Already 2 June in UTC. Tests date boundaries across zones.
How to use
How to use the Edge case string generator
1To measure a string you already have, paste it into the measure box. It shows the visible characters, code points, UTF-16 units and UTF-8 bytes.
2Pick a group, or leave every group showing.
3Copy a string with its button. The exact characters are copied, including the invisible ones you cannot see on screen.
4Paste it into the field under test and submit. Then check the value everywhere it travels: the API response, the database row, the screen that displays it, and any export.
5For length limits, use the custom length generator to produce exactly the number of characters you need, in a character set that stresses how your storage counts them.
Guide
What testers should know
Length is four different numbers
A single family emoji is one character to the person typing it, seven Unicode code points, eleven UTF-16 code units and twenty-five bytes in UTF-8. Every layer of a typical stack counts with a different one of those, which is why a field can accept a value in the browser and reject it at the database.
HTML maxlength counts UTF-16 code units, as does String.length in JavaScript and Java. MySQL with utf8mb4 and PostgreSQL both count characters in a VARCHAR(n), meaning code points. SQL Server NVARCHAR(n) counts UTF-16 code units. Oracle VARCHAR2 counts bytes unless the column was declared with character semantics. A 255-character limit therefore means four different things depending on which layer enforces it, and the bug is always in the gap between two of them.
Test every limit at the boundary, one under and one over, and then repeat the boundary test with multi-byte characters. A limit that holds for 255 ASCII letters frequently fails for 255 accented letters or 128 emoji.
Invisible characters survive the obvious defences
Trimming is not a cleaning step people can rely on. In JavaScript, trim() removes the non-breaking space and the byte order mark but not the zero-width space. Java String.trim() removes only characters at or below U+0020, so it leaves the non-breaking space in place. Python strip() removes the non-breaking space and leaves the zero-width space. The zero-width space survives all three.
The practical consequence is that two values which look identical on screen compare unequal, so a user cannot log in with a username they can see is correct, or a search finds nothing for a term that is plainly in the record. Paste the whitespace group into any field that is later compared or searched, and check that the comparison still holds.
Normalisation decides whether two names match
The letter é can be stored as one precomposed code point or as an e followed by a combining accent. Both render identically. Unless the application normalises to one form, usually NFC, before storing and comparing, the same name entered on two different devices produces two different records.
Decomposed text arrives from more places than people expect: older macOS file systems, text copied from some PDFs and certain input methods. The precomposed and decomposed pair in the Unicode group are there to test exactly this: both should find the same record.
Escaping probes are a test of encoding, not an attack
The escaping group contains the standard defensive probes: a script tag, an attribute break-out, a SQL tautology, a template expression. They are deliberately benign. They exist to confirm that the application treats input as text, and a pass looks the same for every one of them: the value is stored exactly as typed and displayed back literally, never interpreted.
If a template expression comes back as 49, or a script tag disappears from the rendered page instead of showing as text, input is reaching an interpreter. Use these only on systems you are authorised to test, and treat any of them behaving differently from plain text as a finding to report.
Follow the value all the way round
Most of these strings pass the form and fail later. The full round trip is the test: submit the value, read it back through the API, check the database row, view it on every screen that displays it, export it to CSV and open the file, and search for it. A trailing space trimmed on save but not on comparison, or an emoji stored correctly and truncated in an export, only appears when the value is followed the whole way.
QAble tests input handling the way it fails in production: the full round trip from form to database to export, in every character set your users actually type.
An input chosen because it sits at a boundary or exercises an unusual path: an empty value, a value exactly at a length limit, characters outside the basic Latin set, invisible characters, or text that some layer of the stack treats as code. They find the defects that ordinary test data, which tends to be short ASCII names, never reaches.
Why does one emoji count as two characters in JavaScript?
JavaScript strings are sequences of UTF-16 code units, and characters outside the Basic Multilingual Plane, which includes most emoji, need two code units each. String.length reports code units, not visible characters, so a single emoji has a length of two and a family emoji has a length of eleven.
What is the difference between trimming and normalising?
Trimming removes whitespace from the ends of a string. Normalising converts equivalent Unicode sequences into one canonical form, such as turning an e plus a combining accent into a single é. They solve different problems, and an application usually needs both before it stores or compares user input.
Are the escaping strings safe to use?
Yes. They are the standard benign probes used to check output encoding, and none of them does harm if it executes: the script calls alert(1) and the template expression is arithmetic. Use them only on applications you are authorised to test.
How should I test a field with a 255-character limit?
Test 254, 255 and 256 characters of plain ASCII, then 255 characters of accented letters and enough emoji to exceed the limit in UTF-16 units while staying under it in visible characters. If the limit is enforced in more than one place, those are the cases where the layers disagree.
How do I copy a zero-width space?
Use the copy button next to Zero-width space on its own, in the whitespace group. It copies the single character U+200B, which is almost impossible to select by hand because it has no width on screen.
How do I count the bytes in a string?
Paste it into the measure box at the top of the tool. It shows the length four ways: visible characters, Unicode code points, UTF-16 code units and UTF-8 bytes. Those are the four numbers different layers of a stack mean when they say length.
Is anything I copy sent to QAble?
No. The strings are built into the page and every count is calculated in your browser. Nothing is sent to a server.
Need the edge cases found for you?
QAble testers work through the inputs, payment paths and data that break products in production, before your users find them.