rsnext/test/e2e/root-dir/index.test.ts

266 lines
9.7 KiB
TypeScript
Raw Normal View History

import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { fetchViaHTTP, renderViaHTTP } from 'next-test-utils'
import path from 'path'
import cheerio from 'cheerio'
import webdriver from 'next-webdriver'
describe('root dir', () => {
let next: NextInstance
beforeAll(async () => {
next = await createNext({
files: {
public: new FileRef(path.join(__dirname, 'app/public')),
pages: new FileRef(path.join(__dirname, 'app/pages')),
root: new FileRef(path.join(__dirname, 'app/root')),
'root.server.js': new FileRef(
path.join(__dirname, 'app/root.server.js')
),
'next.config.js': new FileRef(
path.join(__dirname, 'app/next.config.js')
),
},
dependencies: {
react: '18.0.0-rc.2',
'react-dom': '18.0.0-rc.2',
},
})
})
afterAll(() => next.destroy())
it('should serve from pages', async () => {
const html = await renderViaHTTP(next.url, '/')
expect(html).toContain('hello from pages/index')
})
it('should serve dynamic route from pages', async () => {
const html = await renderViaHTTP(next.url, '/blog/first')
expect(html).toContain('hello from pages/blog/[slug]')
})
it('should serve from public', async () => {
const html = await renderViaHTTP(next.url, '/hello.txt')
expect(html).toContain('hello world')
})
it('should serve from root', async () => {
const html = await renderViaHTTP(next.url, '/dashboard')
expect(html).toContain('hello from root/dashboard')
})
it('should include layouts when no direct parent layout', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/integrations')
const $ = cheerio.load(html)
// Should not be nested in dashboard
expect($('h1').text()).toBe('Dashboard')
// Should include the page text
expect($('p').text()).toBe('hello from root/dashboard/integrations')
})
// TODO: why is this routable but /should-not-serve-server.server.js
it('should not include parent when not in parent directory with route in directory', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/rootonly/hello')
const $ = cheerio.load(html)
// Should be nested in /root.js
expect($('html').hasClass('this-is-the-document-html')).toBeTruthy()
expect($('body').hasClass('this-is-the-document-body')).toBeTruthy()
// Should not be nested in dashboard
expect($('h1').text()).toBeFalsy()
// Should render the page text
expect($('p').text()).toBe('hello from root/dashboard/rootonly/hello')
})
it('should include parent document when no direct parent layout', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/integrations')
const $ = cheerio.load(html)
// Root has to provide it's own document
expect($('html').hasClass('this-is-the-document-html')).toBeTruthy()
expect($('body').hasClass('this-is-the-document-body')).toBeTruthy()
})
it('should not include parent when not in parent directory', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/changelog')
const $ = cheerio.load(html)
// Should not be nested in dashboard
expect($('h1').text()).toBeFalsy()
// Should include the page text
expect($('p').text()).toBe('hello from root/dashboard/changelog')
})
it('should serve nested parent', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/deployments/123')
const $ = cheerio.load(html)
// Should be nested in dashboard
expect($('h1').text()).toBe('Dashboard')
// Should be nested in deployments
expect($('h2').text()).toBe('Deployments hello')
})
it('should serve dynamic parameter', async () => {
const html = await renderViaHTTP(next.url, '/dashboard/deployments/123')
const $ = cheerio.load(html)
// Should include the page text with the parameter
expect($('p').text()).toBe(
'hello from root/dashboard/deployments/[id]. ID is: 123'
)
})
it('should include document html and body', async () => {
const html = await renderViaHTTP(next.url, '/dashboard')
const $ = cheerio.load(html)
expect($('html').hasClass('this-is-the-document-html')).toBeTruthy()
expect($('body').hasClass('this-is-the-document-body')).toBeTruthy()
})
it('should not serve when layout is provided but no folder index', async () => {
const res = await fetchViaHTTP(next.url, '/dashboard/deployments')
expect(res.status).toBe(404)
expect(await res.text()).toContain('This page could not be found')
})
// TODO: do we want to make this only work for /root or is it allowed
// to work for /pages as well?
it.skip('should match partial parameters', async () => {
const html = await renderViaHTTP(next.url, '/partial-match-123')
expect(html).toContain('hello from root/partial-match-[id]. ID is: 123')
})
// TODO: Implement
describe.skip('parallel routes', () => {
describe('conditional routes', () => {
it('should serve user page', async () => {
const html = await renderViaHTTP(next.url, '/conditional/tim')
expect(html).toContain('hello from user homepage')
})
it('should serve user teams page', async () => {
const html = await renderViaHTTP(next.url, '/conditional/tim/teams')
expect(html).toContain('hello from user/teams')
})
it('should not serve teams page to user', async () => {
const html = await renderViaHTTP(next.url, '/conditional/tim/members')
expect(html).not.toContain('hello from team/members')
})
it('should serve team page', async () => {
const html = await renderViaHTTP(next.url, '/conditional/vercel')
expect(html).toContain('hello from team homepage')
})
it('should serve team members page', async () => {
const html = await renderViaHTTP(
next.url,
'/conditional/vercel/members'
)
expect(html).toContain('hello from team/members')
})
it('should provide both matches if both paths match', async () => {
const html = await renderViaHTTP(next.url, '/conditional/both')
expect(html).toContain('hello from team homepage')
expect(html).toContain('hello from user homepage')
})
it('should 404 based on getServerSideProps', async () => {
const res = await fetchViaHTTP(next.url, '/conditional/nonexistent')
expect(res.status).toBe(404)
expect(await res.text()).toContain('This page could not be found')
})
})
})
describe('server components', () => {
// TODO: why is this not servable but /dashboard+rootonly/hello.server.js
// should be? Seems like they both either should be servable or not
it('should not serve .server.js as a path', async () => {
// Without .server.js should serve
const html = await renderViaHTTP(next.url, '/should-not-serve-server')
expect(html).toContain('hello from root/should-not-serve-server')
// Should not serve `.server`
const res = await fetchViaHTTP(
next.url,
'/should-not-serve-server.server'
)
expect(res.status).toBe(404)
expect(await res.text()).toContain('This page could not be found')
// Should not serve `.server.js`
const res2 = await fetchViaHTTP(
next.url,
'/should-not-serve-server.server.js'
)
expect(res2.status).toBe(404)
expect(await res2.text()).toContain('This page could not be found')
})
it('should not serve .client.js as a path', async () => {
// Without .client.js should serve
const html = await renderViaHTTP(next.url, '/should-not-serve-client')
expect(html).toContain('hello from root/should-not-serve-client')
// Should not serve `.client`
const res = await fetchViaHTTP(
next.url,
'/should-not-serve-client.client'
)
expect(res.status).toBe(404)
expect(await res.text()).toContain('This page could not be found')
// Should not serve `.client.js`
const res2 = await fetchViaHTTP(
next.url,
'/should-not-serve-client.client.js'
)
expect(res2.status).toBe(404)
expect(await res2.text()).toContain('This page could not be found')
})
it('should serve shared component', async () => {
// Without .client.js should serve
const html = await renderViaHTTP(next.url, '/shared-component-route')
expect(html).toContain('hello from root/shared-component-route')
})
// TODO: implement
it.skip('should serve client component', async () => {
const html = await renderViaHTTP(next.url, '/client-component-route')
expect(html).toContain('hello from root/client-component-route. count: 0')
const browser = await webdriver(next.url, '/client-component-route')
// After hydration count should be 1
expect(await browser.elementByCss('p').text()).toBe(
'hello from root/client-component-route. count: 1'
)
})
// TODO: implement
it.skip('should include client component layout with server component route', async () => {
const html = await renderViaHTTP(next.url, '/client-nested')
const $ = cheerio.load(html)
// Should not be nested in dashboard
expect($('h1').text()).toBe('Client Nested. Count: 0')
// Should include the page text
expect($('p').text()).toBe('hello from root/client-nested')
const browser = await webdriver(next.url, '/client-nested')
// After hydration count should be 1
expect(await browser.elementByCss('h1').text()).toBe(
'Client Nested. Count: 0'
)
// After hydration count should be 1
expect(await browser.elementByCss('h1').text()).toBe(
'hello from root/client-nested'
)
})
})
})