Skip to content

Commit

Permalink
update /test/vike-react/
Browse files Browse the repository at this point in the history
  • Loading branch information
brillout committed Sep 24, 2024
1 parent 6019173 commit da3f2b4
Show file tree
Hide file tree
Showing 35 changed files with 733 additions and 121 deletions.
13 changes: 8 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/vike-react/.test-dev.test.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import { testRun } from './.testRun'
testRun('npm run dev')
testRun('pnpm run dev')
2 changes: 1 addition & 1 deletion test/vike-react/.test-preview.test.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import { testRun } from './.testRun'
testRun('npm run preview')
testRun('pnpm run preview')
289 changes: 240 additions & 49 deletions test/vike-react/.testRun.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,249 @@
import { run, page, test, expect, getServerUrl, fetchHtml, autoRetry } from '@brillout/test-e2e'
import { ensureWasClientSideRouted, testCounter } from '../../test/utils'

export { testRun }
import { test, expect, run, fetchHtml, page, getServerUrl, autoRetry, partRegex } from '@brillout/test-e2e'
import assert from 'node:assert'

let isProd: boolean

const titleDefault = 'My Vike + React App'
const pages = {
'/': {
title: titleDefault,
text: 'Rendered to HTML.',
counter: true,
image: true
},
'/star-wars': {
title: '6 Star Wars Movies',
description: 'All the 6 movies from the Star Wars franchise',
text: 'A New Hope',
image: true
},
'/star-wars/3': {
title: 'Return of the Jedi',
description: 'Star Wars Movie Return of the Jedi from Richard Marquand',
text: '1983-05-25'
},
'/streaming': {
title: titleDefault,
text: 'Progressive Rendering',
counter: true
},
'/without-ssr': {
title: 'No SSR',
text: 'This page is rendered only in the browser',
counter: true,
noSSR: true
}
} as const

