Skip to content

Commit 00c64d0

Browse files
authored
[Fast Refresh] Add more test cases (#12568)
1 parent 960368e commit 00c64d0

File tree

1 file changed

+355
-0
lines changed

1 file changed

+355
-0
lines changed

test/acceptance/ReactRefreshLogBox.test.js

+355
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,358 @@ test('logbox: can recover from a component error', async () => {
210210

211211
await cleanup()
212212
})
213+
214+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/3#issuecomment-554137262
215+
test('render error not shown right after syntax error', async () => {
216+
const [session, cleanup] = await sandbox()
217+
218+
// Starting here:
219+
await session.patch(
220+
'index.js',
221+
`
222+
class ClassDefault extends React.Component {
223+
render() {
224+
return <h1>Default Export</h1>;
225+
}
226+
}
227+
228+
export default ClassDefault;
229+
`
230+
)
231+
232+
expect(
233+
await session.evaluate(() => document.querySelector('h1').textContent)
234+
).toBe('Default Export')
235+
236+
// Break it with a syntax error:
237+
await session.patch(
238+
'index.js',
239+
`
240+
import * as React from 'react';
241+
242+
class ClassDefault extends React.Component {
243+
render()
244+
return <h1>Default Export</h1>;
245+
}
246+
}
247+
248+
export default ClassDefault;
249+
`
250+
)
251+
expect(await session.hasRedbox(true)).toBe(true)
252+
253+
// Now change the code to introduce a runtime error without fixing the syntax error:
254+
await session.patch(
255+
'index.js',
256+
`
257+
import * as React from 'react';
258+
259+
class ClassDefault extends React.Component {
260+
render()
261+
throw new Error('nooo');
262+
return <h1>Default Export</h1>;
263+
}
264+
}
265+
266+
export default ClassDefault;
267+
`
268+
)
269+
expect(await session.hasRedbox(true)).toBe(true)
270+
271+
// Now fix the syntax error:
272+
await session.patch(
273+
'index.js',
274+
`
275+
import * as React from 'react';
276+
277+
class ClassDefault extends React.Component {
278+
render() {
279+
throw new Error('nooo');
280+
return <h1>Default Export</h1>;
281+
}
282+
}
283+
284+
export default ClassDefault;
285+
`
286+
)
287+
expect(await session.hasRedbox(true)).toBe(true)
288+
expect(await session.getRedboxSource()).toMatchInlineSnapshot(`
289+
"index.js (6:16) @ ClassDefault.render
290+
291+
4 | class ClassDefault extends React.Component {
292+
5 | render() {
293+
> 6 | throw new Error('nooo');
294+
| ^
295+
7 | return <h1>Default Export</h1>;
296+
8 | }
297+
9 | }"
298+
`)
299+
300+
await cleanup()
301+
})
302+
303+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/3#issuecomment-554137807
304+
test('module init error not shown', async () => {
305+
// Start here:
306+
const [session, cleanup] = await sandbox()
307+
308+
// We start here.
309+
await session.patch(
310+
'index.js',
311+
`
312+
import * as React from 'react';
313+
class ClassDefault extends React.Component {
314+
render() {
315+
return <h1>Default Export</h1>;
316+
}
317+
}
318+
export default ClassDefault;
319+
`
320+
)
321+
322+
expect(
323+
await session.evaluate(() => document.querySelector('h1').textContent)
324+
).toBe('Default Export')
325+
326+
// Add a throw in module init phase:
327+
await session.patch(
328+
'index.js',
329+
`
330+
// top offset for snapshot
331+
import * as React from 'react';
332+
throw new Error('no')
333+
class ClassDefault extends React.Component {
334+
render() {
335+
return <h1>Default Export</h1>;
336+
}
337+
}
338+
export default ClassDefault;
339+
`
340+
)
341+
342+
expect(await session.hasRedbox(true)).toBe(true)
343+
expect(await session.getRedboxSource()).toMatchInlineSnapshot(`
344+
"index.js (4:12) @ Module../index.js
345+
346+
2 | // top offset for snapshot
347+
3 | import * as React from 'react';
348+
> 4 | throw new Error('no')
349+
| ^
350+
5 | class ClassDefault extends React.Component {
351+
6 | render() {
352+
7 | return <h1>Default Export</h1>;"
353+
`)
354+
355+
await cleanup()
356+
})
357+
358+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/3#issuecomment-554144016
359+
test('stuck error', async () => {
360+
const [session, cleanup] = await sandbox()
361+
362+
// We start here.
363+
await session.patch(
364+
'index.js',
365+
`
366+
import * as React from 'react';
367+
368+
function FunctionDefault() {
369+
return <h1>Default Export Function</h1>;
370+
}
371+
372+
export default FunctionDefault;
373+
`
374+
)
375+
376+
// We add a new file. Let's call it Foo.js.
377+
await session.write(
378+
'Foo.js',
379+
`
380+
// intentionally skips export
381+
export default function Foo() {
382+
return React.createElement('h1', null, 'Foo');
383+
}
384+
`
385+
)
386+
387+
// We edit our first file to use it.
388+
await session.patch(
389+
'index.js',
390+
`
391+
import * as React from 'react';
392+
import Foo from './Foo';
393+
function FunctionDefault() {
394+
return <Foo />;
395+
}
396+
export default FunctionDefault;
397+
`
398+
)
399+
400+
// We get an error because Foo didn't import React. Fair.
401+
expect(await session.hasRedbox(true)).toBe(true)
402+
expect(await session.getRedboxSource()).toMatchInlineSnapshot(`
403+
"Foo.js (4:8) @ Foo
404+
405+
2 | // intentionally skips export
406+
3 | export default function Foo() {
407+
> 4 | return React.createElement('h1', null, 'Foo');
408+
| ^
409+
5 | }
410+
6 | "
411+
`)
412+
413+
// Let's add that to Foo.
414+
await session.patch(
415+
'Foo.js',
416+
`
417+
import * as React from 'react';
418+
export default function Foo() {
419+
return React.createElement('h1', null, 'Foo');
420+
}
421+
`
422+
)
423+
424+
// Expected: this fixes the problem
425+
expect(await session.hasRedbox()).toBe(false)
426+
427+
await cleanup()
428+
})
429+
430+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/3#issuecomment-554150098
431+
test('syntax > runtime error', async () => {
432+
const [session, cleanup] = await sandbox()
433+
434+
// Start here.
435+
await session.patch(
436+
'index.js',
437+
`
438+
import * as React from 'react';
439+
440+
export default function FunctionNamed() {
441+
return <div />
442+
}
443+
`
444+
)
445+
// TODO: this acts weird without above step
446+
await session.patch(
447+
'index.js',
448+
`
449+
import * as React from 'react';
450+
let i = 0
451+
setInterval(() => {
452+
i++
453+
throw Error('no ' + i)
454+
}, 1000)
455+
export default function FunctionNamed() {
456+
return <div />
457+
}
458+
`
459+
)
460+
461+
await new Promise(resolve => setTimeout(resolve, 1000))
462+
expect(await session.hasRedbox(true)).toBe(true)
463+
expect(await session.getRedboxSource()).toMatchInlineSnapshot(`
464+
"index.js (6:14) @ eval
465+
466+
4 | setInterval(() => {
467+
5 | i++
468+
> 6 | throw Error('no ' + i)
469+
| ^
470+
7 | }, 1000)
471+
8 | export default function FunctionNamed() {
472+
9 | return <div />"
473+
`)
474+
475+
// Make a syntax error.
476+
await session.patch(
477+
'index.js',
478+
`
479+
import * as React from 'react';
480+
let i = 0
481+
setInterval(() => {
482+
i++
483+
throw Error('no ' + i)
484+
}, 1000)
485+
export default function FunctionNamed() {
486+
`
487+
)
488+
489+
await new Promise(resolve => setTimeout(resolve, 1000))
490+
expect(await session.hasRedbox(true)).toBe(true)
491+
expect(await session.getRedboxSource()).toMatch('SyntaxError')
492+
493+
// Test that runtime error does not take over:
494+
await new Promise(resolve => setTimeout(resolve, 2000))
495+
expect(await session.hasRedbox(true)).toBe(true)
496+
expect(await session.getRedboxSource()).toMatch('SyntaxError')
497+
498+
await cleanup()
499+
})
500+
501+
// https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/3#issuecomment-554152127
502+
test('boundaries', async () => {
503+
const [session, cleanup] = await sandbox()
504+
505+
await session.write(
506+
'FunctionDefault.js',
507+
`
508+
export default function FunctionDefault() {
509+
return <h2>hello</h2>
510+
}
511+
`
512+
)
513+
await session.patch(
514+
'index.js',
515+
`
516+
import FunctionDefault from './FunctionDefault.js'
517+
class ErrorBoundary extends React.Component {
518+
constructor() {
519+
super()
520+
this.state = { hasError: false, error: null };
521+
}
522+
static getDerivedStateFromError(error) {
523+
return {
524+
hasError: true,
525+
error
526+
};
527+
}
528+
render() {
529+
if (this.state.hasError) {
530+
return this.props.fallback;
531+
}
532+
return this.props.children;
533+
}
534+
}
535+
function App() {
536+
return (
537+
<ErrorBoundary fallback={<h2>error</h2>}>
538+
<FunctionDefault />
539+
</ErrorBoundary>
540+
);
541+
}
542+
export default App;
543+
`
544+
)
545+
546+
expect(
547+
await session.evaluate(() => document.querySelector('h2').textContent)
548+
).toBe('hello')
549+
550+
await session.write(
551+
'FunctionDefault.js',
552+
`export default function FunctionDefault() { throw new Error('no'); }`
553+
)
554+
555+
expect(await session.hasRedbox(true)).toBe(true)
556+
expect(await session.getRedboxSource()).toMatchInlineSnapshot(`
557+
"FunctionDefault.js (1:50) @ FunctionDefault
558+
559+
> 1 | export default function FunctionDefault() { throw new Error('no'); }
560+
| ^"
561+
`)
562+
expect(
563+
await session.evaluate(() => document.querySelector('h2').textContent)
564+
).toBe('error')
565+
566+
await cleanup()
567+
})

0 commit comments

Comments
 (0)