test: slightly improve test reliability (#27811)

This commit is contained in:
Daniel Roe 2024-06-25 08:48:39 +02:00
parent e3448fa0da
commit 51c8c35667
No known key found for this signature in database
GPG Key ID: CBC814C393D93268
4 changed files with 39 additions and 16 deletions

View File

@ -492,7 +492,7 @@ describe('pages', () => {
}) })
it('client only page', async () => { it('client only page', async () => {
const response = await fetch('/client-only').then(r => r.text()) const response = await fetch('/client-only-page').then(r => r.text())
// Should not contain rendered page on initial request // Should not contain rendered page on initial request
expect(response).not.toContain('"hasAccessToWindow": true') expect(response).not.toContain('"hasAccessToWindow": true')
@ -520,10 +520,11 @@ describe('pages', () => {
// Then go to non client only page // Then go to non client only page
await clientInitialPage.click('a') await clientInitialPage.click('a')
await new Promise(resolve => setTimeout(resolve, 50)) // little delay to finish transition await clientInitialPage.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/client-only-page/normal')
// that page should be client rendered // that page should be client rendered
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot('"false"') // TODO: investigate why multiple elements are appearing on page
expect(await clientInitialPage.locator('#server-rendered').first().textContent()).toMatchInlineSnapshot('"false"')
// and not contain any errors or warnings // and not contain any errors or warnings
expect(errors.length).toBe(0) expect(errors.length).toBe(0)
@ -545,6 +546,8 @@ describe('pages', () => {
// Go to client only page // Go to client only page
await normalInitialPage.click('a') await normalInitialPage.click('a')
await normalInitialPage.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/client-only-page')
// and expect same object to be present // and expect same object to be present
expect(await normalInitialPage.locator('#state').textContent()).toMatchInlineSnapshot(` expect(await normalInitialPage.locator('#state').textContent()).toMatchInlineSnapshot(`
"{ "{
@ -1421,6 +1424,7 @@ describe('deferred app suspense resolve', () => {
it.each(['/async-parent/child', '/internal-layout/async-parent/child'])('should wait for all suspense instance on initial hydration', async (path) => { it.each(['/async-parent/child', '/internal-layout/async-parent/child'])('should wait for all suspense instance on initial hydration', async (path) => {
const { page, consoleLogs } = await renderPage(path) const { page, consoleLogs } = await renderPage(path)
await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
// Wait for all pending micro ticks to be cleared in case hydration hasn't finished yet. // Wait for all pending micro ticks to be cleared in case hydration hasn't finished yet.
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10)))
@ -1517,7 +1521,7 @@ describe('nested suspense', () => {
const first = start.match(/\/suspense\/(?<parentType>a?sync)-(?<parentNum>\d)\/(?<childType>a?sync)-(?<childNum>\d)\//)!.groups! const first = start.match(/\/suspense\/(?<parentType>a?sync)-(?<parentNum>\d)\/(?<childType>a?sync)-(?<childNum>\d)\//)!.groups!
const last = nav.match(/\/suspense\/(?<parentType>a?sync)-(?<parentNum>\d)\//)!.groups! const last = nav.match(/\/suspense\/(?<parentType>a?sync)-(?<parentNum>\d)\//)!.groups!
await new Promise<void>(resolve => setTimeout(resolve, 50)) await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, nav)
expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes('<Suspense> is an experimental feature')).sort()).toEqual([ expect(consoleLogs.map(l => l.text).filter(i => !i.includes('[vite]') && !i.includes('<Suspense> is an experimental feature')).sort()).toEqual([
// [first load] from parent // [first load] from parent
@ -1579,6 +1583,7 @@ describe('page key', () => {
await page.click(`[href="${path}/1"]`) await page.click(`[href="${path}/1"]`)
await page.waitForSelector('#page-1') await page.waitForSelector('#page-1')
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `${path}/1`)
// Wait for all pending micro ticks to be cleared, // Wait for all pending micro ticks to be cleared,
// so we are not resolved too early when there are repeated page loading // so we are not resolved too early when there are repeated page loading
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10)))
@ -1593,6 +1598,7 @@ describe('page key', () => {
await page.click(`[href="${path}/1"]`) await page.click(`[href="${path}/1"]`)
await page.waitForSelector('#page-1') await page.waitForSelector('#page-1')
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `${path}/1`)
// Wait for all pending micro ticks to be cleared, // Wait for all pending micro ticks to be cleared,
// so we are not resolved too early when there are repeated page loading // so we are not resolved too early when there are repeated page loading
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10)))
@ -1625,6 +1631,7 @@ describe('layout change not load page twice', () => {
await page.click(`[href="${path2}"]`) await page.click(`[href="${path2}"]`)
await page.waitForSelector('#with-layout2') await page.waitForSelector('#with-layout2')
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, path2)
// Wait for all pending micro ticks to be cleared, // Wait for all pending micro ticks to be cleared,
// so we are not resolved too early when there are repeated page loading // so we are not resolved too early when there are repeated page loading
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10)))
@ -1917,7 +1924,7 @@ describe.skipIf(isDev() || isWindows || !isRenderingJson)('prefetching', () => {
describe.runIf(isDev() && (!isWindows || !isCI))('detecting invalid root nodes', () => { describe.runIf(isDev() && (!isWindows || !isCI))('detecting invalid root nodes', () => {
it.each(['1', '2', '3', '4'])('should detect invalid root nodes in pages (\'/invalid-root/%s\')', async (path) => { it.each(['1', '2', '3', '4'])('should detect invalid root nodes in pages (\'/invalid-root/%s\')', async (path) => {
const { consoleLogs, page } = await renderPage(joinURL('/invalid-root', path)) const { consoleLogs, page } = await renderPage(joinURL('/invalid-root', path))
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, joinURL('/invalid-root', path))
await expectWithPolling( await expectWithPolling(
() => consoleLogs () => consoleLogs
.map(w => w.text).join('\n') .map(w => w.text).join('\n')
@ -1930,7 +1937,7 @@ describe.runIf(isDev() && (!isWindows || !isCI))('detecting invalid root nodes',
it.each(['fine'])('should not complain if there is no transition (%s)', async (path) => { it.each(['fine'])('should not complain if there is no transition (%s)', async (path) => {
const { consoleLogs, page } = await renderPage(joinURL('/invalid-root', path)) const { consoleLogs, page } = await renderPage(joinURL('/invalid-root', path))
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10))) await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, joinURL('/invalid-root', path))
const consoleLogsWarns = consoleLogs.filter(i => i.type === 'warning') const consoleLogsWarns = consoleLogs.filter(i => i.type === 'warning')
expect(consoleLogsWarns.length).toEqual(0) expect(consoleLogsWarns.length).toEqual(0)
@ -2597,12 +2604,12 @@ describe('teleports', () => {
describe('Node.js compatibility for client-side', () => { describe('Node.js compatibility for client-side', () => {
it('should work', async () => { it('should work', async () => {
const { page } = await renderPage('/node-compat') const { page } = await renderPage('/experimental/node-compat')
await page.locator('body').getByText('Nuxt is Awesome!').waitFor() await page.locator('body').getByText('Nuxt is Awesome!').waitFor()
expect(await page.innerHTML('body')).toContain('CWD: [available]') expect(await page.innerHTML('body')).toContain('CWD: [available]')
await page.close() await page.close()
}, 40_000)
}) })
}, 30_000)
function normaliseIslandResult (result: NuxtIslandResponse) { function normaliseIslandResult (result: NuxtIslandResponse) {
return { return {

View File

@ -1,8 +1,8 @@
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { $fetch, setup } from '@nuxt/test-utils/e2e' import { $fetch, createPage, setup } from '@nuxt/test-utils/e2e'
import { isWindows } from 'std-env' import { isWindows } from 'std-env'
import { expectNoClientErrors, renderPage } from './utils' import { expectNoClientErrors } from './utils'
const isWebpack = process.env.TEST_BUILDER === 'webpack' const isWebpack = process.env.TEST_BUILDER === 'webpack'
@ -24,31 +24,40 @@ describe('test basic config', () => {
it('test HelloWorld.vue', async () => { it('test HelloWorld.vue', async () => {
const html = await $fetch('/') const html = await $fetch('/')
const { page } = await renderPage('/') const page = await createPage('/')
await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
expect(html).toContain('<div id="hello-world">hello, Helloworld.vue here ! </div>') expect(html).toContain('<div id="hello-world">hello, Helloworld.vue here ! </div>')
expect(await page.locator('body').innerHTML()).toContain('<div id="hello-world">hello, Helloworld.vue here ! </div>') expect(await page.locator('body').innerHTML()).toContain('<div id="hello-world">hello, Helloworld.vue here ! </div>')
await page.close()
}) })
it('test Name.ts', async () => { it('test Name.ts', async () => {
const html = await $fetch('/') const html = await $fetch('/')
const { page } = await renderPage('/') const page = await createPage('/')
await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
expect(html).toContain('<div id="name">I am the Name.ts component</div>') expect(html).toContain('<div id="name">I am the Name.ts component</div>')
expect(await page.locator('body').innerHTML()).toContain('<div id="name">I am the Name.ts component</div>') expect(await page.locator('body').innerHTML()).toContain('<div id="name">I am the Name.ts component</div>')
await page.close()
}) })
it('test ShowTemplate.ts', async () => { it('test ShowTemplate.ts', async () => {
const html = await $fetch('/') const html = await $fetch('/')
const { page } = await renderPage('/') const page = await createPage('/')
await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
expect(html).toContain('<div id="show-template">Hello my name is : John, i am defined by ShowTemplate.vue and my template is retrieved from the API</div>') expect(html).toContain('<div id="show-template">Hello my name is : John, i am defined by ShowTemplate.vue and my template is retrieved from the API</div>')
expect(await page.locator('body').innerHTML()).toContain('<div id="show-template">Hello my name is : John, i am defined by ShowTemplate.vue and my template is retrieved from the API</div>') expect(await page.locator('body').innerHTML()).toContain('<div id="show-template">Hello my name is : John, i am defined by ShowTemplate.vue and my template is retrieved from the API</div>')
await page.close()
}) })
it('test Interactive component.ts', async () => { it('test Interactive component.ts', async () => {
const html = await $fetch('/') const html = await $fetch('/')
const { page } = await renderPage('/') const page = await createPage('/')
await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
expect(html).toContain('I am defined by Interactive in the setup of App.vue. My full component definition is retrieved from the api') expect(html).toContain('I am defined by Interactive in the setup of App.vue. My full component definition is retrieved from the api')
expect(await page.locator('#interactive').innerHTML()).toContain('I am defined by Interactive in the setup of App.vue. My full component definition is retrieved from the api') expect(await page.locator('#interactive').innerHTML()).toContain('I am defined by Interactive in the setup of App.vue. My full component definition is retrieved from the api')
@ -56,5 +65,7 @@ describe('test basic config', () => {
await button.click() await button.click()
const count = page.locator('#interactive-count') const count = page.locator('#interactive-count')
expect(await count.innerHTML()).toBe('1') expect(await count.innerHTML()).toBe('1')
await page.close()
}) })
}) })

View File

@ -22,15 +22,18 @@ await setup({
describe('suspense multiple nav', () => { describe('suspense multiple nav', () => {
it('should not throw error', async () => { it('should not throw error', async () => {
const { page, consoleLogs, pageErrors } = await renderPage('/') const { page, consoleLogs, pageErrors } = await renderPage('/')
await page.waitForLoadState('networkidle') await page.waitForFunction(() => window.useNuxtApp?.() && !window.useNuxtApp?.().isHydrating)
expect(await page.locator('#btn-a').textContent()).toMatchInlineSnapshot('" Target A "') expect(await page.locator('#btn-a').textContent()).toMatchInlineSnapshot('" Target A "')
// Make sure it navigates to the correct page // Make sure it navigates to the correct page
await page.locator('#btn-a').click() await page.locator('#btn-a').click()
await page.waitForFunction(() => window.useNuxtApp?.()._route.path === '/target')
console.log(page.url()) console.log(page.url())
expect(await page.locator('#content').textContent()).toContain('Hello a') expect(await page.locator('#content').textContent()).toContain('Hello a')
await page.goBack() await page.goBack()
await page.waitForFunction(() => window.useNuxtApp?.()._route.path === '/')
// When back // When back
expect(await page.locator('body').textContent()).toContain('Index Page') expect(await page.locator('body').textContent()).toContain('Index Page')
@ -40,6 +43,8 @@ describe('suspense multiple nav', () => {
page.locator('#btn-b').click(), page.locator('#btn-b').click(),
]) ])
await page.waitForFunction(() => window.useNuxtApp?.()._route.path === '/target')
expect.soft(await page.locator('#content').textContent()).toContain('Hello b') expect.soft(await page.locator('#content').textContent()).toContain('Hello b')
const consoleLogErrors = consoleLogs.filter(i => i.type === 'error') const consoleLogErrors = consoleLogs.filter(i => i.type === 'error')