import * as React from 'react'; import { createElement } from 'react'; import { createRoot, Root } from 'react-dom/client'; import { MemoryRouter, useLocation } from 'react-router-dom'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import SettingsModal from '../settings-modal'; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; const act = (React as { act?: (cb: () => void | Promise) => void | Promise }).act as (cb: () => void | Promise) => void | Promise; const testState = vi.hoisted(() => ({ account: { pkcOptions: { libp2pJsClientsOptions: [{ key: 'libp2pjs' }], }, } as Record, })); vi.mock('@bitsocial/bitsocial-react-hooks', () => ({ useAccount: () => testState.account, })); vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, }), })); vi.mock('../account-settings', () => ({ default: () =>
account-settings
, })); vi.mock('../crypto-address-setting', () => ({ default: () =>
crypto-address-setting
, })); vi.mock('../crypto-wallets-setting', () => ({ default: () =>
crypto-wallets-setting
, })); vi.mock('../interface-settings', () => ({ default: () =>
interface-settings
, })); vi.mock('../media-hosting-settings', () => ({ default: () =>
media-hosting-settings
, })); vi.mock('../advanced-settings', () => ({ default: () =>
advanced-settings
, })); vi.mock('../subscriptions-setting', () => ({ default: () =>
subscriptions-settings
, })); vi.mock('../trusted-board-links-setting', () => ({ default: () =>
trusted-board-links-settings
, })); vi.mock('../p2p-stats-settings', () => ({ default: () =>
p2p-stats-settings
, })); const LocationProbe = () => { const location = useLocation(); return
{location.pathname + location.hash}
; }; let root: Root; let container: HTMLDivElement; const render = (initialEntry = '/all/settings') => { act(() => { root.render( createElement(MemoryRouter, { initialEntries: [initialEntry] }, createElement(React.Fragment, {}, createElement(SettingsModal), createElement(LocationProbe))), ); }); }; const getLocationText = () => container.querySelector('[data-testid="location"]')?.textContent ?? ''; const getSectionToggleByText = (text: string) => { const control = Array.from(container.querySelectorAll('label, button')).find((candidate) => (candidate.textContent ?? '').includes(text)); if (!control) { throw new Error(`Section toggle containing "${text}" not found`); } return control; }; describe('SettingsModal', () => { beforeEach(() => { vi.clearAllMocks(); container = document.createElement('div'); document.body.appendChild(container); root = createRoot(container); }); afterEach(() => { act(() => root.unmount()); container.remove(); }); it('opens the account section for crypto subsection hashes', () => { render('/all/settings#crypto-wallet-settings'); expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull(); expect(container.querySelector('[data-testid="crypto-address-setting"]')).not.toBeNull(); expect(container.querySelector('[data-testid="crypto-wallets-setting"]')).not.toBeNull(); }); it('updates the hash when sections open and close', async () => { render('/all/settings#account-settings'); expect(getLocationText()).toBe('/all/settings#account-settings'); await act(async () => { getSectionToggleByText('interface').click(); }); expect(getLocationText()).toBe('/all/settings#interface-settings'); expect(container.querySelector('[data-testid="interface-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull(); await act(async () => { getSectionToggleByText('interface').click(); }); expect(getLocationText()).toBe('/all/settings#account-settings'); expect(container.querySelector('[data-testid="interface-settings-panel"]')).toBeNull(); await act(async () => { getSectionToggleByText('bitsocial_account').click(); }); expect(getLocationText()).toBe('/all/settings'); expect(container.querySelector('[data-testid="account-settings"]')).toBeNull(); }); it('expands and collapses all settings sections', async () => { render('/all/settings'); const expandAllControl = Array.from(container.querySelectorAll('button')).find((candidate) => (candidate.textContent ?? '').includes('expand_all_settings')); if (!expandAllControl) { throw new Error('expand_all_settings control not found'); } await act(async () => { expandAllControl.dispatchEvent(new MouseEvent('click', { bubbles: true })); }); expect(container.querySelector('[data-testid="interface-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="media-hosting-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="account-settings"]')).not.toBeNull(); expect(container.querySelector('[data-testid="subscriptions-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="trusted-board-links-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="advanced-settings-panel"]')).not.toBeNull(); expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull(); const collapseAllControl = Array.from(container.querySelectorAll('button')).find((candidate) => (candidate.textContent ?? '').includes('collapse_all_settings')); if (!collapseAllControl) { throw new Error('collapse_all_settings control not found'); } await act(async () => { collapseAllControl.dispatchEvent(new MouseEvent('click', { bubbles: true })); }); expect(container.querySelector('[data-testid="interface-settings-panel"]')).toBeNull(); expect(container.querySelector('[data-testid="media-hosting-settings-panel"]')).toBeNull(); expect(container.querySelector('[data-testid="account-settings"]')).toBeNull(); expect(container.querySelector('[data-testid="subscriptions-settings-panel"]')).toBeNull(); expect(container.querySelector('[data-testid="trusted-board-links-settings-panel"]')).toBeNull(); expect(container.querySelector('[data-testid="advanced-settings-panel"]')).toBeNull(); expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).toBeNull(); }); it('opens the p2p stats section from its hash', () => { render('/all/settings#p2p-stats-settings'); expect(container.querySelector('[data-testid="p2p-stats-settings-panel"]')).not.toBeNull(); }); it('closes the modal when the overlay is clicked', async () => { render('/all/settings#interface-settings'); const overlay = container.querySelector('button'); if (!overlay) { throw new Error('overlay not found'); } await act(async () => { overlay.dispatchEvent(new MouseEvent('click', { bubbles: true })); }); expect(getLocationText()).toBe('/all'); }); it('closes the modal when Escape is pressed', async () => { render('/all/settings'); await act(async () => { document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); }); expect(getLocationText()).toBe('/all'); }); });