Frontend unit tests development (Vitest)

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Developing Unit Tests for Frontend (Vitest)

Vitest—next-generation test runner from Vite team. Uses same config as Vite project, supports native ESM, order of magnitude faster than Jest on large projects. Default choice for Vite, Nuxt 3, SvelteKit projects.

Setup

npm install -D vitest @vitest/ui jsdom @testing-library/react @testing-library/jest-dom
// vite.config.ts (or vitest.config.ts)
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [react()],
    test: {
        environment: 'jsdom',
        globals: true,
        setupFiles: ['./src/test/setup.ts'],
        coverage: {
            provider: 'v8',
            reporter: ['text', 'json', 'html'],
            thresholds: { lines: 80, functions: 80, branches: 70 },
        },
    },
});
// src/test/setup.ts
import '@testing-library/jest-dom';
import { cleanup } from '@testing-library/react';
import { afterEach } from 'vitest';

afterEach(() => cleanup());

Syntax Identical to Jest

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { formatDate } from '../utils/date';

describe('formatDate', () => {
    it('formats ISO date to English locale', () => {
        const date = new Date('2024-11-15T10:00:00Z');
        expect(formatDate(date, 'en-US')).toBe('November 15, 2024');
    });

    it('returns dash for null', () => {
        expect(formatDate(null)).toBe('—');
    });
});

Testing Components

import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import userEvent from '@testing-library/user-event';
import { SearchInput } from './SearchInput';

describe('SearchInput', () => {
    it('calls onSearch after debounce', async () => {
        vi.useFakeTimers();
        const onSearch = vi.fn();
        render(<SearchInput onSearch={onSearch} debounce={300} />);

        await userEvent.type(screen.getByRole('searchbox'), 'laptop');
        expect(onSearch).not.toHaveBeenCalled(); // debounce not passed

        vi.advanceTimersByTime(300);
        expect(onSearch).toHaveBeenCalledWith('laptop');

        vi.useRealTimers();
    });

    it('clears input on Escape', async () => {
        render(<SearchInput onSearch={vi.fn()} />);
        const input = screen.getByRole('searchbox');

        await userEvent.type(input, 'text');
        await userEvent.keyboard('{Escape}');
        expect(input).toHaveValue('');
    });
});

Mocks and Spies

// vi.mock—replace module
vi.mock('../services/api', () => ({
    getProducts: vi.fn().mockResolvedValue([
        { id: 1, name: 'MacBook', price: 1500 },
    ]),
}));

// vi.spyOn—spy on method
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});

Concurrent Tests (Difference from Jest)

// Vitest supports parallel tests within describe
describe.concurrent('parallel tests', () => {
    it.concurrent('test 1', async () => { ... });
    it.concurrent('test 2', async () => { ... });
});

UI Mode

# Interactive browser UI
npx vitest --ui
# Opens http://localhost:51204/__vitest__/
# Shows test tree, coverage, failed test diffs

Performance vs Jest

On project with 500+ tests Vitest typically 2–5x faster than Jest due to:

  • Native ESM without CJS transformation
  • Shared dev server with main Vite process
  • Watch mode with HMR for tests

Timeline

Setting up Vitest + migration from Jest (if needed) + writing first test suite: 2–4 days.