Hyperapp — это минималистичный JavaScript-фреймворк для создания пользовательских интерфейсов с реактивной моделью данных. Его ядро построено на концепции state-driven UI, где интерфейс полностью определяется состоянием приложения. Основные элементы архитектуры Hyperapp:
Эта модель позволяет строить приложения, где поток данных прост и предсказуем, а интерфейс полностью определяется состоянием.
Hyperapp не требует сложной сборки: достаточно подключения через npm или CDN. Типичный процесс установки через npm выглядит так:
npm install hyperapp
Импорт в модуле ES6:
import { h, app } from "hyperapp";
Создание базового приложения:
const state = { count: 0 };
const actions = {
increment: () => state => ({ count: state.count + 1 }),
decrement: () => state => ({ count: state.count - 1 })
};
const view = (state, actions) => (
<div>
<h1>{state.count}</h1>
<button oncl ick={actions.increment}>+</button>
<button oncl ick={actions.decrement}>-</button>
</div>
);
app({ init: state, view, actions, root: document.getElementById("app") });
Тестирование в Hyperapp можно разделить на юнит-тестирование, интеграционное тестирование и e2e-тестирование. Для каждого типа доступны специальные инструменты.
Юнит-тесты проверяют отдельные функции и действия, обеспечивая корректное изменение состояния.
Jest — основной инструмент для юнит-тестов в Hyperapp. Он позволяет:
Пример тестирования action с Jest:
import { actions } from "./actions";
test("increment action increases count", () => {
const state = { count: 0 };
const newState = actions.increment()(state);
expect(newState.count).toBe(1);
});
Mocha + Chai также могут применяться для тестирования логики приложения. Их комбинация особенно полезна для гибкой настройки асинхронных сценариев и сложных проверок состояния.
Hyperapp не использует сложный виртуальный DOM, как React, но тестирование view-компонентов также возможно с помощью библиотек:
Пример теста view-компонента:
import { h } from "hyperapp";
import { render } from "@testing-library/dom";
import { view } from "./app";
test("view renders initial state", () => {
const container = document.createElement("div");
render(view({ count: 0 }, {}), container);
expect(container.textContent).toContain("0");
});
Интеграционные тесты проверяют взаимодействие нескольких частей приложения: состояния, действий и эффектов.
Cypress — популярный фреймворк для интеграционных тестов в браузере. Он позволяет симулировать пользовательские события и проверять изменения интерфейса при изменении состояния.
Пример Cypress-теста:
describe("Counter app", () => {
it("increments and decrements counter", () => {
cy.visit("http://localhost:3000");
cy.get("button").contains("+").click();
cy.get("h1").should("contain", "1");
cy.get("button").contains("-").click();
cy.get("h1").should("contain", "0");
});
});
End-to-End тесты оценивают поведение приложения в реальных условиях. Помимо Cypress, можно использовать Playwright, который поддерживает автоматизацию браузеров, скриншоты и многопоточность. E2E-тесты проверяют сценарии пользователя от входа на страницу до взаимодействия с динамическими компонентами.
Для качественного тестирования важно изолировать Hyperapp-приложение от внешних зависимостей:
fetch-mock или
msw.Пример эффекта с мокированием:
const fetchEffect = (url) => (dispatch, props) => {
fetch(url)
.then(res => res.json())
.then(data => dispatch({ type: "setData", data }))
.catch(err => console.error(err));
};
При тестировании этот эффект можно заменить на:
const mockFetchEffect = (url) => (dispatch) => {
dispatch({ type: "setData", data: { mock: true } });
};
Для оценки качества тестирования используется coverage-отчет:
Пример команды для Jest:
jest --coverage
Hyperapp, несмотря на минимализм, легко интегрируется с современными инструментами тестирования, обеспечивая высокое качество приложений и предсказуемость их поведения.