2023-04-11 22:57:12 +00:00
|
|
|
import { Script, createContext } from 'node:vm'
|
2022-04-05 18:38:23 +00:00
|
|
|
import { expect } from 'vitest'
|
2023-07-13 17:26:04 +00:00
|
|
|
import type { Page } from 'playwright-core'
|
2023-04-07 10:34:35 +00:00
|
|
|
import { parse } from 'devalue'
|
2023-04-07 16:02:47 +00:00
|
|
|
import { reactive, ref, shallowReactive, shallowRef } from 'vue'
|
2023-04-07 10:34:35 +00:00
|
|
|
import { createError } from 'h3'
|
2023-12-11 18:20:11 +00:00
|
|
|
import { getBrowser, url, useTestContext } from '@nuxt/test-utils/e2e'
|
2022-04-05 18:38:23 +00:00
|
|
|
|
2024-05-09 20:47:31 +00:00
|
|
|
export const isRenderingJson = process.env.TEST_PAYLOAD !== 'js'
|
2023-04-11 22:57:12 +00:00
|
|
|
|
2022-04-05 18:38:23 +00:00
|
|
|
export async function renderPage (path = '/') {
|
2022-04-07 11:28:04 +00:00
|
|
|
const ctx = useTestContext()
|
|
|
|
if (!ctx.options.browser) {
|
2022-08-26 15:47:29 +00:00
|
|
|
throw new Error('`renderPage` require `options.browser` to be set')
|
2022-04-07 11:28:04 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 18:38:23 +00:00
|
|
|
const browser = await getBrowser()
|
|
|
|
const page = await browser.newPage({})
|
2022-08-26 15:47:29 +00:00
|
|
|
const pageErrors: Error[] = []
|
2023-08-12 07:18:58 +00:00
|
|
|
const requests: string[] = []
|
2022-10-08 14:18:57 +00:00
|
|
|
const consoleLogs: { type: string, text: string }[] = []
|
2022-04-05 18:38:23 +00:00
|
|
|
|
|
|
|
page.on('console', (message) => {
|
|
|
|
consoleLogs.push({
|
|
|
|
type: message.type(),
|
2024-04-05 18:08:32 +00:00
|
|
|
text: message.text(),
|
2022-04-05 18:38:23 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
page.on('pageerror', (err) => {
|
|
|
|
pageErrors.push(err)
|
|
|
|
})
|
2023-08-12 07:18:58 +00:00
|
|
|
page.on('request', (req) => {
|
2023-09-19 21:26:15 +00:00
|
|
|
try {
|
|
|
|
requests.push(req.url().replace(url('/'), '/'))
|
|
|
|
} catch (err) {
|
|
|
|
// TODO
|
|
|
|
}
|
2023-08-12 07:18:58 +00:00
|
|
|
})
|
2022-04-05 18:38:23 +00:00
|
|
|
|
|
|
|
if (path) {
|
2024-03-16 20:19:07 +00:00
|
|
|
await gotoPath(page, path)
|
2022-04-05 18:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
page,
|
|
|
|
pageErrors,
|
2023-08-12 07:18:58 +00:00
|
|
|
requests,
|
2024-04-05 18:08:32 +00:00
|
|
|
consoleLogs,
|
2022-04-05 18:38:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function expectNoClientErrors (path: string) {
|
2022-04-07 11:28:04 +00:00
|
|
|
const ctx = useTestContext()
|
|
|
|
if (!ctx.options.browser) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-09 13:54:46 +00:00
|
|
|
const { page, pageErrors, consoleLogs } = (await renderPage(path))!
|
2022-04-05 18:38:23 +00:00
|
|
|
|
|
|
|
const consoleLogErrors = consoleLogs.filter(i => i.type === 'error')
|
2022-07-29 12:50:02 +00:00
|
|
|
const consoleLogWarnings = consoleLogs.filter(i => i.type === 'warning')
|
2022-04-05 18:38:23 +00:00
|
|
|
|
|
|
|
expect(pageErrors).toEqual([])
|
|
|
|
expect(consoleLogErrors).toEqual([])
|
|
|
|
expect(consoleLogWarnings).toEqual([])
|
2023-03-09 13:54:46 +00:00
|
|
|
|
|
|
|
await page.close()
|
2022-04-05 18:38:23 +00:00
|
|
|
}
|
2022-10-08 14:18:57 +00:00
|
|
|
|
2023-08-12 07:18:58 +00:00
|
|
|
export async function gotoPath (page: Page, path: string) {
|
|
|
|
await page.goto(url(path))
|
2024-03-16 20:19:07 +00:00
|
|
|
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path && !window.useNuxtApp?.().isHydrating, path)
|
2023-08-12 07:18:58 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 22:09:32 +00:00
|
|
|
type EqualityVal = string | number | boolean | null | undefined | RegExp
|
2023-01-22 16:46:45 +00:00
|
|
|
export async function expectWithPolling (
|
2023-02-13 22:09:32 +00:00
|
|
|
get: () => Promise<EqualityVal> | EqualityVal,
|
|
|
|
expected: EqualityVal,
|
2023-01-22 16:46:45 +00:00
|
|
|
retries = process.env.CI ? 100 : 30,
|
2024-04-05 18:08:32 +00:00
|
|
|
delay = process.env.CI ? 500 : 100,
|
2023-01-22 16:46:45 +00:00
|
|
|
) {
|
2023-02-13 22:09:32 +00:00
|
|
|
let result: EqualityVal
|
2023-01-22 16:46:45 +00:00
|
|
|
for (let i = retries; i >= 0; i--) {
|
|
|
|
result = await get()
|
2023-02-13 22:09:32 +00:00
|
|
|
if (result?.toString() === expected?.toString()) {
|
2023-01-22 16:46:45 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
await new Promise(resolve => setTimeout(resolve, delay))
|
|
|
|
}
|
2023-02-13 22:09:32 +00:00
|
|
|
expect(result?.toString(), `"${result?.toString()}" did not equal "${expected?.toString()}" in ${retries * delay}ms`).toEqual(expected?.toString())
|
2023-01-22 16:46:45 +00:00
|
|
|
}
|
|
|
|
|
2023-04-07 10:34:35 +00:00
|
|
|
const revivers = {
|
|
|
|
NuxtError: (data: any) => createError(data),
|
|
|
|
EmptyShallowRef: (data: any) => shallowRef(JSON.parse(data)),
|
|
|
|
EmptyRef: (data: any) => ref(JSON.parse(data)),
|
|
|
|
ShallowRef: (data: any) => shallowRef(data),
|
|
|
|
ShallowReactive: (data: any) => shallowReactive(data),
|
2023-06-14 09:09:27 +00:00
|
|
|
Island: (key: any) => key,
|
2023-04-07 10:34:35 +00:00
|
|
|
Ref: (data: any) => ref(data),
|
|
|
|
Reactive: (data: any) => reactive(data),
|
|
|
|
// test fixture reviver only
|
2024-04-05 18:08:32 +00:00
|
|
|
BlinkingText: () => '<revivified-blink>',
|
2023-04-07 10:34:35 +00:00
|
|
|
}
|
|
|
|
export function parsePayload (payload: string) {
|
|
|
|
return parse(payload || '', revivers)
|
|
|
|
}
|
|
|
|
export function parseData (html: string) {
|
2023-04-11 22:57:12 +00:00
|
|
|
if (!isRenderingJson) {
|
|
|
|
const { script } = html.match(/<script>(?<script>window.__NUXT__.*?)<\/script>/)?.groups || {}
|
|
|
|
const _script = new Script(script)
|
|
|
|
return {
|
|
|
|
script: _script.runInContext(createContext({ window: {} })),
|
2024-04-05 18:08:32 +00:00
|
|
|
attrs: {},
|
2023-04-11 22:57:12 +00:00
|
|
|
}
|
|
|
|
}
|
2023-04-07 10:34:35 +00:00
|
|
|
const { script, attrs } = html.match(/<script type="application\/json" id="__NUXT_DATA__"(?<attrs>[^>]+)>(?<script>.*?)<\/script>/)?.groups || {}
|
|
|
|
const _attrs: Record<string, string> = {}
|
2024-05-14 17:54:37 +00:00
|
|
|
for (const attr of attrs.matchAll(/( |^)(?<key>[\w-]+)="(?<value>[^"]+)"/g)) {
|
2023-04-07 10:34:35 +00:00
|
|
|
_attrs[attr!.groups!.key] = attr!.groups!.value
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
script: parsePayload(script || ''),
|
2024-04-05 18:08:32 +00:00
|
|
|
attrs: _attrs,
|
2023-04-07 10:34:35 +00:00
|
|
|
}
|
|
|
|
}
|