Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions packages/router-core/tests/tsr-script-teardown.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
import minifiedTsrBootStrapScript from '../src/ssr/tsrScript?script-string'

type TsrBootstrap = {
h: () => void
e: () => void
c: () => void
}

// Assign `self.$_TSR`.
function installBootstrap(): TsrBootstrap {
new Function(minifiedTsrBootStrapScript)()
return (window as any).$_TSR
}

function setReadyState(value: DocumentReadyState) {
Object.defineProperty(document, 'readyState', {
configurable: true,
get: () => value,
})
}

describe('$_TSR client teardown', () => {
beforeEach(() => {
;(window as any).$R = { tsr: [] }
delete (window as any).$_TSR
})

afterEach(() => {
delete (window as any).$_TSR
delete (window as any).$R
setReadyState('complete')
})

test('does not tear down until both hydrated and streamEnded', () => {
setReadyState('complete')
const tsr = installBootstrap()

tsr.h()
expect((window as any).$_TSR).toBeDefined()

tsr.e()
expect((window as any).$_TSR).toBeUndefined()
})

test('tears down immediately when the document is already parsed', () => {
setReadyState('complete')
const tsr = installBootstrap()

tsr.h()
tsr.e()

expect((window as any).$_TSR).toBeUndefined()
expect((window as any).$R.tsr).toBeUndefined()
})

// Regression: deferred/streamed deserializations can still arrive after the
// `$_TSR.e()` stream-end marker (e.g. Solid 2 streams resource hydration past
// it). Tearing `$_TSR` down immediately would make those late references
// throw `$_TSR is not defined`, so teardown waits for the document to finish
// parsing.
test('keeps $_TSR alive until DOMContentLoaded while the document is still loading', () => {
setReadyState('loading')
const tsr = installBootstrap()

tsr.h()
tsr.e()

// Still available for late streamed scripts.
expect((window as any).$_TSR).toBeDefined()
expect((window as any).$R.tsr).toBeDefined()

document.dispatchEvent(new Event('DOMContentLoaded'))

expect((window as any).$_TSR).toBeUndefined()
expect((window as any).$R.tsr).toBeUndefined()
})
})
Loading