// In-memory browser history and fictional programs only. No network calls. import assert from 'node:assert/strict'; import { parseHTML } from 'linkedom'; import { createServer } from 'vite'; const { window } = parseHTML('
'); Object.assign(globalThis, { window, document: window.document, HTMLElement: window.HTMLElement, IS_REACT_ACT_ENVIRONMENT: true }); window.location = new URL('https://test.invalid/checkup/'); window.history = { scrollRestoration: 'auto' }; const scrolls = []; window.scrollTo = (...args) => scrolls.push(['top', ...args]); window.HTMLElement.prototype.scrollIntoView = function(options) { scrolls.push(['list', this.textContent, options]); }; const { default: React, act } = await import('react'); const { createRoot } = await import('react-dom/client'); const { Simulate } = await import('react-dom/test-utils'); const { MemoryRouter, Routes, Route, useNavigate, useLocation } = await import('react-router-dom'); const vite = await createServer({ server: { middlewareMode: true, hmr: false }, appType: 'custom' }); const { default: Layout } = await vite.ssrLoadModule('/src/components/Layout.jsx'); const { default: CheckupsPage } = await vite.ssrLoadModule('/src/pages/CheckupsPage.jsx'); const { ApiDataProvider } = await vite.ssrLoadModule('/src/context/ApiData.jsx'); const { api } = await vite.ssrLoadModule('/src/api.js'); const programs = [{ id: 1, slug: 'child', name: 'Детский тест', audience: 'kids' }, { id: 2, slug: 'adult', name: 'Взрослый тест', audience: 'adults' }]; api.checkups = async () => ({ data: programs }); api.branches = api.settings = async () => ({ data: [] }); let navigate; let currentLocation; function HistoryProbe() { navigate = useNavigate(); currentLocation = useLocation(); return null; } const container = document.getElementById('root'); const root = createRoot(container); const click = async (node) => { assert.ok(node); await act(async () => Simulate.click(node, { button: 0 })); }; async function mount(url) { await act(async () => root.render(React.createElement(MemoryRouter, { key: url, initialEntries: ['/previous/', url] }, React.createElement(ApiDataProvider, { value: {} }, React.createElement(HistoryProbe), React.createElement(Routes, {}, React.createElement(Route, { element: React.createElement(Layout) }, React.createElement(Route, { path: '/checkup/', element: React.createElement(CheckupsPage) }), React.createElement(Route, { path: '/checkup/:slug/', element: React.createElement('p', {}, 'Detail page') }), React.createElement(Route, { path: '/previous/', element: React.createElement('p', {}, 'Previous page') }))))))); } const selected = () => container.querySelector('[role="tab"][aria-selected="true"]').textContent; try { await mount('/checkup/'); assert.equal(window.history.scrollRestoration, 'manual'); assert.equal(selected(), 'Взрослые'); scrolls.length = 0; await click([...container.querySelectorAll('[role="tab"]')].find((node) => node.textContent === 'Детские')); assert.equal(selected(), 'Детские'); assert.equal(currentLocation.search, '?audience=kids'); assert.equal(scrolls.length, 0, 'Tab selection must not jump'); await click(container.querySelector('.checkup-card__more')); assert.match(container.textContent, /Detail page/); assert.ok(scrolls.some((s) => s[0] === 'top'), 'New detail page starts at top'); scrolls.length = 0; await act(async () => navigate(-1)); assert.equal(selected(), 'Детские'); assert.match(container.querySelector('.checkup-grid').textContent, /Детский тест/); assert.equal(scrolls.length, 1); assert.equal(scrolls[0][0], 'list'); assert.equal(scrolls[0][1], 'Программы чек-апов'); await act(async () => navigate(1)); scrolls.length = 0; await act(async () => navigate(-1)); assert.equal(selected(), 'Детские'); assert.equal(scrolls[0][0], 'list'); await act(async () => navigate(-1)); assert.equal(currentLocation.pathname, '/previous/', 'Tab changes do not pollute history'); await mount('/checkup/?audience=kids'); assert.equal(selected(), 'Детские', 'Direct links and reloads preserve audience'); await click([...container.querySelectorAll('[role="tab"]')].find((node) => node.textContent === 'Взрослые')); assert.equal(currentLocation.search, ''); await click(container.querySelector('.checkup-card__more')); await act(async () => navigate(-1)); assert.equal(selected(), 'Взрослые'); console.log('PASS: kids/adult tab persists, Back returns to list heading, Forward/Back works, no extra tab history, new details start at top'); } finally { await act(async () => root.unmount()); assert.equal(window.history.scrollRestoration, 'auto', 'Unmount restores browser policy'); await vite.close(); }