| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import type { ReactNode } from 'react';
- import { act, renderHook, waitFor } from '@testing-library/react';
- import { QueryClientProvider } from '@tanstack/react-query';
- import { afterEach, describe, expect, it, vi } from 'vitest';
- import { useAllSettings } from '@/api/queries/useAllSettings';
- import { keys } from '@/api/queryKeys';
- import { makeTestQueryClient } from '@/test/test-utils';
- import { HttpUtil, Msg } from '@/utils';
- afterEach(() => {
- vi.restoreAllMocks();
- });
- describe('useAllSettings', () => {
- it('refreshes cached default settings after a successful save', async () => {
- vi.spyOn(HttpUtil, 'post').mockResolvedValue(new Msg(true, '', {}));
- const queryClient = makeTestQueryClient();
- const fetchDefaults = vi
- .fn()
- .mockResolvedValueOnce({ subURI: 'https://example.com/sub/' })
- .mockResolvedValueOnce({ subURI: 'https://example.com/my_custom_path/' });
- const defaultsQuery = {
- queryKey: keys.settings.defaults(),
- queryFn: fetchDefaults,
- staleTime: Infinity,
- };
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- await queryClient.query(defaultsQuery);
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- await act(async () => {
- await result.current.saveAll();
- });
- const defaults = await queryClient.query(defaultsQuery);
- expect(fetchDefaults).toHaveBeenCalledTimes(2);
- expect(defaults.subURI).toBe('https://example.com/my_custom_path/');
- });
- it('keeps cached default settings when a save fails', async () => {
- vi.spyOn(HttpUtil, 'post').mockImplementation(async (url) => {
- if (url === '/panel/api/setting/update') return new Msg(false, 'Save failed');
- return new Msg(true, '', {});
- });
- const queryClient = makeTestQueryClient();
- const fetchDefaults = vi
- .fn()
- .mockResolvedValueOnce({ subURI: 'https://example.com/sub/' })
- .mockResolvedValueOnce({ subURI: 'https://example.com/my_custom_path/' });
- const defaultsQuery = {
- queryKey: keys.settings.defaults(),
- queryFn: fetchDefaults,
- staleTime: Infinity,
- };
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- await queryClient.query(defaultsQuery);
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- await act(async () => {
- await result.current.saveAll();
- });
- const defaults = await queryClient.query(defaultsQuery);
- expect(fetchDefaults).toHaveBeenCalledOnce();
- expect(defaults.subURI).toBe('https://example.com/sub/');
- });
- it('accepts legacy overlength regex settings without logging a response validation warning', async () => {
- const subJsonUserAgentRegex = 'x'.repeat(2_049);
- vi.spyOn(HttpUtil, 'post').mockResolvedValue(new Msg(true, '', { subJsonUserAgentRegex }));
- const warning = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
- const queryClient = makeTestQueryClient();
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- expect(result.current.allSetting.subJsonUserAgentRegex).toBe(subJsonUserAgentRegex);
- expect(warning).not.toHaveBeenCalled();
- });
- it('keeps an edited setting when a refetch returns older server data', async () => {
- const values = [{ webPort: 2053 }, { webPort: 2054 }];
- let index = 0;
- vi.spyOn(HttpUtil, 'post').mockImplementation(async () => new Msg(true, '', values[index++]));
- const queryClient = makeTestQueryClient();
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- act(() => result.current.updateSetting({ webPort: 3000 }));
- await queryClient.invalidateQueries({ queryKey: keys.settings.all() });
- await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(2));
- expect(result.current.allSetting.webPort).toBe(3000);
- expect(result.current.saveDisabled).toBe(false);
- });
- it('hydrates redacted secrets after a successful save', async () => {
- let fetchCount = 0;
- vi.spyOn(HttpUtil, 'post').mockImplementation(async (url) => {
- if (url === '/panel/api/setting/all') {
- fetchCount += 1;
- return new Msg(
- true,
- '',
- fetchCount === 1 ? { hasTgBotToken: false } : { hasTgBotToken: true, tgBotToken: '' },
- );
- }
- return new Msg(true, '');
- });
- const queryClient = makeTestQueryClient();
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- act(() => result.current.updateSetting({ tgBotToken: 'secret' }));
- await act(async () => {
- await result.current.saveAll();
- });
- await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(3));
- expect(result.current.allSetting.tgBotToken).toBe('');
- expect(result.current.allSetting.hasTgBotToken).toBe(true);
- expect(result.current.saveDisabled).toBe(true);
- });
- it('establishes a saved baseline for a full-payload security save', async () => {
- let fetchCount = 0;
- vi.spyOn(HttpUtil, 'post').mockImplementation(async (url) => {
- if (url === '/panel/api/setting/all') {
- fetchCount += 1;
- return new Msg(
- true,
- '',
- fetchCount === 1 ? { hasTgBotToken: false } : { hasTgBotToken: true, tgBotToken: '' },
- );
- }
- return new Msg(true, '');
- });
- const queryClient = makeTestQueryClient();
- const wrapper = ({ children }: { children: ReactNode }) => (
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- );
- const { result } = renderHook(() => useAllSettings(), { wrapper });
- await waitFor(() => expect(result.current.fetched).toBe(true));
- act(() => result.current.updateSetting({ tgBotToken: 'secret' }));
- await act(async () => {
- await result.current.savePayload({
- ...result.current.allSetting,
- twoFactorEnable: false,
- twoFactorToken: '',
- });
- });
- await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(3));
- expect(result.current.allSetting.tgBotToken).toBe('');
- expect(result.current.allSetting.hasTgBotToken).toBe(true);
- expect(result.current.saveDisabled).toBe(true);
- });
- });
|