mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(faq): scroll direct hash links
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import * as React from 'react';
|
||||
import { createElement } from 'react';
|
||||
import { createRoot, type Root } from 'react-dom/client';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import FAQ from '../faq';
|
||||
|
||||
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
const act = (React as { act?: (cb: () => void | Promise<void>) => void | Promise<void> }).act as (cb: () => void | Promise<void>) => void | Promise<void>;
|
||||
|
||||
vi.mock('react-router-hash-link', () => ({
|
||||
HashLink: ({ children, to }: { children: React.ReactNode; to: string }) => createElement('a', { href: to }, children),
|
||||
}));
|
||||
|
||||
vi.mock('../../home/home', () => ({
|
||||
Footer: () => createElement('div', { 'data-testid': 'footer' }, 'footer'),
|
||||
HomeLogo: () => createElement('div', { 'data-testid': 'home-logo' }, 'home-logo'),
|
||||
}));
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let root: Root;
|
||||
let scrollIntoViewMock: ReturnType<typeof vi.fn>;
|
||||
|
||||
const renderFAQ = async (initialEntry = '/faq') => {
|
||||
await act(async () => {
|
||||
root.render(createElement(MemoryRouter, { initialEntries: [initialEntry] }, createElement(FAQ)));
|
||||
});
|
||||
};
|
||||
|
||||
describe('FAQ', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
window.scrollTo = vi.fn();
|
||||
scrollIntoViewMock = vi.fn();
|
||||
Element.prototype.scrollIntoView = scrollIntoViewMock as unknown as typeof Element.prototype.scrollIntoView;
|
||||
document.title = 'before';
|
||||
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
root = createRoot(container);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
act(() => root.unmount());
|
||||
container.remove();
|
||||
});
|
||||
|
||||
it('scrolls to the FAQ hash target on direct hash routes', async () => {
|
||||
await renderFAQ('/faq#sage');
|
||||
|
||||
const sageQuestion = document.getElementById('sage');
|
||||
expect(sageQuestion?.textContent).toBe('What is "sage"?');
|
||||
expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);
|
||||
expect(scrollIntoViewMock.mock.contexts[0]).toBe(sageQuestion);
|
||||
expect(window.scrollTo).not.toHaveBeenCalled();
|
||||
expect(document.title).toBe('FAQ - 5chan');
|
||||
});
|
||||
|
||||
it('scrolls to the top when there is no FAQ hash target', async () => {
|
||||
await renderFAQ();
|
||||
|
||||
expect(scrollIntoViewMock).not.toHaveBeenCalled();
|
||||
expect(window.scrollTo).toHaveBeenCalledWith(0, 0);
|
||||
expect(document.title).toBe('FAQ - 5chan');
|
||||
});
|
||||
});
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
import { type ReactNode, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { HashLink } from 'react-router-hash-link';
|
||||
import { Footer, HomeLogo } from '../home/home';
|
||||
import styles from './faq.module.css';
|
||||
@@ -788,10 +788,20 @@ const FAQ_SECTIONS: FAQSection[] = [
|
||||
];
|
||||
|
||||
const FAQ = () => {
|
||||
const { hash } = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
document.title = 'FAQ - 5chan';
|
||||
}, []);
|
||||
|
||||
const anchorId = hash.startsWith('#') ? hash.slice(1) : '';
|
||||
const anchorElement = anchorId ? document.getElementById(anchorId) : null;
|
||||
if (anchorElement) {
|
||||
anchorElement.scrollIntoView();
|
||||
return;
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
}, [hash]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
|
||||
Reference in New Issue
Block a user