Repository: vercel/next.js
Pull request: [test] improve segment explorer tests snapshot

Format line format: `<segment> [<files,>]`

This will help visualize the rendered segment explorer panel easier by checking the snapshot. e.g.

```
app/ [layout.tsx]
parallel-routes/ [layout.tsx, page.tsx]
@bar/ [layout.tsx, page.tsx]
@foo/ [layout.tsx, page.tsx]
```     

Changed files:
filename: test/development/app-dir/segment-explorer-globals/segment-explorer-globals.test.ts
patch: @@ -1,22 +1,5 @@
 import { nextTestSetup } from 'e2e-utils'
-import { openDevToolsIndicatorPopover } from 'next-test-utils'
-import { Playwright } from 'next-webdriver'
-
-async function getSegmentExplorerContent(browser: Playwright) {
-  // open the devtool button
-  await openDevToolsIndicatorPopover(browser)
-
-  // open the segment explorer
-  await browser.elementByCss('[data-segment-explorer]').click()
-
-  //  wait for the segment explorer to be visible
-  await browser.waitForElementByCss('[data-nextjs-devtool-segment-explorer]')
-
-  const content = await browser.elementByCss(
-    '[data-nextjs-devtool-segment-explorer]'
-  )
-  return content.text()
-}
+import { getSegmentExplorerContent } from 'next-test-utils'
 
 describe('segment-explorer - globals', () => {
   const { next } = nextTestSetup({
@@ -25,17 +8,15 @@ describe('segment-explorer - globals', () => {
 
   it('should show global-error segment', async () => {
     const browser = await next.browser('/runtime-error')
-    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     global-error.tsx"
-    `)
+    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(
+      `"app/ [global-error.tsx]"`
+    )
   })
 
   it('should display parallel routes default page when present', async () => {
     const browser = await next.browser('/404-not-found')
-    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     global-not-found.tsx"
-    `)
+    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(
+      `"app/ [global-not-found.tsx]"`
+    )
   })
 })

filename: test/development/app-dir/segment-explorer/segment-explorer.test.ts
patch: @@ -1,22 +1,5 @@
 import { nextTestSetup } from 'e2e-utils'
-import { openDevToolsIndicatorPopover, retry } from 'next-test-utils'
-import { Playwright } from 'next-webdriver'
-
-async function getSegmentExplorerContent(browser: Playwright) {
-  // open the devtool button
-  await openDevToolsIndicatorPopover(browser)
-
-  // open the segment explorer
-  await browser.elementByCss('[data-segment-explorer]').click()
-
-  //  wait for the segment explorer to be visible
-  await browser.waitForElementByCss('[data-nextjs-devtool-segment-explorer]')
-
-  const content = await browser.elementByCss(
-    '[data-nextjs-devtool-segment-explorer]'
-  )
-  return content.text()
-}
+import { getSegmentExplorerContent, retry } from 'next-test-utils'
 
 describe('segment-explorer', () => {
   const { next } = nextTestSetup({
@@ -26,61 +9,39 @@ describe('segment-explorer', () => {
   it('should render the segment explorer for parallel routes', async () => {
     const browser = await next.browser('/parallel-routes')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     parallel-routes/
-     layout.tsx
-     page.tsx
-     @bar/
-     layout.tsx
-     page.tsx
-     @foo/
-     layout.tsx
-     page.tsx"
+     "app/ [layout.tsx]
+     parallel-routes/ [layout.tsx, page.tsx]
+     @bar/ [layout.tsx, page.tsx]
+     @foo/ [layout.tsx, page.tsx]"
     `)
   })
 
   it('should render the segment explorer for parallel routes in edge runtime', async () => {
     const browser = await next.browser('/parallel-routes-edge')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     parallel-routes-edge/
-     layout.tsx
-     page.tsx
-     @bar/
-     layout.tsx
-     page.tsx
-     @foo/
-     layout.tsx
-     page.tsx"
+     "app/ [layout.tsx]
+     parallel-routes-edge/ [layout.tsx, page.tsx]
+     @bar/ [layout.tsx, page.tsx]
+     @foo/ [layout.tsx, page.tsx]"
     `)
   })
 
   it('should render the segment explorer for nested routes', async () => {
     const browser = await next.browser('/blog/~/grid')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     (v2)/
-     layout.tsx
-     blog / (team)/
-     layout.tsx
-     template.tsx
-     ~ / (overview)/
-     layout.tsx
-     grid/
-     page.tsx"
+     "app/ [layout.tsx]
+     (v2)/ [layout.tsx]
+     blog / (team)/ [layout.tsx, template.tsx]
+     ~ / (overview)/ [layout.tsx]
+     grid/ [page.tsx]"
     `)
   })
 
   it('should cleanup on soft navigation', async () => {
     const browser = await next.browser('/soft-navigation/a')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     soft-navigation / a/
-     page.tsx"
+     "app/ [layout.tsx]
+     soft-navigation / a/ [page.tsx]"
     `)
 
     await browser.elementByCss('[href="/soft-navigation/b"]').click()
@@ -89,75 +50,55 @@ describe('segment-explorer', () => {
     })
 
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     soft-navigation / b/
-     page.tsx"
+     "app/ [layout.tsx]
+     soft-navigation / b/ [page.tsx]"
     `)
   })
 
   it('should handle show file segments in order', async () => {
     const browser = await next.browser('/file-segments')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     (all) / file-segments/
-     layout.tsx
-     template.tsx
-     page.tsx"
+     "app/ [layout.tsx]
+     (all) / file-segments/ [layout.tsx, template.tsx, page.tsx]"
     `)
   })
 
   it('should indicate segment explorer is not available for pages router', async () => {
     const browser = await next.browser('/pages-router')
-    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(
-      `"Route Info currently is only available for the App Router."`
-    )
+    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`""`)
   })
 
   it('should handle special built-in not-found segments', async () => {
     const browser = await next.browser('/404')
-    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     not-found.js"
-    `)
+    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(
+      `"app/ [layout.tsx, not-found.js]"`
+    )
   })
 
   it('should show global-error segment', async () => {
     const browser = await next.browser('/runtime-error')
-    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     global-error.js"
-    `)
+    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(
+      `"app/ [global-error.js]"`
+    )
   })
 
   it('should show navigation boundaries of the segment', async () => {
     const browser = await next.browser('/boundary?name=not-found')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     boundary/
-     layout.tsx
-     not-found.tsx"
+     "app/ [layout.tsx]
+     boundary/ [layout.tsx, not-found.tsx]"
     `)
 
     await browser.loadPage(`${next.url}/boundary?name=forbidden`)
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     boundary/
-     layout.tsx
-     forbidden.tsx"
+     "app/ [layout.tsx]
+     boundary/ [layout.tsx, forbidden.tsx]"
     `)
 
     await browser.loadPage(`${next.url}/boundary?name=unauthorized`)
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     boundary/
-     layout.tsx
-     unauthorized.tsx"
+     "app/ [layout.tsx]
+     boundary/ [layout.tsx, unauthorized.tsx]"
     `)
   })
 
@@ -172,52 +113,37 @@ describe('segment-explorer', () => {
     })
 
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     search/
-     layout.tsx
-     loading.tsx"
+     "app/ [layout.tsx]
+     search/ [layout.tsx, loading.tsx]"
     `)
   })
 
   it('should show the custom error boundary when present', async () => {
     const browser = await next.browser('/runtime-error/boundary')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     runtime-error / boundary/
-     error.tsx"
+     "app/ [layout.tsx]
+     runtime-error / boundary/ [error.tsx]"
     `)
   })
 
   it('should display parallel routes default page when present', async () => {
     const browser = await next.browser('/parallel-default/subroute')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     parallel-default/
-     layout.tsx
-     default.tsx
-     @bar/
-     layout.tsx
-     subroute/
-     page.tsx
-     @foo/
-     default.tsx"
+     "app/ [layout.tsx]
+     parallel-default/ [layout.tsx, default.tsx]
+     @bar/ [layout.tsx]
+     subroute/ [page.tsx]
+     @foo/ [default.tsx]"
     `)
   })
 
   it('should display boundary selector when a segment has only boundary files', async () => {
     const browser = await next.browser('/no-layout/framework/blog')
     expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
-     "app/
-     layout.tsx
-     no-layout/
-     framework/
-     layout.tsx
-     blog/
-     layout.tsx
-     page.tsx"
+     "app/ [layout.tsx]
+     no-layout/ []
+     framework/ [layout.tsx]
+     blog/ [layout.tsx, page.tsx]"
     `)
   })
 })

filename: test/lib/next-test-utils.ts
patch: @@ -962,6 +962,36 @@ export async function openDevToolsIndicatorPopover(
   }
 }
 
+export async function getSegmentExplorerContent(browser: Playwright) {
+  // open the devtool button
+  await openDevToolsIndicatorPopover(browser)
+
+  // open the segment explorer
+  await browser.elementByCss('[data-segment-explorer]').click()
+
+  //  wait for the segment explorer to be visible
+  await browser.waitForElementByCss('[data-nextjs-devtool-segment-explorer]')
+
+  const rows = await browser.elementsByCss('.segment-explorer-item')
+  let result: string[] = []
+  for (const row of rows) {
+    // query filename of row: segment-explorer-filename
+    const segment = (
+      (await (await row.$('.segment-explorer-filename--path'))?.innerText()) ||
+      ''
+    ).trim()
+    const files = (
+      (await (await row.$('.segment-explorer-files'))?.innerText()) || ''
+    )
+      .split(/\n+/)
+      .map((file) => file.trim())
+
+    // line format: segment [files]
+    result.push(`${segment} [${files.join(', ')}]`)
+  }
+  return result.join('\n')
+}
+
 export async function hasDevToolsPanel(browser: Playwright) {
   const result = await browser.eval(() => {
     const portal = document.querySelector('nextjs-portal')