function testRun(cmd: 'npm run dev' | 'npm run preview', isStem?: true) {
run(cmd, { doNotFailOnWarning: true })
function testRun(cmd: `pnpm run ${'dev' | 'preview'}`) {
run(cmd)
isProd = cmd !== 'pnpm run dev'
testPages()
testPageNavigation_betweenWithSSRAndWithout()
testPageNavigation_titleUpdate()
testUseConfig()
}

function testPageNavigation_betweenWithSSRAndWithout() {
const textWithSSR = 'Rendered to HTML.'
const textWithoutSSR = "It isn't rendered to HTML"

test('page content is rendered to HTML', async () => {
const html = await fetchHtml('/')
expect(html).toContain('<li>Rendered to HTML.</li>')
const url = '/without-ssr'
test(url + " isn't rendered to HTML", async () => {
const html = await fetchHtml(url)
expect(html).toContain('<div id="root"></div>')
expect(html).not.toContain(textWithoutSSR)
await page.goto(getServerUrl() + url)
await testCounter()
const body = await page.textContent('body')
expect(body).toContain(textWithoutSSR)
})

test('page is rendered to the DOM and interactive', async () => {
await page.goto(getServerUrl() + '/')
test('Switch between SSR and non-SSR page', async () => {
let body: string | null
const t1 = textWithoutSSR
const t2 = textWithSSR

body = await page.textContent('body')
expect(body).toContain(t1)
expect(body).not.toContain(t2)
ensureWasClientSideRouted('/pages/without-ssr')

await page.click('a:has-text("Welcome")')
await testCounter()
body = await page.textContent('body')
expect(body).toContain(t2)
expect(body).not.toContain(t1)
ensureWasClientSideRouted('/pages/without-ssr')

// Client-side routing
await page.click('a[href="/star-wars"]')
await autoRetry(async () => {
expect(await page.textContent('h1')).toBe('Star Wars Movies')
})
expect(await page.textContent('body')).toContain('The Phantom Menace')
await ensureWasClientSideRouted(isStem ? '/pages/index/index' : '/pages/index')
})

test('data fetching page, HTML', async () => {
const html = await fetchHtml('/star-wars')
expect(html).toContain('<a href="/star-wars/6">Revenge of the Sith</a>')
expect(html).toContain('<a href="/star-wars/4">The Phantom Menace</a>')
})

test('data fetching page, DOM', async () => {
await page.goto(getServerUrl() + '/star-wars')
const text = await page.textContent('body')
expect(text).toContain('Revenge of the Sith')
expect(text).toContain('The Phantom Menace')

await page.click('a[href="/star-wars/4"]')
await autoRetry(async () => {
expect(await page.textContent('h1')).toBe('The Phantom Menace')
})
const pageContent = 'The Phantom MenaceRelease Date: 1999-05-19Director: George LucasProducer: Rick McCallum'
expect(await page.textContent('body')).toContain(pageContent)
})

test('ssr: false', async () => {
const html = await fetchHtml('/star-wars/4')
expect(html).toContain('<html')
// <head> is render to HTML
expect(html).toContain('<title>The Phantom Menace</title>')
expect(html).toContain('<meta name="description" content="Demo showcasing Vike + React"/>')
expect(html).toContain('<link rel="icon"')
// <body> isn't rendered to HTML
expect(html).not.toContain('<h1>')
expect(html).toContain('<div id="root"></div>')
await page.click('a:has-text("Without SSR")')
await testCounter()
body = await page.textContent('body')
expect(body).toContain(t1)
expect(body).not.toContain(t2)
ensureWasClientSideRouted('/pages/without-ssr')
})
}

function testPageNavigation_titleUpdate() {
test('title update client-side page navigation', async () => {
{
const { title } = pages['/']
await page.goto(getServerUrl() + '/')
await expectTitle(title)
}
const testMovieList = async () => {
const { title } = pages['/star-wars']
await page.click(`a[href="/star-wars"]`)
await expectTitle(title)
}
await testMovieList()
const testMoviePage = async () => {
const { title } = pages['/star-wars/3']
await page.click(`a:has-text("${title}")`)
await expectTitle(title)
}
await testMoviePage()
await testMovieList()
await testMoviePage()
await testMovieList()
await testMoviePage()
})
}
async function expectTitle(title: string) {
await autoRetry(async () => {
const titleActual = await page.evaluate(() => window.document.title)
expect(titleActual).toBe(title)
})
}

function testPages() {
Object.entries(pages).forEach(([url, pageInfo]) => {
testPage({ url, ...pageInfo })
})
}

function testPage({
url,
title,
description,
text,
counter,
noSSR,
image
}: {
url: string
title: string
description?: string
text: string
counter?: true
noSSR?: true
image?: true
}) {
test(url + ' (HTML)', async () => {
const html = await fetchHtml(url)
if (!noSSR) {
expect(html).toContain(text)
}
expect(getTitle(html)).toBe(title)
expect(html).toMatch(partRegex`<link rel="icon" href="${getAssetUrl('logo.svg')}"/>`)

if (description) {
expect(html).toMatch(partRegex`<meta name="description" content="${description}"${/\s*/}/>`)
} else {
expect(html).not.toContain('<meta name="description"')
}

if (image) {
expect(html).toMatch(partRegex`<meta property="og:image" content="${getAssetUrl('logo-new.svg')}">`)
} else {
expect(html).not.toContain('og:image')
}
})
test(url + ' (Hydration)', async () => {
await page.goto(getServerUrl() + url)
if (counter) {
await testCounter()
}
const body = await page.textContent('body')
expect(body).toContain(text)
})
}

function getTitle(html: string) {
const title = html.match(/<title>(.*?)<\/title>/i)?.[1]
return title
}

async function testCounter() {
// autoRetry() for awaiting client-side code loading & executing
await autoRetry(
async () => {
expect(await page.textContent('button')).toBe('Counter 0')
await page.click('button')
expect(await page.textContent('button')).toContain('Counter 1')
},
{ timeout: 5 * 1000 }
)
}

function testUseConfig() {
test('useConfig() HTML', async () => {
const html = await fetchHtml('/images')
expect(html).toMatch(
partRegex`<script type="application/ld+json">{"@context":"https://schema.org/","contentUrl":{"src":"${getAssetUrl(
'logo-new.svg'
)}"},"creator":{"@type":"Person","name":"brillout"}}</script>`
)
expect(html).toMatch(
partRegex`<script type="application/ld+json">{"@context":"https://schema.org/","contentUrl":{"src":"${getAssetUrl(
'logo.svg'
)}"},"creator":{"@type":"Person","name":"Romuald Brillout"}}</script>`
)
})
test('useConfig() hydration', async () => {
await page.goto(getServerUrl() + '/')
await testCounter()
ensureWasClientSideRouted('/pages/index')
await page.click('a:has-text("useConfig()")')
await testCounter()
ensureWasClientSideRouted('/pages/index')
await page.goto(getServerUrl() + '/images')
await testCounter()
})
}

/** Ensure page wasn't server-side routed.
*
* Examples:
* await ensureWasClientSideRouted('/pages/index')
* await ensureWasClientSideRouted('/pages/about')
*/
async function ensureWasClientSideRouted(pageIdFirst: `/pages/${string}`) {
// Check whether the HTML is from the first page before Client-side Routing.
// page.content() doesn't return the original HTML (it dumps the DOM to HTML).
// Therefore only the serialized pageContext tell us the original HTML.
const html = await page.content()
const pageId = findFirstPageId(html)
expect(pageId).toBe(pageIdFirst)
}
function findFirstPageId(html: string) {
expect(html).toContain('<script id="vike_pageContext" type="application/json">')
expect(html).toContain('"pageId"')
expect(html.split('"pageId"').length).toBe(2)
const match = partRegex`"pageId":"${/([^"]+)/}"`.exec(html)
expect(match).toBeTruthy()
const pageId = match![1]
expect(pageId).toBeTruthy()
return pageId
}

function getAssetUrl(fileName: string) {
if (!isProd) {
return `/assets/${fileName}`
}
const [fileBaseName, fileExt, ...r] = fileName.split('.')
assert(r.length === 0)
return partRegex`/assets/static/${fileBaseName}.${/[a-zA-Z0-9_-]+/}.${fileExt}`
}
1 change: 1 addition & 0 deletions test/vike-react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copied from: https://github.com/vikejs/vike-react/tree/main/examples/full
Loading

0 comments on commit da3f2b4

Please sign in to comment.