Good test names are documentation. Bad test names are noise.
These 10 rules will make your tests readable, debuggable, and maintainable.
Source: Frontend Testing Guide: 10 Essential Rules
Every test name should start with "should" followed by an action verb.
1// Bad2it("displays the error message", () => {});3it("modal visibility", () => {});4it("form validation working", () => {});5 6// Good7it("should display error message when validation fails", () => {});8it("should show modal when trigger button is clicked", () => {});9it("should validate form when user submits", () => {});
Pattern: should [verb] [expected outcome]
Specify what causes the behavior you're testing.
1// Bad2it("should update counter", () => {});3it("should validate email", () => {});4it("should show dropdown", () => {});5 6// Good7it("should increment counter when plus button is clicked", () => {});8it("should show error when email format is invalid", () => {});9it("should open dropdown when toggle is clicked", () => {});
Pattern: should [verb] [expected outcome] when [trigger event]
Use describe blocks to create clear test hierarchies.
1// Bad 2describe("AuthForm", () => { 3 it("should test empty state", () => {}); 4 it("should test invalid state", () => {}); 5 it("should test success state", () => {}); 6}); 7 8// Good 9describe("AuthForm", () => {10 describe("when form is empty", () => {11 it("should disable submit button", () => {});12 it("should not show any validation errors", () => {});13 });14 15 describe("when submitting invalid data", () => {16 it("should show validation errors", () => {});17 it("should keep submit button disabled", () => {});18 });19});
Pattern:
1describe("[Component/Feature]", () => {2 describe("when [specific condition]", () => {3 it("should [expected behavior]", () => {});4 });5});
Clearly describe the before and after states in your test names.
1// Bad2it("should change status", () => {});3it("should update todo", () => {});4it("should modify permissions", () => {});5 6// Good7it("should change status from pending to approved", () => {});8it("should mark todo as completed when checkbox clicked", () => {});9it("should upgrade user from basic to premium", () => {});
Pattern: should change [attribute] from [initial state] to [final state]
Include loading and result states for asynchronous operations.
1// Bad2it("should load data", () => {});3it("should handle API call", () => {});4it("should fetch user", () => {});5 6// Good7it("should show skeleton while loading data", () => {});8it("should display error message when API call fails", () => {});9it("should render profile after user data loads", () => {});
Pattern: should [verb] [expected outcome] [during/after] [async operation]
Be explicit about the type of error and what causes it.
1// Bad2it("should show error", () => {});3it("should handle invalid input", () => {});4it("should validate form", () => {});5 6// Good7it('should show "Invalid Card" when card number is wrong', () => {});8it('should display "Required" when password is empty', () => {});9it("should show network error when API is unreachable", () => {});
Pattern: should show [specific error message] when [error condition]
Write tests using domain language rather than implementation details.
1// Bad2it("should update state", () => {});3it("should dispatch action", () => {});4it("should modify DOM", () => {});5 6// Good7it("should save customer order", () => {});8it("should update cart total", () => {});9it("should mark order as delivered", () => {});
Pattern: should [business action] [business entity]
Specify conditions that affect the behavior being tested.
1// Bad2it("should enable button", () => {});3it("should show message", () => {});4it("should apply discount", () => {});5 6// Good7it("should enable checkout when cart has items", () => {});8it("should show free shipping when total exceeds $100", () => {});9it("should apply discount when user is premium member", () => {});
Pattern: should [expected behavior] when [precondition]
Describe visual changes as users would perceive them.
1// Bad2it("should set error class", () => {});3it("should toggle visibility", () => {});4it("should update styles", () => {});5 6// Good7it("should highlight search box in red when empty", () => {});8it("should show green checkmark when password is strong", () => {});9it("should disable submit button while processing", () => {});
Pattern: should [visual change] when [user action/condition]
Break down complex processes into clear steps.
1// Bad 2describe("Checkout", () => { 3 it("should process checkout", () => {}); 4 it("should handle shipping", () => {}); 5 it("should complete order", () => {}); 6}); 7 8// Good 9describe("Checkout Process", () => {10 it("should first validate items are in stock", () => {});11 it("should then collect shipping address", () => {});12 it("should finally process payment", () => {});13 14 describe("after successful payment", () => {15 it("should display order confirmation", () => {});16 it("should send confirmation email", () => {});17 });18});
Pattern:
1describe("[Complex Process]", () => {2 it("should first [initial step]", () => {});3 it("should then [next step]", () => {});4 it("should finally [final step]", () => {});5 6 describe("after [key milestone]", () => {7 it("should [follow-up action]", () => {});8 });9});
Here's a comprehensive example showing how to combine all these rules:
1// Bad 2describe("ShoppingCart", () => { 3 it("test adding item", () => {}); 4 it("check total", () => {}); 5 it("handle checkout", () => {}); 6}); 7 8// Good 9describe("ShoppingCart", () => {10 describe("when adding items", () => {11 it("should add item to cart when add button is clicked", () => {});12 it("should update total price immediately", () => {});13 it("should show item count badge", () => {});14 });15 16 describe("when cart is empty", () => {17 it("should display empty cart message", () => {});18 it("should disable checkout button", () => {});19 });20 21 describe("during checkout process", () => {22 it("should validate stock before proceeding", () => {});23 it("should show loading indicator while processing payment", () => {});24 it("should display success message after completion", () => {});25 });26});
Before committing your test, verify that its name: