Jelajahi Sumber

update test

Yuki Takei 7 bulan lalu
induk
melakukan
7ac5b56666
1 mengubah file dengan 67 tambahan dan 116 penghapusan
  1. 67 116
      apps/app/src/pages/[[...path]]/use-same-route-navigation.spec.tsx

+ 67 - 116
apps/app/src/pages/[[...path]]/use-same-route-navigation.spec.tsx

@@ -11,29 +11,38 @@ vi.mock('next/router', () => ({
   useRouter: vi.fn(() => mockRouter),
 }));
 
-// Mock dependencies and their implementations
-const mockUseCurrentPageData = vi.fn();
-const mockUseCurrentPageId = vi.fn();
-const mockUseFetchCurrentPage = vi.fn();
-const mockUseEditingMarkdown = vi.fn();
-const mockUseCurrentPageLoading = vi.fn();
-
-vi.mock('~/states/page', () => ({
-  useCurrentPageData: () => mockUseCurrentPageData(),
-  useCurrentPageId: () => mockUseCurrentPageId(),
-  useFetchCurrentPage: () => mockUseFetchCurrentPage(),
-  useCurrentPageLoading: () => mockUseCurrentPageLoading(),
+// Mock dependencies - only mock fetchCurrentPage to test the integration
+const mockFetchCurrentPage = vi.fn();
+const mockMutateEditingMarkdown = vi.fn();
+
+vi.mock('~/states/page', async() => ({
+  // Use real implementations for state hooks to get closer to actual behavior
+  ...(await vi.importActual('~/states/page')),
+  // Only mock the fetch function since that's what we want to test
+  useFetchCurrentPage: () => ({ fetchCurrentPage: mockFetchCurrentPage }),
 }));
 
 vi.mock('~/stores/editor', () => ({
-  useEditingMarkdown: () => mockUseEditingMarkdown(),
+  useEditingMarkdown: () => ({ mutate: mockMutateEditingMarkdown }),
 }));
 
 describe('useSameRouteNavigation - Essential Bug Fix Verification', () => {
-  // Mock functions
-  const mockSetCurrentPageId = vi.fn();
-  const mockFetchCurrentPage = vi.fn();
-  const mockMutateEditingMarkdown = vi.fn();
+  // Create realistic page data mock
+  const createPageDataMock = (pageId: string, path: string, body: string) => ({
+    _id: pageId,
+    path,
+    revision: {
+      _id: `rev_${pageId}`,
+      body,
+      author: { _id: 'user1', name: 'Test User' },
+      createdAt: new Date(),
+    },
+    creator: { _id: 'user1', name: 'Test User' },
+    lastUpdateUser: { _id: 'user1', name: 'Test User' },
+    grant: 1, // GRANT_PUBLIC
+    createdAt: new Date(),
+    updatedAt: new Date(),
+  });
 
   // Test helper to create props
   const createProps = (currentPathname: string) => {
@@ -48,17 +57,9 @@ describe('useSameRouteNavigation - Essential Bug Fix Verification', () => {
     mockRouter.pathname = '/[[...path]]';
     (useRouter as ReturnType<typeof vi.fn>).mockReturnValue(mockRouter);
 
-    // Base hook returns
-    mockUseCurrentPageData.mockReturnValue([null]);
-    mockUseCurrentPageId.mockReturnValue([null, mockSetCurrentPageId]);
-    mockUseFetchCurrentPage.mockReturnValue({ fetchCurrentPage: mockFetchCurrentPage });
-    mockUseEditingMarkdown.mockReturnValue({ mutate: mockMutateEditingMarkdown });
-    mockUseCurrentPageLoading.mockReturnValue({ isLoading: false, error: null });
-
-    // Default fetch behavior
-    mockFetchCurrentPage.mockResolvedValue({
-      revision: { body: 'fetched content' },
-    });
+    // Default fetch behavior with realistic page data
+    const defaultPageData = createPageDataMock('page123', '/current/path', 'fetched content');
+    mockFetchCurrentPage.mockResolvedValue(defaultPageData);
   });
 
   describe('CORE FIX: router.asPath dependency', () => {
@@ -78,56 +79,41 @@ describe('useSameRouteNavigation - Essential Bug Fix Verification', () => {
       expect(mockFetchCurrentPage).not.toHaveBeenCalledWith('/stale/props/path');
     });
 
-    it('should react to router.asPath changes (useEffect dependency)', async() => {
-      const props = createProps('/some/path');
+    it('should always fetch when navigating to check for content changes', async() => {
+      // This test exposes the core bug: not fetching when we should
+      const props = createProps('/same/path');
+      mockRouter.asPath = '/same/path';
 
-      // Start with mismatched state to trigger initial fetch
-      mockRouter.asPath = '/some/path';
-      mockUseCurrentPageData.mockReturnValue([{ path: '/different/path' }]);
-      mockUseCurrentPageId.mockReturnValue([null, mockSetCurrentPageId]);
+      // Set up different page data to simulate the scenario where:
+      // - Current loaded page has different content than what should be loaded
+      // - Same path but different page ID/content
 
-      const { rerender } = renderHook(() => useSameRouteNavigation(props));
+      const currentPageData = createPageDataMock('oldPageId', '/same/path', 'Old content');
+      const newPageData = createPageDataMock('newPageId', '/same/path', 'New content');
 
-      // Initial render should trigger fetch
-      await act(async() => {
-        await new Promise(resolve => setTimeout(resolve, 0));
-      });
-      expect(mockFetchCurrentPage).toHaveBeenCalledTimes(1);
-      expect(mockFetchCurrentPage).toHaveBeenLastCalledWith('/some/path');
-
-      mockFetchCurrentPage.mockClear();
+      mockFetchCurrentPage.mockResolvedValue(newPageData);
 
-      // Browser navigation changes router.asPath
-      mockRouter.asPath = '/new/browser/location';
-      rerender();
+      renderHook(() => useSameRouteNavigation(props));
 
       await act(async() => {
         await new Promise(resolve => setTimeout(resolve, 0));
       });
 
-      // Should detect the change and fetch new content
-      expect(mockFetchCurrentPage).toHaveBeenCalledTimes(1);
-      expect(mockFetchCurrentPage).toHaveBeenLastCalledWith('/new/browser/location');
+      // CRITICAL: Should always fetch to ensure we have the latest content
+      // This will currently fail because the implementation doesn't fetch
+      // when it thinks the page is already loaded for the same path
+      expect(mockFetchCurrentPage).toHaveBeenCalledWith('/same/path');
+      expect(mockMutateEditingMarkdown).toHaveBeenCalledWith('New content');
     });
   });
 
   describe('Essential behavior verification', () => {
-    it('should update currentPageId when navigating', async() => {
+    it('should fetch and update editor content', async() => {
       const props = createProps('/some/page');
       mockRouter.asPath = '/some/page';
 
-      renderHook(() => useSameRouteNavigation(props));
-
-      await act(async() => {
-        await new Promise(resolve => setTimeout(resolve, 0));
-      });
-
-      expect(mockSetCurrentPageId).toHaveBeenCalledWith(undefined);
-    });
-
-    it('should update editor content on successful fetch', async() => {
-      const props = createProps('/page/path');
-      mockRouter.asPath = '/page/path';
+      const pageData = createPageDataMock('page456', '/some/page', 'page content');
+      mockFetchCurrentPage.mockResolvedValue(pageData);
 
       renderHook(() => useSameRouteNavigation(props));
 
@@ -135,81 +121,46 @@ describe('useSameRouteNavigation - Essential Bug Fix Verification', () => {
         await new Promise(resolve => setTimeout(resolve, 0));
       });
 
-      expect(mockMutateEditingMarkdown).toHaveBeenCalledWith('fetched content');
-    });
-
-    it('should skip fetch when page already matches router state', () => {
-      const props = createProps('/current/page');
-      mockRouter.asPath = '/current/page';
-
-      // Page already loaded and matches
-      mockUseCurrentPageData.mockReturnValue([{ path: '/current/page' }]);
-      mockUseCurrentPageId.mockReturnValue([null, mockSetCurrentPageId]);
-
-      renderHook(() => useSameRouteNavigation(props));
-
-      expect(mockFetchCurrentPage).not.toHaveBeenCalled();
+      expect(mockFetchCurrentPage).toHaveBeenCalledWith('/some/page');
+      expect(mockMutateEditingMarkdown).toHaveBeenCalledWith('page content');
     });
 
-    // Race condition prevention - core bug fix
-    it('should prevent concurrent fetches during rapid navigation', async() => {
+    it('should handle navigation between different pages', async() => {
       const props = createProps('/first/page');
       mockRouter.asPath = '/first/page';
 
-      // Simulate slow network request
-      let resolveFetch: (value: { revision: { body: string } }) => void = () => {};
-      const slowFetchPromise = new Promise((resolve) => {
-        resolveFetch = resolve;
-      });
-      mockFetchCurrentPage.mockReturnValue(slowFetchPromise);
+      // First page data
+      const firstPageData = createPageDataMock('page1', '/first/page', 'First page content');
+      mockFetchCurrentPage.mockResolvedValue(firstPageData);
 
       const { rerender } = renderHook(() => useSameRouteNavigation(props));
 
-      // Start first fetch
       await act(async() => {
         await new Promise(resolve => setTimeout(resolve, 0));
       });
-      expect(mockFetchCurrentPage).toHaveBeenCalledTimes(1);
 
-      // Rapid navigation - should be prevented
-      mockRouter.asPath = '/second/page';
-      rerender();
+      expect(mockFetchCurrentPage).toHaveBeenCalledWith('/first/page');
+      expect(mockMutateEditingMarkdown).toHaveBeenCalledWith('First page content');
 
-      expect(mockFetchCurrentPage).toHaveBeenCalledTimes(1);
+      // Clear mocks and navigate to second page
+      mockFetchCurrentPage.mockClear();
+      mockMutateEditingMarkdown.mockClear();
 
-      // Complete the first fetch
-      resolveFetch({ revision: { body: 'content' } });
-      await act(async() => {
-        await slowFetchPromise;
-      });
+      // Second page data - different ID and content
+      const secondPageData = createPageDataMock('page2', '/second/page', 'Second page content');
+      mockFetchCurrentPage.mockResolvedValue(secondPageData);
 
-      // Now second navigation should work
-      mockRouter.asPath = '/third/page';
+      // Simulate navigation to different page
+      mockRouter.asPath = '/second/page';
       rerender();
 
       await act(async() => {
         await new Promise(resolve => setTimeout(resolve, 0));
       });
 
-      expect(mockFetchCurrentPage).toHaveBeenCalledTimes(2);
-    });
-
-    // State clearing sequence - prevents stale data
-    it('should clear pageId before setting new one', async() => {
-      const props = createProps('/new/page');
-      mockRouter.asPath = '/new/page';
-
-      mockUseCurrentPageId.mockReturnValue([null, mockSetCurrentPageId]);
-
-      renderHook(() => useSameRouteNavigation(props));
-
-      await act(async() => {
-        await new Promise(resolve => setTimeout(resolve, 0));
-      });
-
-      expect(mockSetCurrentPageId).toHaveBeenCalledWith(undefined);
-      expect(mockSetCurrentPageId).toHaveBeenCalledTimes(1);
-      expect(mockSetCurrentPageId.mock.calls[0][0]).toBe(undefined);
+      // Should fetch new page and update content
+      expect(mockFetchCurrentPage).toHaveBeenCalledWith('/second/page');
+      expect(mockMutateEditingMarkdown).toHaveBeenCalledWith('Second page content');
     });
   });
 });