Интеграционные тесты навигации

Page.js — это клиентская библиотека маршрутизации для одностраничных приложений на JavaScript. Интеграционные тесты навигации позволяют убедиться, что маршруты обрабатываются корректно, страницы и компоненты отображаются в нужной последовательности, а состояние приложения обновляется предсказуемо при переходах между маршрутами.

Настройка тестового окружения

Для интеграционных тестов необходимо создать изолированное окружение, где маршруты Page.js могут быть обработаны без влияния сторонних факторов. Обычно используется тестовый HTML-файл или контейнер <div> в DOM, куда будут рендериться компоненты приложения.

import page from 'page';

let appContainer;

beforeEach(() => {
    appContainer = document.createElement('div');
    appContainer.id = 'app';
    document.body.appendChild(appContainer);
});

afterEach(() => {
    document.body.removeChild(appContainer);
    page.stop();
});

Ключевым моментом является использование page.stop(), чтобы сбросить все обработчики маршрутов между тестами и исключить побочные эффекты.

Определение маршрутов

Маршруты Page.js задаются через метод page(path, callback). Для тестов можно определить минимальный набор маршрутов, включающий переходы и редиректы:

page('/', () => {
    appContainer.textContent = 'Главная страница';
});

page('/about', () => {
    appContainer.textContent = 'О нас';
});

page('/redirect', () => {
    page.redirect('/about');
});

Для интеграционных тестов важно имитировать реальные переходы и проверять конечное состояние DOM и URL.

Симуляция навигации

Page.js позволяет управлять навигацией через методы page.show(path) и page.start(). Для интеграционных тестов используется последовательное выполнение маршрутов:

test('Навигация между страницами', () => {
    page.start({ dispatch: false });
    
    page.show('/');
    expect(appContainer.textContent).toBe('Главная страница');
    
    page.show('/about');
    expect(appContainer.textContent).toBe('О нас');
});

Параметр dispatch: false отключает автоматическую обработку маршрута при старте, что позволяет полностью контролировать последовательность теста.

Проверка редиректов

Редиректы — одна из наиболее чувствительных частей навигации. Для их тестирования важно убедиться, что после перехода на исходный путь выполняется корректное перенаправление:

test('Редирект с /redirect на /about', () => {
    page.start({ dispatch: false });
    
    page.show('/redirect');
    
    // После редиректа должна отображаться страница /about
    expect(appContainer.textContent).toBe('О нас');
});

Для сложных сценариев можно использовать моки или spy-функции для отслеживания вызовов page.show и page.redirect.

Тестирование динамических маршрутов

Page.js поддерживает параметры в URL (/user/:id). Интеграционные тесты должны проверять корректное извлечение параметров:

page('/user/:id', ctx => {
    appContainer.textContent = `Пользователь ${ctx.params.id}`;
});

test('Динамический маршрут /user/:id', () => {
    page.start({ dispatch: false });

    page.show('/user/42');
    expect(appContainer.textContent).toBe('Пользователь 42');

    page.show('/user/100');
    expect(appContainer.textContent).toBe('Пользователь 100');
});

Контекст ctx предоставляет доступ не только к параметрам, но и к query-параметрам и состоянию навигации, что позволяет тестировать сложные сценарии взаимодействия.

Интеграция с фреймворками

При использовании Page.js в связке с библиотеками вроде React или Vue интеграционные тесты должны проверять, что рендеринг компонентов выполняется корректно. Основная задача — убедиться, что компонент получает правильные пропсы на основе маршрута.

// React пример
import { render } from '@testing-library/react';
import App from './App';

page('/dashboard', () => {
    render(<App route="dashboard" />, appContainer);
});

test('Компонент Dashboard отображается на маршруте /dashboard', () => {
    page.start({ dispatch: false });
    page.show('/dashboard');

    expect(appContainer.querySelector('h1').textContent).toBe('Dashboard');
});

Тестирование навигации с историей

Для проверки работы кнопок браузера (назад/вперед) можно использовать методы истории (window.history.pushState, window.history.back):

test('История браузера обновляется корректно', () => {
    page.start({ dispatch: false });

    page.show('/');
    expect(window.location.pathname).toBe('/');

    page.show('/about');
    expect(window.location.pathname).toBe('/about');

    window.history.back();
    expect(window.location.pathname).toBe('/');
});

Этот подход позволяет симулировать реальные действия пользователя и проверять реакцию приложения на изменения истории.

Логирование и отладка

Для крупных интеграционных тестов полезно подключать логирование маршрутов:

page('*', ctx => {
    console.log(`Навигация на ${ctx.path}`);
});

Это позволяет отслеживать последовательность вызовов, особенно при тестировании редиректов и динамических маршрутов.

Ключевые рекомендации

  • Использовать отдельный контейнер для рендеринга тестируемых компонентов, чтобы избежать конфликтов с реальным DOM.
  • Сбрасывать маршруты после каждого теста с page.stop().
  • Проверять как контент DOM, так и URL браузера для полного контроля навигации.
  • Тестировать редиректы и динамические параметры с различными значениями.
  • Интегрировать Page.js с фреймворками через рендеринг компонентов внутри колбэков маршрутов.

Эти подходы обеспечивают стабильность навигации и позволяют выявлять ошибки в маршрутизации до релиза приложения, делая интеграционные тесты надежным инструментом контроля поведения Page.js в реальном приложении.