|
|
@@ -10,10 +10,13 @@ declare const window: Window & {
|
|
|
}
|
|
|
|
|
|
describe('async component hydration strategies', () => {
|
|
|
- const { page, click, text, count } = setupPuppeteer(['--window-size=800,600'])
|
|
|
+ const { page, click, text, count } = setupPuppeteer([
|
|
|
+ '--window-size=800,600',
|
|
|
+ '--disable-web-security',
|
|
|
+ ])
|
|
|
|
|
|
- async function goToCase(name: string, query = '') {
|
|
|
- const file = `file://${path.resolve(__dirname, `./hydration-strat-${name}.html${query}`)}`
|
|
|
+ async function goToCase(name: string, query = '', vapor = false) {
|
|
|
+ const file = `file://${path.resolve(__dirname, `./hydration-strat-${name}${vapor ? '-vapor' : ''}.html${query}`)}`
|
|
|
await page().goto(file)
|
|
|
}
|
|
|
|
|
|
@@ -22,138 +25,148 @@ describe('async component hydration strategies', () => {
|
|
|
expect(await text('button')).toBe(n)
|
|
|
}
|
|
|
|
|
|
- test('idle', async () => {
|
|
|
- const messages: string[] = []
|
|
|
- page().on('console', e => messages.push(e.text()))
|
|
|
-
|
|
|
- await goToCase('idle')
|
|
|
- // not hydrated yet
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- // wait for hydration
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- // assert message order: hyration should happen after already queued main thread work
|
|
|
- expect(messages.slice(1)).toMatchObject(['resolve', 'busy', 'hydrated'])
|
|
|
- await assertHydrationSuccess()
|
|
|
+ describe('vdom', () => {
|
|
|
+ runSharedTests(false)
|
|
|
})
|
|
|
|
|
|
- test('visible', async () => {
|
|
|
- await goToCase('visible')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- // scroll down
|
|
|
- await page().evaluate(() => window.scrollTo({ top: 1000 }))
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess()
|
|
|
+ describe('vapor', () => {
|
|
|
+ runSharedTests(true)
|
|
|
})
|
|
|
|
|
|
- test('visible (with rootMargin)', async () => {
|
|
|
- await goToCase('visible', '?rootMargin=1000')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- // should hydrate without needing to scroll
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess()
|
|
|
- })
|
|
|
-
|
|
|
- test('visible (fragment)', async () => {
|
|
|
- await goToCase('visible', '?fragment')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- expect(await count('span')).toBe(2)
|
|
|
- // scroll down
|
|
|
- await page().evaluate(() => window.scrollTo({ top: 1000 }))
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess()
|
|
|
- })
|
|
|
-
|
|
|
- test('visible (root v-if) should not throw error', async () => {
|
|
|
- const spy = vi.fn()
|
|
|
- const currentPage = page()
|
|
|
- currentPage.on('pageerror', spy)
|
|
|
- await goToCase('visible', '?v-if')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- expect(spy).toBeCalledTimes(0)
|
|
|
- currentPage.off('pageerror', spy)
|
|
|
- })
|
|
|
-
|
|
|
- test('media query', async () => {
|
|
|
- await goToCase('media')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- // resize
|
|
|
- await page().setViewport({ width: 400, height: 600 })
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess()
|
|
|
- })
|
|
|
-
|
|
|
- // #13255
|
|
|
- test('media query (patched before hydration)', async () => {
|
|
|
- const spy = vi.fn()
|
|
|
- const currentPage = page()
|
|
|
- currentPage.on('pageerror', spy)
|
|
|
-
|
|
|
- const warn: any[] = []
|
|
|
- currentPage.on('console', e => warn.push(e.text()))
|
|
|
-
|
|
|
- await goToCase('media')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
-
|
|
|
- // patch
|
|
|
- await page().evaluate(() => (window.show.value = false))
|
|
|
- await click('button')
|
|
|
- expect(await text('button')).toBe('1')
|
|
|
-
|
|
|
- // resize
|
|
|
- await page().setViewport({ width: 400, height: 600 })
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess('2')
|
|
|
-
|
|
|
- expect(spy).toBeCalledTimes(0)
|
|
|
- currentPage.off('pageerror', spy)
|
|
|
- expect(
|
|
|
- warn.some(w => w.includes('Skipping lazy hydration for component')),
|
|
|
- ).toBe(true)
|
|
|
- })
|
|
|
-
|
|
|
- test('interaction', async () => {
|
|
|
- await goToCase('interaction')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- await click('button')
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- // should replay event
|
|
|
- expect(await text('button')).toBe('1')
|
|
|
- await assertHydrationSuccess('2')
|
|
|
- })
|
|
|
-
|
|
|
- test('interaction (fragment)', async () => {
|
|
|
- await goToCase('interaction', '?fragment')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- await click('button')
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- // should replay event
|
|
|
- expect(await text('button')).toBe('1')
|
|
|
- await assertHydrationSuccess('2')
|
|
|
- })
|
|
|
-
|
|
|
- test('custom', async () => {
|
|
|
- await goToCase('custom')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- await click('#custom-trigger')
|
|
|
- await page().waitForFunction(() => window.isHydrated)
|
|
|
- await assertHydrationSuccess()
|
|
|
- })
|
|
|
-
|
|
|
- test('custom teardown', async () => {
|
|
|
- await goToCase('custom')
|
|
|
- await page().waitForFunction(() => window.isRootMounted)
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- await page().evaluate(() => (window.show.value = false))
|
|
|
- expect(await text('#app')).toBe('off')
|
|
|
- expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
- expect(await page().evaluate(() => window.teardownCalled)).toBe(true)
|
|
|
- })
|
|
|
+ function runSharedTests(vapor: boolean) {
|
|
|
+ test('idle', async () => {
|
|
|
+ const messages: string[] = []
|
|
|
+ page().on('console', e => messages.push(e.text()))
|
|
|
+
|
|
|
+ await goToCase('idle', '', vapor)
|
|
|
+ // not hydrated yet
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ // wait for hydration
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ // assert message order: hyration should happen after already queued main thread work
|
|
|
+ expect(messages.slice(1)).toMatchObject(['resolve', 'busy', 'hydrated'])
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ test('visible', async () => {
|
|
|
+ await goToCase('visible', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ // scroll down
|
|
|
+ await page().evaluate(() => window.scrollTo({ top: 1000 }))
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ test('visible (with rootMargin)', async () => {
|
|
|
+ await goToCase('visible', '?rootMargin=1000', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ // should hydrate without needing to scroll
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ test('visible (fragment)', async () => {
|
|
|
+ await goToCase('visible', '?fragment', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ expect(await count('span')).toBe(2)
|
|
|
+ // scroll down
|
|
|
+ await page().evaluate(() => window.scrollTo({ top: 1000 }))
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ test('visible (root v-if) should not throw error', async () => {
|
|
|
+ const spy = vi.fn()
|
|
|
+ const currentPage = page()
|
|
|
+ currentPage.on('pageerror', spy)
|
|
|
+ await goToCase('visible', '?v-if', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ expect(spy).toBeCalledTimes(0)
|
|
|
+ currentPage.off('pageerror', spy)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('media query', async () => {
|
|
|
+ await goToCase('media', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ // resize
|
|
|
+ await page().setViewport({ width: 400, height: 600 })
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ // #13255
|
|
|
+ test('media query (patched before hydration)', async () => {
|
|
|
+ const spy = vi.fn()
|
|
|
+ const currentPage = page()
|
|
|
+ currentPage.on('pageerror', spy)
|
|
|
+
|
|
|
+ const warn: any[] = []
|
|
|
+ currentPage.on('console', e => warn.push(e.text()))
|
|
|
+
|
|
|
+ await goToCase('media', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+
|
|
|
+ // patch
|
|
|
+ await page().evaluate(() => (window.show.value = false))
|
|
|
+ await click('button')
|
|
|
+ expect(await text('button')).toBe('1')
|
|
|
+
|
|
|
+ // resize
|
|
|
+ await page().setViewport({ width: 400, height: 600 })
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess('2')
|
|
|
+
|
|
|
+ expect(spy).toBeCalledTimes(0)
|
|
|
+ currentPage.off('pageerror', spy)
|
|
|
+ expect(
|
|
|
+ warn.some(w => w.includes('Skipping lazy hydration for component')),
|
|
|
+ ).toBe(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('interaction', async () => {
|
|
|
+ await goToCase('interaction', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ await click('button')
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ // should replay event
|
|
|
+ expect(await text('button')).toBe('1')
|
|
|
+ await assertHydrationSuccess('2')
|
|
|
+ })
|
|
|
+
|
|
|
+ test('interaction (fragment)', async () => {
|
|
|
+ await goToCase('interaction', '?fragment', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ await click('button')
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ // should replay event
|
|
|
+ expect(await text('button')).toBe('1')
|
|
|
+ await assertHydrationSuccess('2')
|
|
|
+ })
|
|
|
+
|
|
|
+ test('custom', async () => {
|
|
|
+ await goToCase('custom', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ await click('#custom-trigger')
|
|
|
+ await page().waitForFunction(() => window.isHydrated)
|
|
|
+ await assertHydrationSuccess()
|
|
|
+ })
|
|
|
+
|
|
|
+ test('custom teardown', async () => {
|
|
|
+ await goToCase('custom', '', vapor)
|
|
|
+ await page().waitForFunction(() => window.isRootMounted)
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ await page().evaluate(() => (window.show.value = false))
|
|
|
+ expect(await text('#app')).toBe('off')
|
|
|
+ expect(await page().evaluate(() => window.isHydrated)).toBe(false)
|
|
|
+ expect(await page().evaluate(() => window.teardownCalled)).toBe(true)
|
|
|
+ })
|
|
|
+ }
|
|
|
})
|