Why do test names matter so much?
The name is the first thing you read when a test fails, and often the only thing. Results shows test 2 with a red cross, and you have learned nothing until you open the file, find the test and work out what it was for. Results showing discount › gives 10% off orders over 30 tells you which promise broke before you read a single number.
Names also matter when nothing fails. A new person joining the Crumb and Crust site, or you in six months, can read the list of test names and learn the discount rules without reading the code. Good names turn the test file into a short, checked description of what the code does.
What makes a good test name?
A good name states a rule in plain words, with the condition and the outcome: gives 10% off orders over 30, refuses an order with no pickup day, takes 5 off three or more jobs. It names the situation, so you know the input, and the result, so you know what was expected. Numbers from the rule belong in the name when they are the point, such as 30 and 10%.
Leave out words that add nothing. should correctly calculate the discount is longer than test 1 and says almost as little: which discount, for which order? Avoid naming the code's internals, such as sets rate to 0.1, because the name should still be true if the code is rewritten in a different way.
- Say the condition: orders over 30, card holders, a full walk
- Say the outcome: gives 10% off, refuses the booking, throws
- Use the rule's own numbers when they matter
- Describe behaviour a customer would recognise, not variable names
How do describe and the test name read together?
Results joins the describe() name and the test name with an arrow, so the two should read as one phrase. discount › gives 10% off orders over 30 works because discount names the thing and the test name says what it does. Nesting another level gives a third part, such as quote › express › adds 10 to the total.
Many teams use it() in place of test() for this reason. The two are the same function in Vitest and Jest, and it reads naturally inside a describe: describe('canBook') with it('refuses a booking when every place is taken'). Pick one style per project and keep to it.
describe('discount', () => {
test('gives nothing off orders under 30', () => {
expect(discount(20)).toBe(0);
});
test('gives 10% off an order of exactly 30', () => {
expect(discount(30)).toBe(3);
});
});

How does writing the name help you find missing tests?
Once every test states a rule, gaps become visible. Read the names for discount() in the starting file, once renamed: under 30 gets nothing, over 30 gets 10%, card holders get 5%. Nobody has said what happens at exactly 30, or what a card holder spending 40 gets. The rule in the comment answers both, and each answer becomes a test with its own name.
Writing the name before the body is a useful habit for the same reason. If you cannot finish the sentence gives ... when ..., you are not yet sure what the code should do, and it is better to find that out before writing any assertion.
What is test.todo for?
test.todo('gives staff 20% off whatever they spend') records a test you plan to write, with a name and no body. Results lists it as a to-do, separate from passes and failures, and it never fails. It is a way to write down a rule the moment you hear about it, in the place where it will eventually be checked.
Use it when planning a feature: write a test.todo() for each rule, then turn them into real tests one by one. Do not leave to-dos lying around for months, because a long list of them stops meaning anything. The practice runner shows to-dos in Results the same way Vitest marks them in its report.
What happens when a name and its test disagree?
A name is a claim, and the body is the evidence. When they disagree, the name wins in the reader's head, which is dangerous. The Break It test is called refuses a booking when the walk is full, but its data has 13 people booked on a 12-place walk. Anyone reading Results believes full walks are covered. They are not: at exactly 12 of 12, canBook() still says yes, because it uses <=.
When you review tests, read each name, then check that the body really does what the name says, with data that matches the words. Full means booked equals places. Over 30 means a value above 30, and exactly 30 means 30. Mismatches like these are where untested cases hide behind tests that look complete.
Should names describe the code or the behaviour?
Describe the behaviour. returns false when booked <= places copies the code into the name, including any bug in it, and becomes wrong the moment the code is fixed. refuses a booking when every place is taken describes what a bird club member sees, and stays true however the check is written.
Behaviour names also survive refactoring. If someone rewrites canBook() to use placesLeft(walk) > 0, every behaviour name still applies, and the tests still prove the same promises. Names tied to implementation details would all need renaming, and renamed tests are easy to get subtly wrong.
What do AI tools get wrong with test names?
Generated test names tend to start with should and end vaguely: should work correctly, should handle edge cases, should return the right value. Those names fit any test, which means they explain none. Another common pattern is a name copied between tests with a number added, such as calculates discount 2.
Ask the tool for names that state the rule with its numbers, or rename them yourself as you review. While you do, check each body against its new name. Renaming is often when you notice that a test called handles empty input never passes an empty value at all.
Field notes
- A test name should state a condition and an outcome in plain words.
- The
describename and test name read together as one phrase in Results. - Clear names make gaps easy to see, such as an order of exactly 30.
test.todo()records a planned test with a name and no body.
Easy to get wrong
A numbered name tells you nothing when it fails. A name that states the rule tells you which promise broke before you open the file.
The name promised a full walk and the data showed an overbooked one. Make the data match the words, or the name hides an untested case.
Words like should and correctly fill space without saying what correct means. Name the condition and the result.
Questions people ask
Is it or test better?
They are the same function in Vitest and Jest. it reads well inside describe blocks as a sentence about the thing described. test reads well on its own. Choose one per project.
How long can a test name be?
As long as it needs to state the rule, usually five to twelve words. If it needs two clauses joined by and, the test is probably checking two things.
Does a test.todo count as passing?
No. It is reported as a to-do, neither passing nor failing. The suite can be fully green with to-dos listed, which is why they should not pile up.
Should test names start with should?
They can, but the word rarely adds meaning. gives 10% off orders over 30 is shorter and says the same as should give 10% off orders over 30. Whatever you choose, keep it consistent.