mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
merge: board selector default boards fix
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import * as React from 'react';
|
||||
import { createElement } from 'react';
|
||||
import { createRoot, type Root } from 'react-dom/client';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import Rules from '../rules';
|
||||
|
||||
(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>;
|
||||
|
||||
const testState = vi.hoisted(() => ({
|
||||
boardIdentifier: undefined as string | undefined,
|
||||
communities: {} as Record<string, { rules?: string[]; shortAddress?: string; state?: string; title?: string }>,
|
||||
directories: [
|
||||
{ address: 'anime-posting.eth', title: '/a/ - Anime & Manga' },
|
||||
{ address: 'random-posting.eth', title: '/b/ - Random' },
|
||||
] as Array<{ address: string; title?: string }>,
|
||||
navigateMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('react-router-dom', async () => {
|
||||
const actual = await vi.importActual<typeof import('react-router-dom')>('react-router-dom');
|
||||
return {
|
||||
...actual,
|
||||
useNavigate: () => testState.navigateMock,
|
||||
useParams: () => ({
|
||||
boardIdentifier: testState.boardIdentifier,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
||||
useCommunity: ({ communityAddress }: { communityAddress?: string }) => (communityAddress ? testState.communities[communityAddress] : undefined),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/use-directories', async () => {
|
||||
const actual = await vi.importActual<typeof import('../../../hooks/use-directories')>('../../../hooks/use-directories');
|
||||
return {
|
||||
...actual,
|
||||
useDirectories: () => testState.directories,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../home', () => ({
|
||||
Footer: () => createElement('div', { 'data-testid': 'footer' }, 'footer'),
|
||||
HomeLogo: () => createElement('div', { 'data-testid': 'home-logo' }, 'home-logo'),
|
||||
}));
|
||||
|
||||
vi.mock('../../../components/markdown', () => ({
|
||||
default: ({ content }: { content: string }) => createElement('div', { 'data-testid': 'markdown' }, content),
|
||||
}));
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let root: Root;
|
||||
|
||||
const renderRules = async () => {
|
||||
await act(async () => {
|
||||
root.render(createElement(Rules));
|
||||
});
|
||||
};
|
||||
|
||||
describe('Rules', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
testState.boardIdentifier = undefined;
|
||||
testState.communities = {};
|
||||
testState.directories = [
|
||||
{ address: 'anime-posting.eth', title: '/a/ - Anime & Manga' },
|
||||
{ address: 'random-posting.eth', title: '/b/ - Random' },
|
||||
];
|
||||
window.scrollTo = vi.fn();
|
||||
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
root = createRoot(container);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
act(() => root.unmount());
|
||||
container.remove();
|
||||
});
|
||||
|
||||
it('keeps custom-address routes out of the default board select', async () => {
|
||||
testState.boardIdentifier = 'custom-board.eth';
|
||||
testState.communities = {
|
||||
'custom-board.eth': {
|
||||
rules: ['No custom options in the select.'],
|
||||
shortAddress: 'custom-board.eth',
|
||||
state: 'succeeded',
|
||||
},
|
||||
};
|
||||
|
||||
await renderRules();
|
||||
|
||||
const select = container.querySelector('select');
|
||||
expect(select).toBeTruthy();
|
||||
expect(select?.value).toBe('');
|
||||
expect(Array.from(select?.options ?? []).map((option) => option.value)).toEqual(['', 'anime-posting.eth', 'random-posting.eth']);
|
||||
expect(container.textContent).toContain('Rules for: custom-board.eth');
|
||||
});
|
||||
|
||||
it('keeps the canonical default board selected for known directories', async () => {
|
||||
testState.boardIdentifier = 'a';
|
||||
testState.communities = {
|
||||
'anime-posting.eth': {
|
||||
rules: ['Stay on topic.'],
|
||||
state: 'succeeded',
|
||||
},
|
||||
};
|
||||
|
||||
await renderRules();
|
||||
|
||||
const select = container.querySelector('select');
|
||||
expect(select).toBeTruthy();
|
||||
expect(select?.value).toBe('anime-posting.eth');
|
||||
expect(Array.from(select?.options ?? []).map((option) => option.value)).toEqual(['', 'anime-posting.eth', 'random-posting.eth']);
|
||||
expect(container.textContent).toContain('Rules for: /a/ - Anime & Manga');
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState, FormEvent } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useCommunity } from '@bitsocialnet/bitsocial-react-hooks';
|
||||
import { Footer, HomeLogo } from '../home';
|
||||
import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories';
|
||||
import { useDirectories, DirectoryCommunity, findDirectoryByAddress } from '../../hooks/use-directories';
|
||||
import { getSubplebbitAddress, getBoardPath } from '../../lib/utils/route-utils';
|
||||
import Markdown from '../../components/markdown';
|
||||
import styles from './rules.module.css';
|
||||
@@ -103,6 +103,8 @@ const BoardSelector = ({
|
||||
onSelect: (address: string) => void;
|
||||
}) => {
|
||||
const [customAddress, setCustomAddress] = useState('');
|
||||
const selectedDefaultBoard = findDirectoryByAddress(directories, selectedAddress);
|
||||
const selectedBoardValue = selectedDefaultBoard?.address ?? '';
|
||||
|
||||
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = e.target.value;
|
||||
@@ -129,7 +131,7 @@ const BoardSelector = ({
|
||||
</div>
|
||||
<div className={styles.boxContent}>
|
||||
<div className={styles.selectorRow}>
|
||||
<select value={selectedAddress} onChange={handleSelectChange} className={styles.boardSelect}>
|
||||
<select value={selectedBoardValue} onChange={handleSelectChange} className={styles.boardSelect}>
|
||||
<option value=''>Select board...</option>
|
||||
{[...directories]
|
||||
.sort((a, b) => getBoardShortCode(a.title).localeCompare(getBoardShortCode(b.title)))
|
||||
@@ -142,7 +144,6 @@ const BoardSelector = ({
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
{selectedAddress && !directories.some((sub) => sub.address === selectedAddress) && <option value={selectedAddress}>{selectedAddress}</option>}
|
||||
</select>
|
||||
<span className={styles.orSeparator}>or</span>
|
||||
<form onSubmit={handleCustomSubmit} className={styles.customAddressForm}>
|
||||
|
||||
Reference in New Issue
Block a user