rsnext/test/lib/development-sandbox.ts
Tim Neutkens 486567d2d7
Update ReactRefreshRegression test snapshot for Turbopack (#60767)
## What?

While looking at some tests that use this helper I noticed we have the
helper duplicated currently. This ensures the session uses the same
helper.

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->


Closes NEXT-2127
2024-01-18 11:06:04 +01:00

147 lines
4.1 KiB
TypeScript

import {
getRedboxComponentStack,
getRedboxDescription,
getRedboxHeader,
getRedboxSource,
hasRedbox,
waitFor,
} from './next-test-utils'
import webdriver from './next-webdriver'
import { NextInstance } from './next-modes/base'
import { BrowserInterface } from './browsers/base'
export function waitForHydration(browser: BrowserInterface): Promise<void> {
return browser.evalAsync(function () {
var callback = arguments[arguments.length - 1]
if ((window as any).__NEXT_HYDRATED) {
callback()
} else {
var timeout = setTimeout(callback, 30 * 1000)
;(window as any).__NEXT_HYDRATED_CB = function () {
clearTimeout(timeout)
callback()
}
}
})
}
export async function sandbox(
next: NextInstance,
initialFiles?: Map<string, string>,
initialUrl: string = '/',
webDriverOptions: any = undefined
) {
await next.stop()
await next.clean()
if (initialFiles) {
for (const [k, v] of initialFiles.entries()) {
await next.patchFile(k, v)
}
}
await next.start()
const browser = await webdriver(next.url, initialUrl, webDriverOptions)
return {
browser,
session: {
async write(filename, content) {
// Update the file on filesystem
await next.patchFile(filename, content)
},
async patch(filename, content) {
// Register an event for HMR completion
await browser.eval(function () {
;(window as any).__HMR_STATE = 'pending'
var timeout = setTimeout(() => {
;(window as any).__HMR_STATE = 'timeout'
}, 30 * 1000)
;(window as any).__NEXT_HMR_CB = function () {
clearTimeout(timeout)
;(window as any).__HMR_STATE = 'success'
}
})
await this.write(filename, content)
for (;;) {
const status = await browser.eval(() => (window as any).__HMR_STATE)
if (!status) {
await waitFor(750)
// Wait for application to re-hydrate:
await waitForHydration(browser)
console.log('Application re-loaded.')
// Slow down tests a bit:
await waitFor(750)
return false
}
if (status === 'success') {
console.log('Hot update complete.')
break
}
if (status !== 'pending') {
throw new Error(`Application is in inconsistent state: ${status}.`)
}
await waitFor(30)
}
// Slow down tests a bit (we don't know how long re-rendering takes):
await waitFor(750)
return true
},
async remove(filename) {
await next.deleteFile(filename)
},
async evaluate(snippet: string | Function) {
if (typeof snippet === 'function' || typeof snippet === 'string') {
const result = await browser.eval(snippet)
await waitFor(30)
return result
} else {
throw new Error(
`You must pass a string or function to be evaluated in the browser.`
)
}
},
async hasRedbox() {
return hasRedbox(browser)
},
async hasErrorToast() {
return browser.eval(() => {
return Boolean(
Array.from(document.querySelectorAll('nextjs-portal')).find((p) =>
p.shadowRoot.querySelector('[data-nextjs-toast]')
)
)
})
},
async getRedboxDescription() {
return getRedboxDescription(browser)
},
async getRedboxSource(includeHeader = false) {
const header = includeHeader ? await getRedboxHeader(browser) : ''
const source = await getRedboxSource(browser)
if (includeHeader) {
return `${header}\n\n${source}`
}
return source
},
async getRedboxComponentStack() {
return getRedboxComponentStack(browser)
},
async waitForAndOpenRuntimeError() {
return browser.waitForElementByCss('[data-nextjs-toast]').click()
},
},
async cleanup() {
await browser.close()
await next.stop()
await next.clean()
},
}
}