next.js/test/e2e/app-dir/interception-dynamic-single-segment/interception-dynamic-single-segment.test.ts
interception-dynamic-single-segment.test.ts303 lines11.5 KB
import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'

describe('interception-dynamic-single-segment', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should intercept from nested route to deeper nested route with (.) modifier', async () => {
    // This test covers the bug fix for same-level (.) interception
    // where navigation from a nested route (e.g., /groups/123) to a deeper route
    // (e.g., /groups/123/new) should trigger the modal interception.
    //
    // The bug was that the regex pattern used [^/]+ which only matched single segments,
    // so interception failed when the source route had multiple segments like /groups/123
    const browser = await next.browser('/groups/123')

    // Verify we're on the group page
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Group 123')
      expect(text).toContain('New Item')
    })

    // Navigate from /groups/123 to /groups/123/new
    // This should trigger the modal interception
    await browser.elementById('new-link').click()

    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain('Modal: New item for group 123')
    })

    // The children should still show the group page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Group 123')
    })

    // Refresh to verify the full page renders (not intercepted)
    await browser.refresh()
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('New item for group 123')
    })
  })

  it('should intercept from deeply nested route (4 segments) with (.) modifier', async () => {
    // This test covers deeply nested routes with multiple dynamic segments
    // Source: /org/acme/team/engineering (4 segments, 2 dynamic)
    // Target: /org/acme/team/engineering/settings (5 segments)
    //
    // This ensures the regex fix (.+) handles very deep nesting correctly
    const browser = await next.browser('/org/acme/team/engineering')

    // Verify we're on the team page
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Team engineering in Org acme')
      expect(text).toContain('Settings')
    })

    // Navigate from /org/acme/team/engineering to /org/acme/team/engineering/settings
    // This should trigger the modal interception
    await browser.elementById('settings-link').click()

    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain(
        'Modal: Settings for Team engineering in Org acme'
      )
    })

    // The children should still show the team page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Team engineering in Org acme')
    })

    // Refresh to verify the full page renders (not intercepted)
    await browser.refresh()
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain(
        'Settings for Team engineering in Org acme'
      )
    })
  })

  it('should intercept with programmatic navigation using router.push', async () => {
    // Test that interception works with programmatic navigation, not just Link clicks
    // This ensures the NEXT_URL header is set correctly in all navigation scenarios
    const browser = await next.browser('/groups/123')

    // Verify we're on the group page
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Group 123')
    })

    // Use router.push to navigate programmatically
    await browser.eval('window.next.router.push("/groups/123/new")')

    // Should trigger the modal interception
    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain('Modal: New item for group')
    })

    // The children should still show the group page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Group 123')
    })
  })

  it('should intercept from nested route with query parameters', async () => {
    // Test that interception works when the source route has query parameters
    // The query params should not interfere with route matching
    const browser = await next.browser('/groups/123?tab=settings&view=grid')

    // Verify we're on the group page with query params
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Group 123')
      expect(text).toContain('New Item')
    })

    // Navigate to /groups/123/new (query params in source shouldn't affect interception)
    await browser.elementById('new-link').click()

    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain('Modal: New item for group')
    })

    // The children should still show the group page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Group 123')
    })
  })

  it('should intercept with consecutive dynamic segments', async () => {
    // Test that interception works with consecutive dynamic segments [a]/[b]/[c]
    // This is an edge case where there are no static segments between dynamics
    // Source: /x/y/z (3 consecutive dynamic segments)
    // Target: /x/y/z/item
    const browser = await next.browser('/x/y/z')

    // Verify we're on the consecutive dynamic page
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Path: x/y/z')
      expect(text).toContain('View Item')
    })

    // Navigate to /x/y/z/item
    await browser.elementById('item-link').click()

    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain('Modal: Item for path x/y/z')
    })

    // The children should still show the consecutive page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Path: x/y/z')
    })

    // Refresh to verify the full page renders (not intercepted)
    await browser.refresh()
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Item for path: x/y/z')
    })
  })

  it('should intercept with purely static multi-segment paths', async () => {
    // Test that interception works with static (non-dynamic) multi-segment paths
    // This ensures the fix doesn't break static route interception
    // Source: /admin/dashboard/users (3 static segments)
    // Target: /admin/dashboard/users/new (4 static segments)
    const browser = await next.browser('/admin/dashboard/users')

    // Verify we're on the users page
    await retry(async () => {
      const text = await browser.elementByCss('body').text()
      expect(text).toContain('Admin Dashboard - Users')
      expect(text).toContain('New User')
    })

    // Navigate to /admin/dashboard/users/new
    await browser.elementById('new-user-link').click()

    await retry(async () => {
      const modalText = await browser.elementById('modal').text()
      expect(modalText).toContain('Modal: New User Form')
    })

    // The children should still show the users page
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('Admin Dashboard - Users')
    })

    // Refresh to verify the full page renders (not intercepted)
    await browser.refresh()
    await retry(async () => {
      const childrenText = await browser.elementById('children').text()
      expect(childrenText).toContain('New User Form')
    })
  })

  describe('nested navigation - descendants of intercepting route', () => {
    // These tests verify the key bug fix: the regex pattern now matches
    // all descendants of the intercepting route level, not just the exact level.
    // Previously, navigation FROM a nested route (e.g., /groups/123/nested) would
    // fail to trigger interception. Now it should work from any depth.
    // NOTE: These are conceptual tests - actual nested pages would need to be created
    // in the app directory structure to fully test this behavior in a real app.

    it('should intercept when navigating from a child route using back navigation', async () => {
      // Start at /groups/123, navigate to /groups/123/new (intercepted),
      // then navigate away and back
      const browser = await next.browser('/groups/123')

      await retry(async () => {
        const text = await browser.elementByCss('body').text()
        expect(text).toContain('Group 123')
      })

      // First navigation - should intercept
      await browser.elementById('new-link').click()
      await retry(async () => {
        const modalText = await browser.elementById('modal').text()
        expect(modalText).toContain('Modal: New item for group')
      })

      // Navigate back
      await browser.back()
      await retry(async () => {
        const text = await browser.elementByCss('body').text()
        expect(text).toContain('Group 123')
      })

      // Navigate forward again - should still intercept
      await browser.forward()
      await retry(async () => {
        const modalText = await browser.elementById('modal').text()
        expect(modalText).toContain('Modal: New item for group')
      })
    })

    it('should intercept multiple times from the same route', async () => {
      // Test that interception works consistently on repeated navigation
      const browser = await next.browser('/groups/456')

      for (let i = 0; i < 3; i++) {
        await browser.elementById('new-link').click()
        await retry(async () => {
          const modalText = await browser.elementById('modal').text()
          expect(modalText).toContain('Modal: New item for group 456')
        })

        // Go back to test again
        await browser.back()
        await retry(async () => {
          const text = await browser.elementByCss('body').text()
          expect(text).toContain('Group 456')
        })
      }
    })

    it('should intercept when navigating between different dynamic segments', async () => {
      // Test interception works across different dynamic route values
      // First group
      const browser1 = await next.browser('/groups/100')

      await browser1.elementById('new-link').click()
      await retry(async () => {
        const modalText = await browser1.elementById('modal').text()
        expect(modalText).toContain('Modal: New item for group 100')
      })

      // Second group - new browser instance to test fresh navigation
      const browser2 = await next.browser('/groups/200')
      await retry(async () => {
        const text = await browser2.elementByCss('body').text()
        expect(text).toContain('Group 200')
      })

      // Intercept from second group - should still work
      await browser2.elementById('new-link').click()
      await retry(async () => {
        const modalText = await browser2.elementById('modal').text()
        expect(modalText).toContain('Modal: New item for group 200')
      })
    })
  })
})
Quest for Codev2.0.0
/
SIGN IN