forked from boos/BoosAPI
feat: refine BoosAPI console and user workspace
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
describe('App route transition feedback', () => {
|
||||
it('tracks pathname and query changes without remounting page content for search-only navigation', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/web/App.tsx'), 'utf8').replace(/\r\n/g, '\n');
|
||||
|
||||
expect(source).toContain('const routeTransitionKey = `${location.pathname}${location.search}`;');
|
||||
expect(source).toContain('const previousRouteTransitionKeyRef = useRef(routeTransitionKey);');
|
||||
expect(source).toContain('const sidebarRef = useRef<HTMLElement>(null);');
|
||||
expect(source).toContain('const mainRef = useRef<HTMLElement>(null);');
|
||||
expect(source).toContain("import { shouldFocusMainOnRouteChange } from './pages/helpers/routeFocus.js';");
|
||||
expect(source).toContain('previousRouteTransitionKeyRef.current === routeTransitionKey');
|
||||
expect(source).toContain('className="skip-link"');
|
||||
expect(source).toContain('href="#main-content"');
|
||||
expect(source).toContain('mainRef.current?.focus({ preventScroll: true });');
|
||||
expect(source).toContain("{t('跳到主内容')}");
|
||||
expect(source).toContain('ref={mainRef}');
|
||||
expect(source).toContain('id="main-content"');
|
||||
expect(source).toContain('tabIndex={-1}');
|
||||
expect(source).toContain("aria-label={t('主内容')}");
|
||||
expect(source).toContain('const pageMotionKey = `${location.pathname}${location.search}`;');
|
||||
expect(source).toContain('key={location.pathname} motionKey={pageMotionKey}');
|
||||
expect(source).toContain('<Suspense fallback={null}>');
|
||||
expect(source).not.toContain('function RouteLoadingFallback');
|
||||
expect(source).not.toContain('fallback={<RouteLoadingFallback />}');
|
||||
expect(source).not.toContain('routeTransitioning');
|
||||
expect(source).not.toContain('is-route-transitioning');
|
||||
expect(source).toContain('className="sr-only"');
|
||||
expect(source).toContain('aria-live="polite"');
|
||||
expect(source).toContain('aria-atomic="true"');
|
||||
});
|
||||
|
||||
it('moves focus to the main region on shell-driven route changes without stealing field focus', () => {
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/web/App.tsx'), 'utf8').replace(/\r\n/g, '\n');
|
||||
|
||||
expect(source).toContain('const shouldFocusMain = shouldFocusMainOnRouteChange(document.activeElement, {');
|
||||
expect(source).toContain('body: document.body,');
|
||||
expect(source).toContain('topbar: topbarRef.current,');
|
||||
expect(source).toContain('sidebar: sidebarRef.current,');
|
||||
expect(source).not.toContain('const shouldFocusMain = !activeElement');
|
||||
expect(source).toContain('let focusFrameId: number | null = null;');
|
||||
expect(source).toContain("const schedule = typeof window.requestAnimationFrame === 'function'");
|
||||
expect(source).toContain('focusFrameId = schedule(() => {');
|
||||
expect(source).toContain('mainRef.current?.focus({ preventScroll: true });');
|
||||
expect(source).toContain("typeof window.cancelAnimationFrame === 'function'");
|
||||
expect(source).toContain('window.cancelAnimationFrame(focusFrameId);');
|
||||
});
|
||||
|
||||
it('does not render a blocking shell loading frame while lazy routes resolve', () => {
|
||||
const css = readFileSync(resolve(process.cwd(), 'src/web/index.css'), 'utf8').replace(/\r\n/g, '\n');
|
||||
const source = readFileSync(resolve(process.cwd(), 'src/web/App.tsx'), 'utf8').replace(/\r\n/g, '\n');
|
||||
|
||||
expect(css).toContain('.skip-link');
|
||||
expect(css).toContain('.skip-link:focus,\n.skip-link:focus-visible');
|
||||
expect(css).toContain('.sr-only');
|
||||
expect(css).toContain('.skip-link,\n .skip-link:focus,\n .skip-link:focus-visible');
|
||||
expect(source).not.toContain('RouteLoadingFallback');
|
||||
expect(source).not.toContain('animate-fade-in');
|
||||
expect(source).not.toContain('aria-busy={routeTransitioning}');
|
||||
expect(css).not.toContain('.route-progress');
|
||||
expect(css).not.toContain('@keyframes route-progress-sweep');
|
||||
expect(css).not.toContain('.main-content.is-route-transitioning');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user