useServerDraft.test.tsx 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { StrictMode } from 'react';
  2. import { act, renderHook } from '@testing-library/react';
  3. import { describe, expect, it } from 'vitest';
  4. import { useServerDraft } from '@/hooks/useServerDraft';
  5. describe('useServerDraft', () => {
  6. it('keeps an edited draft when the server refetches', () => {
  7. const { result, rerender } = renderHook(
  8. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  9. { initialProps: { server: { value: 'one' } } },
  10. );
  11. act(() => result.current.setDraft({ value: 'edited' }));
  12. rerender({ server: { value: 'two' } });
  13. expect(result.current.draft).toEqual({ value: 'edited' });
  14. expect(result.current.isDirty).toBe(true);
  15. });
  16. it('accepts a refetch that matches the saved draft', () => {
  17. const { result, rerender } = renderHook(
  18. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  19. { initialProps: { server: { value: 'one' } } },
  20. );
  21. act(() => result.current.setDraft({ value: 'saved' }));
  22. rerender({ server: { value: 'saved' } });
  23. expect(result.current.draft).toEqual({ value: 'saved' });
  24. expect(result.current.isDirty).toBe(false);
  25. });
  26. it('compares a preserved draft with the latest server value', () => {
  27. const { result, rerender } = renderHook(
  28. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  29. { initialProps: { server: { value: 'one' } } },
  30. );
  31. act(() => result.current.setDraft({ value: 'later' }));
  32. rerender({ server: { value: 'saved' } });
  33. act(() => result.current.setDraft({ value: 'one' }));
  34. expect(result.current.isDirty).toBe(true);
  35. });
  36. it('hydrates clean drafts under StrictMode', () => {
  37. const { result, rerender } = renderHook(
  38. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  39. {
  40. initialProps: { server: { value: 'one' } },
  41. wrapper: StrictMode,
  42. },
  43. );
  44. rerender({ server: { value: 'two' } });
  45. expect(result.current.draft).toEqual({ value: 'two' });
  46. expect(result.current.isDirty).toBe(false);
  47. });
  48. it('preserves an edit made before the first server response', () => {
  49. const { result, rerender } = renderHook(
  50. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  51. { initialProps: { server: undefined as { value: string } | undefined } },
  52. );
  53. act(() => result.current.setDraft({ value: 'edited' }));
  54. rerender({ server: { value: 'one' } });
  55. expect(result.current.draft).toEqual({ value: 'edited' });
  56. expect(result.current.isDirty).toBe(true);
  57. });
  58. it('marks a sent draft clean before its refetch arrives', () => {
  59. const { result } = renderHook(
  60. ({ server }) => useServerDraft(server, (value) => ({ ...value }), (left, right) => left.value === right.value),
  61. { initialProps: { server: { value: 'one' } } },
  62. );
  63. act(() => result.current.setDraft({ value: 'saved' }));
  64. act(() => result.current.markSaved({ value: 'saved' }));
  65. expect(result.current.isDirty).toBe(false);
  66. });
  67. });