mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
test(ci): align strict community mocks
This commit is contained in:
@@ -48,7 +48,10 @@ const testState = vi.hoisted(() => ({
|
|||||||
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
||||||
useAccount: () => testState.account,
|
useAccount: () => testState.account,
|
||||||
useAccountComment: ({ commentIndex }: { commentIndex?: number }) => (typeof commentIndex === 'number' ? testState.accountComments[commentIndex] : undefined),
|
useAccountComment: ({ commentIndex }: { commentIndex?: number }) => (typeof commentIndex === 'number' ? testState.accountComments[commentIndex] : undefined),
|
||||||
useCommunity: ({ communityAddress }: { communityAddress?: string }) => (communityAddress ? testState.subplebbits[communityAddress] : undefined),
|
useCommunity: (options?: { communityAddress?: string; community?: { name?: string; publicKey?: string } }) => {
|
||||||
|
const communityAddress = options?.communityAddress ?? options?.community?.name ?? options?.community?.publicKey;
|
||||||
|
return communityAddress ? testState.subplebbits[communityAddress] : undefined;
|
||||||
|
},
|
||||||
useAccountCommunities: () => ({
|
useAccountCommunities: () => ({
|
||||||
accountCommunities: Object.fromEntries(testState.accountSubplebbitAddresses.map((address) => [address, { address }])),
|
accountCommunities: Object.fromEntries(testState.accountSubplebbitAddresses.map((address) => [address, { address }])),
|
||||||
}),
|
}),
|
||||||
|
|||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { createElement } from 'react';
|
||||||
|
import { createRoot, Root } from 'react-dom/client';
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import CryptoAddressSetting from '../crypto-address-setting';
|
||||||
|
|
||||||
|
(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 SIGNER_ADDRESS = '12D3KooWSignerPublicKey';
|
||||||
|
|
||||||
|
const hookMocks = vi.hoisted(() => ({
|
||||||
|
setAccount: vi.fn(),
|
||||||
|
useAccount: vi.fn(),
|
||||||
|
useResolvedAuthorAddress: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TestedCryptoAddressSetting = ((CryptoAddressSetting as unknown as { type?: React.ComponentType }).type ??
|
||||||
|
(CryptoAddressSetting as unknown as React.ComponentType)) as React.ComponentType;
|
||||||
|
|
||||||
|
vi.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) =>
|
||||||
|
(
|
||||||
|
({
|
||||||
|
check: 'check',
|
||||||
|
crypto_address_not_resolved: 'Crypto address is not resolved yet.',
|
||||||
|
crypto_address_not_yours: 'Crypto address is not yours.',
|
||||||
|
crypto_address_verification: 'if the crypto address is resolved p2p',
|
||||||
|
crypto_address_yours: 'Crypto address belongs to this account.',
|
||||||
|
enter_crypto_address: 'Enter crypto address.',
|
||||||
|
loading: 'loading',
|
||||||
|
save: 'save',
|
||||||
|
saved: 'saved',
|
||||||
|
}) as Record<string, string>
|
||||||
|
)[key] ?? key,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
||||||
|
setAccount: hookMocks.setAccount,
|
||||||
|
useAccount: hookMocks.useAccount,
|
||||||
|
useResolvedAuthorAddress: hookMocks.useResolvedAuthorAddress,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let root: Root;
|
||||||
|
let container: HTMLDivElement;
|
||||||
|
let alertSpy: ReturnType<typeof vi.spyOn>;
|
||||||
|
let lastResolveOptions: unknown;
|
||||||
|
let resolvedAuthorState: {
|
||||||
|
chainProvider?: { urls?: string[] };
|
||||||
|
error?: unknown;
|
||||||
|
resolvedAddress?: string | null;
|
||||||
|
state?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const render = async () => {
|
||||||
|
await act(async () => {
|
||||||
|
root.render(createElement(TestedCryptoAddressSetting));
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const rerender = render;
|
||||||
|
|
||||||
|
const getInput = () => {
|
||||||
|
const input = container.querySelector('input[placeholder="myaddress.bso"]') as HTMLInputElement | null;
|
||||||
|
if (!input) {
|
||||||
|
throw new Error('crypto address input not found');
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getButtonByText = (text: string) => {
|
||||||
|
const button = Array.from(container.querySelectorAll('button')).find((candidate) => (candidate.textContent ?? '').trim() === text);
|
||||||
|
if (!button) {
|
||||||
|
throw new Error(`button "${text}" not found`);
|
||||||
|
}
|
||||||
|
return button as HTMLButtonElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInputValue = async (value: string) => {
|
||||||
|
await act(async () => {
|
||||||
|
const input = getInput();
|
||||||
|
const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set;
|
||||||
|
if (!valueSetter) {
|
||||||
|
throw new Error('input value setter not found');
|
||||||
|
}
|
||||||
|
valueSetter.call(input, value);
|
||||||
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('CryptoAddressSetting', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
vi.useFakeTimers();
|
||||||
|
|
||||||
|
resolvedAuthorState = {
|
||||||
|
chainProvider: undefined,
|
||||||
|
error: undefined,
|
||||||
|
resolvedAddress: undefined,
|
||||||
|
state: 'initializing',
|
||||||
|
};
|
||||||
|
lastResolveOptions = undefined;
|
||||||
|
|
||||||
|
hookMocks.useAccount.mockReturnValue({
|
||||||
|
author: {
|
||||||
|
address: 'legacy-name.eth',
|
||||||
|
shortAddress: 'legacy-name.eth',
|
||||||
|
},
|
||||||
|
signer: {
|
||||||
|
address: SIGNER_ADDRESS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
hookMocks.setAccount.mockResolvedValue({});
|
||||||
|
hookMocks.useResolvedAuthorAddress.mockImplementation((options: unknown) => {
|
||||||
|
lastResolveOptions = options;
|
||||||
|
return resolvedAuthorState;
|
||||||
|
});
|
||||||
|
|
||||||
|
alertSpy = vi.spyOn(window, 'alert').mockImplementation(() => undefined);
|
||||||
|
container = document.createElement('div');
|
||||||
|
document.body.appendChild(container);
|
||||||
|
root = createRoot(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
act(() => {
|
||||||
|
vi.runOnlyPendingTimers();
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
container.remove();
|
||||||
|
alertSpy.mockRestore();
|
||||||
|
vi.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the full author address as the initial field value', async () => {
|
||||||
|
hookMocks.useAccount.mockReturnValue({
|
||||||
|
author: {
|
||||||
|
address: 'resolved-alias.eth',
|
||||||
|
shortAddress: 'different-short-address',
|
||||||
|
},
|
||||||
|
signer: {
|
||||||
|
address: SIGNER_ADDRESS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await render();
|
||||||
|
|
||||||
|
expect(getInput().value).toBe('resolved-alias.eth');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates the displayed status after async resolution completes', async () => {
|
||||||
|
await render();
|
||||||
|
|
||||||
|
await setInputValue('music-posting.bso');
|
||||||
|
|
||||||
|
expect(container.textContent).toContain('if the crypto address is resolved p2p');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
getButtonByText('check').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.textContent).toContain('loading');
|
||||||
|
expect((lastResolveOptions as { author?: { address?: string } } | undefined)?.author?.address).toBe('music-posting.bso');
|
||||||
|
|
||||||
|
resolvedAuthorState = {
|
||||||
|
...resolvedAuthorState,
|
||||||
|
resolvedAddress: null,
|
||||||
|
state: 'succeeded',
|
||||||
|
};
|
||||||
|
|
||||||
|
await rerender();
|
||||||
|
|
||||||
|
expect(container.textContent).toContain('Crypto address is not resolved yet.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saves a verified alias when it resolves to the signer address', async () => {
|
||||||
|
await render();
|
||||||
|
|
||||||
|
await setInputValue('resolved-name.bso');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
getButtonByText('check').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
resolvedAuthorState = {
|
||||||
|
...resolvedAuthorState,
|
||||||
|
resolvedAddress: SIGNER_ADDRESS,
|
||||||
|
state: 'succeeded',
|
||||||
|
};
|
||||||
|
|
||||||
|
await rerender();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
getButtonByText('save').click();
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hookMocks.setAccount).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
author: expect.objectContaining({
|
||||||
|
address: 'resolved-name.bso',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(container.textContent).toContain('saved');
|
||||||
|
expect(getInput().value).toBe('resolved-name.bso');
|
||||||
|
expect(alertSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -12,114 +12,153 @@ const withErrorHandling = async <T,>(fn: () => Promise<T>, onError: (e: unknown)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const CryptoAddressSetting = () => {
|
const getInitialCryptoAddress = (address?: string) => (address?.includes('.') ? address : '');
|
||||||
const { t } = useTranslation();
|
|
||||||
const account = useAccount();
|
|
||||||
|
|
||||||
const [cryptoState, setCryptoState] = useState({
|
const getDefaultResolutionStatus = (t: (key: string) => string) => ({
|
||||||
cryptoAddress: account?.author?.shortAddress.includes('.') ? account.author.shortAddress : '',
|
|
||||||
checkingCryptoAddress: false,
|
|
||||||
showResolvingMessage: true,
|
|
||||||
resolveString: t('crypto_address_verification'),
|
|
||||||
resolveClass: '',
|
resolveClass: '',
|
||||||
|
resolveString: t('crypto_address_verification'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getResolutionStatus = ({
|
||||||
|
checkedAddress,
|
||||||
|
chainProviderUrls,
|
||||||
|
error,
|
||||||
|
resolvedAddress,
|
||||||
|
signerAddress,
|
||||||
|
state,
|
||||||
|
t,
|
||||||
|
}: {
|
||||||
|
chainProviderUrls?: string[];
|
||||||
|
checkedAddress?: string;
|
||||||
|
error?: unknown;
|
||||||
|
resolvedAddress?: string | null;
|
||||||
|
signerAddress?: string;
|
||||||
|
state?: string;
|
||||||
|
t: (key: string) => string;
|
||||||
|
}) => {
|
||||||
|
if (!checkedAddress) {
|
||||||
|
return getDefaultResolutionStatus(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'failed') {
|
||||||
|
return {
|
||||||
|
resolveClass: styles.red,
|
||||||
|
resolveString: error instanceof Error ? `failed to resolve crypto address, error: ${error.message}` : 'cannot resolve crypto address, unknown error',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === 'resolving' || state === 'ready' || state === 'initializing') {
|
||||||
|
return {
|
||||||
|
resolveClass: styles.yellow,
|
||||||
|
resolveString: chainProviderUrls ? `resolving from ${chainProviderUrls.join(', ')}` : t('loading'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedAddress && resolvedAddress === signerAddress) {
|
||||||
|
return {
|
||||||
|
resolveClass: styles.green,
|
||||||
|
resolveString: t('crypto_address_yours'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedAddress && resolvedAddress !== signerAddress) {
|
||||||
|
return {
|
||||||
|
resolveClass: styles.red,
|
||||||
|
resolveString: t('crypto_address_not_yours'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedAddress === null || state === 'succeeded') {
|
||||||
|
return {
|
||||||
|
resolveClass: styles.red,
|
||||||
|
resolveString: t('crypto_address_not_resolved'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return getDefaultResolutionStatus(t);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showSavedIndicator = (setSavedCryptoAddress: (value: boolean) => void) => {
|
||||||
|
setSavedCryptoAddress(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setSavedCryptoAddress(false);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CryptoAddressSettingContent = ({ account }: { account: ReturnType<typeof useAccount> }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [cryptoAddress, setCryptoAddress] = useState(() => getInitialCryptoAddress(account?.author?.address));
|
||||||
|
const [checkedAddress, setCheckedAddress] = useState<string>();
|
||||||
|
const [savedCryptoAddress, setSavedCryptoAddress] = useState(false);
|
||||||
|
const [showCryptoAddressInfo, setShowCryptoAddressInfo] = useState(false);
|
||||||
|
|
||||||
|
const signerAddress = account?.signer?.address;
|
||||||
|
const authorToResolve = checkedAddress ? { ...account?.author, address: checkedAddress } : undefined;
|
||||||
|
const { resolvedAddress, state, error, chainProvider } = useResolvedAuthorAddress({ author: authorToResolve, cache: false });
|
||||||
|
const resolutionStatus = getResolutionStatus({
|
||||||
|
chainProviderUrls: chainProvider?.urls,
|
||||||
|
checkedAddress,
|
||||||
|
error,
|
||||||
|
resolvedAddress,
|
||||||
|
signerAddress,
|
||||||
|
state,
|
||||||
|
t,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [savedCryptoAddress, setSavedCryptoAddress] = useState(false);
|
|
||||||
const [shouldResolve, setShouldResolve] = useState(false);
|
|
||||||
|
|
||||||
const authorToResolve = shouldResolve ? { ...account?.author, address: cryptoState.cryptoAddress } : undefined;
|
|
||||||
const { resolvedAddress, state, error, chainProvider } = useResolvedAuthorAddress({ author: authorToResolve, cache: false });
|
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState(account?.author?.shortAddress.includes('.') ? account.author.shortAddress : '');
|
|
||||||
|
|
||||||
const checkCryptoAddress = () => {
|
const checkCryptoAddress = () => {
|
||||||
setShouldResolve(true);
|
const addressToCheck = cryptoAddress.trim();
|
||||||
const addressToCheck = inputValue || cryptoState.cryptoAddress;
|
|
||||||
if (!addressToCheck || !addressToCheck.includes('.')) {
|
if (!addressToCheck || !addressToCheck.includes('.')) {
|
||||||
alert(t('enter_crypto_address'));
|
alert(t('enter_crypto_address'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolveString = '';
|
setCryptoAddress(addressToCheck);
|
||||||
let resolveClass = '';
|
setCheckedAddress(addressToCheck);
|
||||||
|
|
||||||
if (state === 'failed') {
|
|
||||||
resolveString = error instanceof Error ? `failed to resolve crypto address, error: ${error.message}` : 'cannot resolve crypto address, unknown error';
|
|
||||||
resolveClass = styles.red;
|
|
||||||
} else if (state === 'resolving') {
|
|
||||||
resolveString = `resolving from ${chainProvider?.urls}`;
|
|
||||||
resolveClass = styles.yellow;
|
|
||||||
} else if (resolvedAddress && resolvedAddress === account?.signer?.address) {
|
|
||||||
resolveString = t('crypto_address_yours');
|
|
||||||
resolveClass = styles.green;
|
|
||||||
} else if (resolvedAddress && resolvedAddress !== account?.signer?.address) {
|
|
||||||
resolveString = t('crypto_address_not_yours');
|
|
||||||
resolveClass = styles.red;
|
|
||||||
} else {
|
|
||||||
resolveString = t('crypto_address_verification');
|
|
||||||
resolveClass = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setCryptoState((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
cryptoAddress: addressToCheck,
|
|
||||||
showResolvingMessage: true,
|
|
||||||
resolveString,
|
|
||||||
resolveClass,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveCryptoAddress = async () => {
|
const saveCryptoAddress = async () => {
|
||||||
if (!cryptoState.cryptoAddress || !cryptoState.cryptoAddress.includes('.')) {
|
const addressToSave = cryptoAddress.trim();
|
||||||
|
|
||||||
|
if (!addressToSave || !addressToSave.includes('.')) {
|
||||||
alert(t('enter_crypto_address'));
|
alert(t('enter_crypto_address'));
|
||||||
return;
|
return;
|
||||||
} else if (cryptoState.cryptoAddress === account?.author?.address) {
|
}
|
||||||
setSavedCryptoAddress(true);
|
|
||||||
setTimeout(() => {
|
if (addressToSave === account?.author?.address) {
|
||||||
setSavedCryptoAddress(false);
|
showSavedIndicator(setSavedCryptoAddress);
|
||||||
}, 2000);
|
|
||||||
return;
|
return;
|
||||||
} else if (resolvedAddress && resolvedAddress !== account?.signer?.address) {
|
}
|
||||||
alert(t('crypto_address_not_yours'));
|
|
||||||
return;
|
if (checkedAddress !== addressToSave || !resolvedAddress) {
|
||||||
} else if (cryptoState.cryptoAddress && !resolvedAddress) {
|
|
||||||
alert(t('crypto_address_not_resolved'));
|
alert(t('crypto_address_not_resolved'));
|
||||||
return;
|
return;
|
||||||
} else if (resolvedAddress && resolvedAddress === account?.signer?.address) {
|
}
|
||||||
|
|
||||||
|
if (resolvedAddress !== signerAddress) {
|
||||||
|
alert(t('crypto_address_not_yours'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await withErrorHandling(
|
const result = await withErrorHandling(
|
||||||
() => setAccount({ ...account, author: { ...account?.author, address: cryptoState.cryptoAddress } }),
|
() => setAccount({ ...account, author: { ...account?.author, address: addressToSave } }),
|
||||||
(error) => {
|
(publishError) => {
|
||||||
if (error instanceof Error) {
|
if (publishError instanceof Error) {
|
||||||
alert(error.message);
|
alert(publishError.message);
|
||||||
console.log(error);
|
console.log(publishError);
|
||||||
} else {
|
} else {
|
||||||
console.error('An unknown error occurred:', error);
|
console.error('An unknown error occurred:', publishError);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (result !== undefined) {
|
|
||||||
setShouldResolve(false);
|
|
||||||
setSavedCryptoAddress(true);
|
|
||||||
setTimeout(() => setSavedCryptoAddress(false), 2000);
|
|
||||||
setCryptoState((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
savedCryptoAddress: true,
|
|
||||||
cryptoAddress: '',
|
|
||||||
checkingCryptoAddress: false,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
setSavedCryptoAddress(true);
|
|
||||||
setCryptoState((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
checkingCryptoAddress: false,
|
|
||||||
showResolvingMessage: false,
|
|
||||||
resolveString: t('crypto_address_verification'),
|
|
||||||
resolveClass: '',
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const [showCryptoAddressInfo, setShowCryptoAddressInfo] = useState(false);
|
if (result === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCheckedAddress(undefined);
|
||||||
|
setCryptoAddress(addressToSave);
|
||||||
|
showSavedIndicator(setSavedCryptoAddress);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.setting}>
|
<div className={styles.setting}>
|
||||||
@@ -127,10 +166,10 @@ const CryptoAddressSetting = () => {
|
|||||||
<input
|
<input
|
||||||
type='text'
|
type='text'
|
||||||
placeholder='myaddress.bso'
|
placeholder='myaddress.bso'
|
||||||
value={cryptoState.cryptoAddress}
|
value={cryptoAddress}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setInputValue(e.target.value);
|
setCheckedAddress(undefined);
|
||||||
setCryptoState((prevState) => ({ ...prevState, cryptoAddress: e.target.value }));
|
setCryptoAddress(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button className={styles.saveButton} onClick={saveCryptoAddress}>
|
<button className={styles.saveButton} onClick={saveCryptoAddress}>
|
||||||
@@ -162,10 +201,17 @@ const CryptoAddressSetting = () => {
|
|||||||
<button className={styles.button} onClick={checkCryptoAddress}>
|
<button className={styles.button} onClick={checkCryptoAddress}>
|
||||||
{t('check')}
|
{t('check')}
|
||||||
</button>{' '}
|
</button>{' '}
|
||||||
<span className={cryptoState.resolveClass}>{cryptoState.resolveString}</span>
|
<span className={resolutionStatus.resolveClass}>{resolutionStatus.resolveString}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CryptoAddressSetting = () => {
|
||||||
|
const account = useAccount();
|
||||||
|
const accountResetKey = account?.id ?? account?.name ?? account?.signer?.address ?? account?.author?.address ?? 'default-account';
|
||||||
|
|
||||||
|
return <CryptoAddressSettingContent key={accountResetKey} account={account} />;
|
||||||
|
};
|
||||||
|
|
||||||
export default memo(CryptoAddressSetting);
|
export default memo(CryptoAddressSetting);
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks/dist/stores/feeds', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../use-directories', () => ({
|
vi.mock('../use-directories', () => ({
|
||||||
|
useDirectories: () => [],
|
||||||
useDirectoryByAddress: () => testState.community,
|
useDirectoryByAddress: () => testState.community,
|
||||||
|
findDirectoryByAddress: () => undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../use-board-feed-page-size', () => ({
|
vi.mock('../use-board-feed-page-size', () => ({
|
||||||
@@ -95,9 +97,9 @@ describe('usePostPageNumber', () => {
|
|||||||
|
|
||||||
expect(renderHook({ postCid: 'post-3', subplebbitAddress: 'music.eth' })).toBe(2);
|
expect(renderHook({ postCid: 'post-3', subplebbitAddress: 'music.eth' })).toBe(2);
|
||||||
expect(testState.preloadOptions).toEqual({
|
expect(testState.preloadOptions).toEqual({
|
||||||
|
communities: [{ name: 'music.eth' }],
|
||||||
postsPerPage: 20,
|
postsPerPage: 20,
|
||||||
sortType: 'active',
|
sortType: 'active',
|
||||||
communityAddresses: ['music.eth'],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,9 +108,9 @@ describe('usePostPageNumber', () => {
|
|||||||
|
|
||||||
expect(renderHook({ postCid: 'post-4', subplebbitAddress: 'music.eth' })).toBe(2);
|
expect(renderHook({ postCid: 'post-4', subplebbitAddress: 'music.eth' })).toBe(2);
|
||||||
expect(testState.preloadOptions).toEqual({
|
expect(testState.preloadOptions).toEqual({
|
||||||
|
communities: [{ name: 'music.eth' }],
|
||||||
postsPerPage: 20,
|
postsPerPage: 20,
|
||||||
sortType: 'active',
|
sortType: 'active',
|
||||||
communityAddresses: ['music.eth'],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
|||||||
|
|
||||||
vi.mock('../../../hooks/use-directories', () => ({
|
vi.mock('../../../hooks/use-directories', () => ({
|
||||||
useDirectories: () => testState.directories,
|
useDirectories: () => testState.directories,
|
||||||
|
findDirectoryByAddress: (directories: Array<{ address: string; title?: string; directoryCode?: string }>, address: string | undefined) =>
|
||||||
|
directories.find((entry) => entry.address === address || entry.directoryCode === address || entry.title === address),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../../hooks/use-resolved-subplebbit-address', () => ({
|
vi.mock('../../../hooks/use-resolved-subplebbit-address', () => ({
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ vi.mock('../../../hooks/use-directories', () => ({
|
|||||||
useDirectories: () => testState.directories,
|
useDirectories: () => testState.directories,
|
||||||
useDirectoryAddresses: () => testState.directories.map((entry) => entry.address),
|
useDirectoryAddresses: () => testState.directories.map((entry) => entry.address),
|
||||||
useDirectoryByAddress: (address: string | undefined) => (address ? testState.directoryByAddress[address] : undefined),
|
useDirectoryByAddress: (address: string | undefined) => (address ? testState.directoryByAddress[address] : undefined),
|
||||||
|
findDirectoryByAddress: (directories: Array<{ address: string; title?: string; directoryCode?: string }>, address: string | undefined) =>
|
||||||
|
directories.find((entry) => entry.address === address || entry.directoryCode === address || entry.title === address),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../../hooks/use-filtered-directory-addresses', () => ({
|
vi.mock('../../../hooks/use-filtered-directory-addresses', () => ({
|
||||||
|
|||||||
@@ -173,6 +173,8 @@ vi.mock('react-virtuoso', () => ({
|
|||||||
vi.mock('../../../hooks/use-directories', () => ({
|
vi.mock('../../../hooks/use-directories', () => ({
|
||||||
useDirectories: () => testState.directories,
|
useDirectories: () => testState.directories,
|
||||||
useDirectoryByAddress: (address: string | undefined) => (address ? testState.directoryByAddress[address] : undefined),
|
useDirectoryByAddress: (address: string | undefined) => (address ? testState.directoryByAddress[address] : undefined),
|
||||||
|
findDirectoryByAddress: (directories: Array<{ address: string; title?: string; directoryCode?: string }>, address: string | undefined) =>
|
||||||
|
directories.find((entry) => entry.address === address || entry.directoryCode === address || entry.title === address),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../../hooks/use-board-feed-page-size', () => ({
|
vi.mock('../../../hooks/use-board-feed-page-size', () => ({
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
|||||||
vi.mock('../../../hooks/use-directories', () => ({
|
vi.mock('../../../hooks/use-directories', () => ({
|
||||||
useDirectories: () => testState.directories,
|
useDirectories: () => testState.directories,
|
||||||
useDirectoryAddresses: () => testState.directoryAddresses,
|
useDirectoryAddresses: () => testState.directoryAddresses,
|
||||||
|
findDirectoryByAddress: (directories: Array<{ address: string; title?: string; directoryCode?: string }>, address: string | undefined) =>
|
||||||
|
directories.find((entry) => entry.address === address || entry.directoryCode === address || entry.title === address),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../../hooks/use-communities-stats', () => ({
|
vi.mock('../../../hooks/use-communities-stats', () => ({
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ vi.mock('react-router-dom', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
|
||||||
useCommunity: ({ communityAddress }: { communityAddress?: string }) => (communityAddress ? testState.communities[communityAddress] : undefined),
|
useCommunity: (options?: { communityAddress?: string; community?: { name?: string; publicKey?: string } }) => {
|
||||||
|
const communityAddress = options?.communityAddress ?? options?.community?.name ?? options?.community?.publicKey;
|
||||||
|
return communityAddress ? testState.communities[communityAddress] : undefined;
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../../hooks/use-directories', async () => {
|
vi.mock('../../../hooks/use-directories', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user