Skip to content

Commit

Permalink
Add tests for HMR (#49206)
Browse files Browse the repository at this point in the history
This adds tests for Turbopack HMR as part of the Next.js turbo
integration test suite.
  • Loading branch information
alexkirsz committed May 10, 2023
1 parent c9d87ee commit 6a3f96e
Show file tree
Hide file tree
Showing 61 changed files with 470 additions and 140 deletions.
1 change: 1 addition & 0 deletions packages/next-swc/crates/next-dev-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/temp
62 changes: 57 additions & 5 deletions packages/next-swc/crates/next-dev-tests/test-harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ declare global {
// We need to extract only the call signature as `autoReady(jest.describe)` drops all the other properties
var describe: AutoReady<typeof jest.describe>
var it: AutoReady<typeof jest.it>
var READY: (arg: string) => void
var TURBOPACK_READY: (arg: string) => void
var TURBOPACK_CHANGE_FILE: (arg: string) => void
var nsObj: (obj: any) => any
var __turbopackFileChanged: (id: string, error: Error) => void

interface Window {
NEXT_HYDRATED?: boolean
Expand Down Expand Up @@ -62,8 +64,8 @@ function markReady() {
isReady = true
requestIdleCallback(
() => {
if (typeof READY === 'function') {
READY('')
if (typeof TURBOPACK_READY === 'function') {
TURBOPACK_READY('')
} else {
console.info(
'%cTurbopack tests:',
Expand All @@ -83,16 +85,28 @@ export function wait(ms: number): Promise<void> {
})
}

async function waitForPath(contentWindow: Window, path: string): Promise<void> {
export async function waitForCondition(
predicate: () => boolean,
timeout: number | null = null
): Promise<void> {
const start = Date.now()
while (true) {
if (contentWindow.location.pathname === path) {
if (predicate()) {
break
}

await wait(1)

if (timeout != null && Date.now() - start > timeout) {
throw new Error('Timed out waiting for condition')
}
}
}

async function waitForPath(contentWindow: Window, path: string): Promise<void> {
return waitForCondition(() => contentWindow.location.pathname === path)
}

/**
* Loads a new page in an iframe and waits for it to load.
*/
Expand Down Expand Up @@ -210,3 +224,41 @@ export function markAsHydrated() {
window.onNextHydrated()
}
}

const fileChangedResolvers: Map<
string,
{ resolve: (value: unknown) => void; reject: (error: Error) => void }
> = new Map()

globalThis.__turbopackFileChanged = (id: string, error?: Error) => {
const resolver = fileChangedResolvers.get(id)
if (resolver == null) {
throw new Error(`No resolver found for id ${id}`)
} else if (error != null) {
resolver.reject(error)
} else {
resolver.resolve(null)
}
}

function unsafeUniqueId(): string {
const LENGTH = 10
const BASE = 16
return Math.floor(Math.random() * Math.pow(BASE, LENGTH))
.toString(BASE)
.slice(0, LENGTH)
}

export async function changeFile(
path: string,
find: string,
replaceWith: string
) {
return new Promise((resolve, reject) => {
const id = unsafeUniqueId()

fileChangedResolvers.set(id, { resolve, reject })

TURBOPACK_CHANGE_FILE(JSON.stringify({ path, id, find, replaceWith }))
})
}

0 comments on commit 6a3f96e

Please sign in to comment.