Middleware в Page.js представляет собой функции, которые выполняются
до основного обработчика маршрута и позволяют
обрабатывать запрос, изменять контекст или контролировать навигацию.
Каждый middleware получает один параметр — объект ctx,
содержащий информацию о текущем маршруте, и функцию next,
вызывающую следующий middleware в цепочке.
page((ctx, next) => {
console.log('Текущий путь:', ctx.path);
next();
});
?.Middleware можно добавлять глобально или для конкретных маршрутов.
Глобальный middleware:
page((ctx, next) => {
ctx.state.startTime = Date.now();
next();
});
Middleware для конкретного маршрута:
page('/profile/:id', authMiddleware, profileHandler);
function authMiddleware(ctx, next) {
if (!ctx.state.user) {
page.redirect('/login');
} else {
next();
}
}
Важный момент: порядок регистрации имеет значение. Middleware выполняются строго в том порядке, в котором они объявлены.
next() и контроль выполненияФункция next() передаёт управление следующему
middleware. Если она не вызвана, цепочка останавливается. Это
используется для:
Пример асинхронного middleware:
page(async (ctx, next) => {
ctx.state.data = await fetchData(ctx.params.id);
next();
});
Тестирование middleware важно для подтверждения корректности обработки маршрутов, проверки логики авторизации, загрузки данных и управления состоянием.
import page from 'page';
import sinon from 'sinon';
describe('authMiddleware', () => {
it('перенаправляет неавторизованного пользователя', () => {
const ctx = { state: {}, path: '/profile', redirect: sinon.spy() };
const next = sinon.spy();
authMiddleware(ctx, next);
sinon.assert.calledWith(ctx.redirect, '/login');
sinon.assert.notCalled(next);
});
it('позволяет авторизованному пользователю продолжить', () => {
const ctx = { state: { user: { name: 'Alice' } }, path: '/profile', redirect: sinon.spy() };
const next = sinon.spy();
authMiddleware(ctx, next);
sinon.assert.calledOnce(next);
sinon.assert.notCalled(ctx.redirect);
});
});
Ключевые моменты тестирования:
ctx с необходимыми полями для
теста.spy для отслеживания вызовов
next() или redirect().ctx.state.user есть/нет).Асинхронные middleware требуют применения async/await и
проверок после завершения промисов:
it('загружает данные перед продолжением', async () => {
const ctx = { params: { id: 1 }, state: {} };
const next = sinon.spy();
await dataMiddleware(ctx, next);
expect(ctx.state.data).toBeDefined();
sinon.assert.calledOnce(next);
});
Page.js поддерживает цепочки middleware, что позволяет строить многоуровневую обработку маршрутов:
page('/dashboard', authMiddleware, loadDashboardData, renderDashboard);
function loadDashboardData(ctx, next) {
ctx.state.dashboard = fetchDashboard();
next();
}
При тестировании таких цепочек важно:
next().ctx для разных сценариев
(например, пользователь авторизован/не авторизован).Для точного тестирования middleware часто используют
mock-функции и объекты ctx, чтобы
изолировать логику от внешних зависимостей, таких как серверные API или
localStorage:
const mockCtx = {
state: {},
redirect: jest.fn(),
params: {},
path: '/test'
};
const next = jest.fn();
await someMiddleware(mockCtx, next);
expect(next).toHaveBeenCalled();
expect(mockCtx.state.modified).toBe(true);
Для тестирования полезно интегрировать логирование вызовов middleware. Это помогает:
ctx.state.page((ctx, next) => {
console.log('Middleware 1:', ctx.path);
next();
});
page((ctx, next) => {
console.log('Middleware 2:', ctx.state);
next();
});
Логирование позволяет визуально убедиться, что middleware вызываются в ожидаемом порядке и данные передаются корректно.
next() в
тестах, чтобы не допустить зависаний.async/await и моками
API.Эти подходы позволяют строить устойчивые, легко тестируемые маршруты в приложениях с Page.js и обеспечивают надежную проверку логики middleware на всех уровнях.