use-all-settings.test.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import type { ReactNode } from 'react';
  2. import { act, renderHook, waitFor } from '@testing-library/react';
  3. import { QueryClientProvider } from '@tanstack/react-query';
  4. import { afterEach, describe, expect, it, vi } from 'vitest';
  5. import { useAllSettings } from '@/api/queries/useAllSettings';
  6. import { keys } from '@/api/queryKeys';
  7. import { makeTestQueryClient } from '@/test/test-utils';
  8. import { HttpUtil, Msg } from '@/utils';
  9. afterEach(() => {
  10. vi.restoreAllMocks();
  11. });
  12. describe('useAllSettings', () => {
  13. it('accepts legacy overlength regex settings without logging a response validation warning', async () => {
  14. const subJsonUserAgentRegex = 'x'.repeat(2_049);
  15. vi.spyOn(HttpUtil, 'post').mockResolvedValue(new Msg(true, '', { subJsonUserAgentRegex }));
  16. const warning = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
  17. const queryClient = makeTestQueryClient();
  18. const wrapper = ({ children }: { children: ReactNode }) => (
  19. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  20. );
  21. const { result } = renderHook(() => useAllSettings(), { wrapper });
  22. await waitFor(() => expect(result.current.fetched).toBe(true));
  23. expect(result.current.allSetting.subJsonUserAgentRegex).toBe(subJsonUserAgentRegex);
  24. expect(warning).not.toHaveBeenCalled();
  25. });
  26. it('keeps an edited setting when a refetch returns older server data', async () => {
  27. const values = [
  28. { webPort: 2053 },
  29. { webPort: 2054 },
  30. ];
  31. let index = 0;
  32. vi.spyOn(HttpUtil, 'post').mockImplementation(async () => new Msg(true, '', values[index++]));
  33. const queryClient = makeTestQueryClient();
  34. const wrapper = ({ children }: { children: ReactNode }) => (
  35. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  36. );
  37. const { result } = renderHook(() => useAllSettings(), { wrapper });
  38. await waitFor(() => expect(result.current.fetched).toBe(true));
  39. act(() => result.current.updateSetting({ webPort: 3000 }));
  40. await queryClient.invalidateQueries({ queryKey: keys.settings.all() });
  41. await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(2));
  42. expect(result.current.allSetting.webPort).toBe(3000);
  43. expect(result.current.saveDisabled).toBe(false);
  44. });
  45. it('hydrates redacted secrets after a successful save', async () => {
  46. let fetchCount = 0;
  47. vi.spyOn(HttpUtil, 'post').mockImplementation(async (url) => {
  48. if (url === '/panel/api/setting/all') {
  49. fetchCount += 1;
  50. return new Msg(true, '', fetchCount === 1 ? { hasTgBotToken: false } : { hasTgBotToken: true, tgBotToken: '' });
  51. }
  52. return new Msg(true, '');
  53. });
  54. const queryClient = makeTestQueryClient();
  55. const wrapper = ({ children }: { children: ReactNode }) => (
  56. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  57. );
  58. const { result } = renderHook(() => useAllSettings(), { wrapper });
  59. await waitFor(() => expect(result.current.fetched).toBe(true));
  60. act(() => result.current.updateSetting({ tgBotToken: 'secret' }));
  61. await act(async () => {
  62. await result.current.saveAll();
  63. });
  64. await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(3));
  65. expect(result.current.allSetting.tgBotToken).toBe('');
  66. expect(result.current.allSetting.hasTgBotToken).toBe(true);
  67. expect(result.current.saveDisabled).toBe(true);
  68. });
  69. it('establishes a saved baseline for a full-payload security save', async () => {
  70. let fetchCount = 0;
  71. vi.spyOn(HttpUtil, 'post').mockImplementation(async (url) => {
  72. if (url === '/panel/api/setting/all') {
  73. fetchCount += 1;
  74. return new Msg(true, '', fetchCount === 1 ? { hasTgBotToken: false } : { hasTgBotToken: true, tgBotToken: '' });
  75. }
  76. return new Msg(true, '');
  77. });
  78. const queryClient = makeTestQueryClient();
  79. const wrapper = ({ children }: { children: ReactNode }) => (
  80. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  81. );
  82. const { result } = renderHook(() => useAllSettings(), { wrapper });
  83. await waitFor(() => expect(result.current.fetched).toBe(true));
  84. act(() => result.current.updateSetting({ tgBotToken: 'secret' }));
  85. await act(async () => {
  86. await result.current.savePayload({ ...result.current.allSetting, twoFactorEnable: false, twoFactorToken: '' });
  87. });
  88. await waitFor(() => expect(HttpUtil.post).toHaveBeenCalledTimes(3));
  89. expect(result.current.allSetting.tgBotToken).toBe('');
  90. expect(result.current.allSetting.hasTgBotToken).toBe(true);
  91. expect(result.current.saveDisabled).toBe(true);
  92. });
  93. });