JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicstestingTest Organization and Structure
PrevNext
testing
beginner
8 min read

Test Organization and Structure

aaa-pattern
best-practices
describe
naming
organization
test-structure

How to organize test files, structure tests with describe and it blocks, write descriptive test names, apply the Arrange-Act-Assert pattern, and choose between co-located and centralized test directories.

Key Points

1Co-located vs Centralized Tests

Co-located tests (Button.test.tsx next to Button.tsx) are preferred in modern projects because they reduce friction and make missing tests visible.

2describe and it Hierarchy

Use describe blocks to group related tests by feature or method, and it/test blocks for individual behaviors. Nesting creates a readable hierarchy.

3Arrange-Act-Assert Pattern

Structure every test in three phases: set up preconditions (Arrange), execute the behavior (Act), and verify the outcome (Assert) for consistent readability.

4Descriptive Test Names

Test names should describe expected behavior, not implementation. A new team member should understand what is being tested without reading the test body.

What You'll Learn

  • Choose between co-located and centralized test file organization for a project
  • Structure tests with describe/it blocks and descriptive naming conventions
  • Apply the Arrange-Act-Assert pattern consistently across all tests
  • Use skip and only for debugging without accidentally committing focused tests

Deep Dive

Well-structured tests are easy to read, maintain, and debug. Test organization is one of the first things interviewers notice because it reflects overall engineering discipline. Both Jest and Vitest use the same describe/it/test API.

File Organization Strategies

There are two main approaches to organizing test files:

Co-located tests place test files next to the code they test:

JavaScript
src/
  components/
    Button.tsx
    Button.test.tsx
  utils/
    format.ts
    format.test.ts

Advantages: Easy to find tests for any file, encourages testing as part of development, makes it obvious when a file lacks tests.

Centralized test directory keeps all tests in a separate __tests__ folder:

JavaScript
src/
  components/
    Button.tsx
  utils/
    format.ts
__tests__/
  components/
    Button.test.tsx
  utils/
    format.test.ts

Advantages: Cleaner source directories, easier to configure separate tooling for tests, matches some organizational preferences.

Most modern projects prefer co-located tests because they reduce friction and make test gaps visible.

describe and it/test Blocks

describe groups related tests. it (or test -- they are aliases) defines individual test cases:

JavaScript
describe('ShoppingCart', () => {
  describe('addItem', () => {
    it('adds the item to the cart', () => { ... });
    it('increases the total by the item price', () => { ... });
    it('handles duplicate items by incrementing quantity', () => { ... });
  });
 
  describe('removeItem', () => {
    it('removes the item from the cart', () => { ... });
    it('throws an error when the item is not in the cart', () => { ... });
  });
});

describe blocks can be nested to create a hierarchy that mirrors the code's structure or the behavior being tested.

Test Naming Conventions

Good test names describe the expected behavior, not the implementation:

  • Use it('should ...') or it('returns/throws/renders ...') format
  • Describe the scenario and expected outcome
  • Avoid technical jargon in test names -- a new team member should understand what is being tested

Good: it('displays an error message when the email is invalid') Bad: it('calls setError with validation result when regex fails')

Arrange-Act-Assert (AAA) Pattern

Every test should have three clearly separated phases:

JavaScript
it('applies a 10% discount for orders over $100', () => {
  // Arrange: Set up test data and preconditions
  const cart = createCart();
  cart.addItem({ name: 'Laptop', price: 150 });
 
  // Act: Execute the behavior under test
  const total = cart.calculateTotal();
 
  // Assert: Verify the expected outcome
  expect(total).toBe(135);
});

Some teams add comments to mark each phase, others rely on whitespace separation. The key is consistency within the project.

One Assertion Per Test (Guideline)

Each test should ideally verify one behavior. Multiple assertions are acceptable when they verify different aspects of the same behavior, but if a test needs many assertions, it may be testing too much.

Test File Naming

Common conventions:

  • Component.test.tsx (most common)
  • Component.spec.tsx (BDD-influenced)
  • __tests__/Component.tsx (directory-based)

Jest and Vitest auto-discover files matching **/*.test.{js,ts,jsx,tsx} and **/*.spec.{js,ts,jsx,tsx} by default.

Skipping and Focusing Tests

  • it.skip() / xit(): Temporarily skip a test
  • it.only() / fit(): Run only this test (useful for debugging)
  • describe.skip() / describe.only(): Skip or focus entire groups

Never commit .only to source control -- it silently skips other tests. Use ESLint rules like eslint-plugin-jest or eslint-plugin-vitest to prevent this.

Fun Fact

The describe/it naming convention comes from RSpec (Ruby, 2005), which was designed to read like English: 'describe ShoppingCart, it adds items to the cart'. This BDD-inspired syntax was adopted by Mocha, then Jasmine, then Jest, and finally Vitest.

Learn These First

Unit Testing Fundamentals

beginner

Continue Learning

Matchers and Assertions

beginner

Test Lifecycle Hooks

beginner

TDD vs BDD Methodologies

advanced

Practice What You Learned

How should you structure and organize test files?
junior
structure
Tests can be organized either alongside source files (Component.test.js) or in a separate __tests__ directory. Use describe blocks to group related tests, clear test names that describe behavior, and follow the Given-When-Then or AAA pattern for clarity.
Previous
Testing Strategy for Large Applications
Next
Visual Regression Testing
PrevNext