mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-21 21:25:11 +00:00
test: init hmr testing (#4372)
This commit is contained in:
parent
625022cf28
commit
5ede291a14
@ -18,6 +18,7 @@
|
|||||||
"vue/one-component-per-file": "off",
|
"vue/one-component-per-file": "off",
|
||||||
"vue/require-default-prop": "off",
|
"vue/require-default-prop": "off",
|
||||||
"vue/no-multiple-template-root": "off",
|
"vue/no-multiple-template-root": "off",
|
||||||
|
"vue/no-v-model-argument": "off",
|
||||||
"jsdoc/require-jsdoc": "off",
|
"jsdoc/require-jsdoc": "off",
|
||||||
"jsdoc/require-param": "off",
|
"jsdoc/require-param": "off",
|
||||||
"jsdoc/require-returns": "off",
|
"jsdoc/require-returns": "off",
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -61,3 +61,5 @@ Temporary Items
|
|||||||
.build-*
|
.build-*
|
||||||
.env
|
.env
|
||||||
.netlify
|
.netlify
|
||||||
|
|
||||||
|
fixtures-temp
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { promises as fsp } from 'node:fs'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { joinURL, withQuery } from 'ufo'
|
import { joinURL, withQuery } from 'ufo'
|
||||||
import { isWindows } from 'std-env'
|
import { isWindows } from 'std-env'
|
||||||
import { normalize } from 'pathe'
|
import { join, normalize } from 'pathe'
|
||||||
// eslint-disable-next-line import/order
|
// eslint-disable-next-line import/order
|
||||||
import { setup, fetch, $fetch, startServer, createPage, url } from '@nuxt/test-utils'
|
import { setup, fetch, $fetch, startServer, isDev, createPage, url } from '@nuxt/test-utils'
|
||||||
import type { NuxtIslandResponse } from '../packages/nuxt/src/core/runtime/nitro/renderer'
|
|
||||||
import { expectNoClientErrors, renderPage, withLogs } from './utils'
|
|
||||||
|
|
||||||
|
import type { NuxtIslandResponse } from '../packages/nuxt/src/core/runtime/nitro/renderer'
|
||||||
|
import { expectNoClientErrors, fixturesDir, expectWithPolling, renderPage, withLogs } from './utils'
|
||||||
|
|
||||||
|
const fixturePath = join(fixturesDir, 'basic')
|
||||||
await setup({
|
await setup({
|
||||||
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
rootDir: fixturePath,
|
||||||
server: true,
|
server: true,
|
||||||
browser: true,
|
browser: true,
|
||||||
setupTimeout: (isWindows ? 240 : 120) * 1000
|
setupTimeout: (isWindows ? 240 : 120) * 1000
|
||||||
@ -981,3 +984,50 @@ describe.skipIf(isWindows)('useAsyncData', () => {
|
|||||||
await expectNoClientErrors('/useAsyncData/promise-all')
|
await expectNoClientErrors('/useAsyncData/promise-all')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// HMR should be at the last
|
||||||
|
// TODO: fix HMR on Windows
|
||||||
|
if (isDev() && !isWindows) {
|
||||||
|
describe('hmr', () => {
|
||||||
|
it('should work', async () => {
|
||||||
|
const { page, pageErrors, consoleLogs } = await renderPage('/')
|
||||||
|
|
||||||
|
expect(await page.title()).toBe('Basic fixture')
|
||||||
|
expect((await page.$('.sugar-counter').then(r => r!.textContent()))!.trim())
|
||||||
|
.toEqual('Sugar Counter 12 x 2 = 24 Inc')
|
||||||
|
|
||||||
|
// reactive
|
||||||
|
await page.$('.sugar-counter button').then(r => r!.click())
|
||||||
|
expect((await page.$('.sugar-counter').then(r => r!.textContent()))!.trim())
|
||||||
|
.toEqual('Sugar Counter 13 x 2 = 26 Inc')
|
||||||
|
|
||||||
|
// modify file
|
||||||
|
let indexVue = await fsp.readFile(join(fixturePath, 'pages/index.vue'), 'utf8')
|
||||||
|
indexVue = indexVue
|
||||||
|
.replace('<Title>Basic fixture</Title>', '<Title>Basic fixture HMR</Title>')
|
||||||
|
.replace('<h1>Hello Nuxt 3!</h1>', '<h1>Hello Nuxt 3! HMR</h1>')
|
||||||
|
indexVue += '<style scoped>\nh1 { color: red }\n</style>'
|
||||||
|
await fsp.writeFile(join(fixturePath, 'pages/index.vue'), indexVue)
|
||||||
|
|
||||||
|
await expectWithPolling(
|
||||||
|
() => page.title(),
|
||||||
|
'Basic fixture HMR'
|
||||||
|
)
|
||||||
|
|
||||||
|
// content HMR
|
||||||
|
const h1 = await page.$('h1')
|
||||||
|
expect(await h1!.textContent()).toBe('Hello Nuxt 3! HMR')
|
||||||
|
|
||||||
|
// style HMR
|
||||||
|
const h1Color = await h1!.evaluate(el => window.getComputedStyle(el).getPropertyValue('color'))
|
||||||
|
expect(h1Color).toMatchInlineSnapshot('"rgb(255, 0, 0)"')
|
||||||
|
|
||||||
|
// ensure no errors
|
||||||
|
const consoleLogErrors = consoleLogs.filter(i => i.type === 'error')
|
||||||
|
const consoleLogWarnings = consoleLogs.filter(i => i.type === 'warn')
|
||||||
|
expect(pageErrors).toEqual([])
|
||||||
|
expect(consoleLogErrors).toEqual([])
|
||||||
|
expect(consoleLogWarnings).toEqual([])
|
||||||
|
}, isWindows ? 60_000 : 30_000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps({
|
defineProps({
|
||||||
count: {
|
multiplier: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
@ -9,6 +9,6 @@ defineProps({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<SugarCounter :count="count" />
|
<SugarCounter :multiplier="multiplier" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
15
test/fixtures/basic/components/SugarCounter.vue
vendored
15
test/fixtures/basic/components/SugarCounter.vue
vendored
@ -1,14 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps<{
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||||
count: number,
|
const { multiplier } = defineProps<{
|
||||||
|
multiplier: number
|
||||||
}>()
|
}>()
|
||||||
// eslint-disable-next-line prefer-const
|
const count = $ref(12)
|
||||||
let multiplier = $ref(2)
|
const doubled = $computed(() => count * multiplier)
|
||||||
const doubled = $computed(() => props.count * multiplier)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="sugar-counter">
|
||||||
Sugar Counter {{ count }} x {{ multiplier }} = {{ doubled }}
|
Sugar Counter {{ count }} x {{ multiplier }} = {{ doubled }}
|
||||||
|
<button @click="count += 1">
|
||||||
|
Inc
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
2
test/fixtures/basic/pages/index.vue
vendored
2
test/fixtures/basic/pages/index.vue
vendored
@ -14,7 +14,7 @@
|
|||||||
<NuxtLink to="/">
|
<NuxtLink to="/">
|
||||||
Link
|
Link
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NestedSugarCounter :count="12" />
|
<NestedSugarCounter :multiplier="2" />
|
||||||
<CustomComponent />
|
<CustomComponent />
|
||||||
<component :is="`test${'-'.toString()}global`" />
|
<component :is="`test${'-'.toString()}global`" />
|
||||||
<component :is="`with${'-'.toString()}suffix`" />
|
<component :is="`with${'-'.toString()}suffix`" />
|
||||||
|
20
test/setup.ts
Normal file
20
test/setup.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { dirname, join } from 'node:path'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
const dir = dirname(fileURLToPath(import.meta.url))
|
||||||
|
const fixtureDir = join(dir, 'fixtures')
|
||||||
|
const tempDir = join(dir, 'fixtures-temp')
|
||||||
|
|
||||||
|
export async function setup () {
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
await fs.remove(tempDir)
|
||||||
|
}
|
||||||
|
await fs.copy(fixtureDir, tempDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function teardown () {
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
await fs.remove(tempDir)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
import { expect } from 'vitest'
|
import { expect } from 'vitest'
|
||||||
import type { Page } from 'playwright'
|
import type { Page } from 'playwright'
|
||||||
import { createPage, getBrowser, url, useTestContext } from '@nuxt/test-utils'
|
import { createPage, getBrowser, url, useTestContext } from '@nuxt/test-utils'
|
||||||
|
|
||||||
|
export const fixturesDir = fileURLToPath(new URL(process.env.NUXT_TEST_DEV ? './fixtures-temp' : './fixtures', import.meta.url))
|
||||||
|
|
||||||
export async function renderPage (path = '/') {
|
export async function renderPage (path = '/') {
|
||||||
const ctx = useTestContext()
|
const ctx = useTestContext()
|
||||||
if (!ctx.options.browser) {
|
if (!ctx.options.browser) {
|
||||||
@ -50,6 +53,23 @@ export async function expectNoClientErrors (path: string) {
|
|||||||
expect(consoleLogWarnings).toEqual([])
|
expect(consoleLogWarnings).toEqual([])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function expectWithPolling (
|
||||||
|
get: () => Promise<string> | string,
|
||||||
|
expected: string,
|
||||||
|
retries = process.env.CI ? 100 : 30,
|
||||||
|
delay = process.env.CI ? 500 : 100
|
||||||
|
) {
|
||||||
|
let result: string | undefined
|
||||||
|
for (let i = retries; i >= 0; i--) {
|
||||||
|
result = await get()
|
||||||
|
if (result === expected) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delay))
|
||||||
|
}
|
||||||
|
expect(result).toEqual(expected)
|
||||||
|
}
|
||||||
|
|
||||||
export async function withLogs (callback: (page: Page, logs: string[]) => Promise<void>) {
|
export async function withLogs (callback: (page: Page, logs: string[]) => Promise<void>) {
|
||||||
let done = false
|
let done = false
|
||||||
const page = await createPage()
|
const page = await createPage()
|
||||||
|
@ -14,8 +14,11 @@ export default defineConfig({
|
|||||||
tsconfigRaw: '{}'
|
tsconfigRaw: '{}'
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
|
globalSetup: 'test/setup.ts',
|
||||||
testTimeout: isWindows ? 60000 : 10000,
|
testTimeout: isWindows ? 60000 : 10000,
|
||||||
// Excluded plugin because it should throw an error when accidentally loaded via Nuxt
|
// Excluded plugin because it should throw an error when accidentally loaded via Nuxt
|
||||||
exclude: [...configDefaults.exclude, '**/this-should-not-load.spec.js']
|
exclude: [...configDefaults.exclude, '**/this-should-not-load.spec.js'],
|
||||||
|
maxThreads: process.env.NUXT_TEST_DEV ? 1 : undefined,
|
||||||
|
minThreads: process.env.NUXT_TEST_DEV ? 1 : undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user