/
githubmirror
/
preact
Обзор
Документация
Войти
/
githubmirror
/
preact
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
debug/test/browser/debug-suspense.test.jsx
189 строк
5 KB
Ryan Christian
test: Switch tests to use `.jsx` file extension (#4925)
29 сен 2025, 16:58
Не верифицирован
29 сен 2025, 16:58
8e3e4ce
Код
Авторство
О чём код?
import { createElement, render, lazy, Suspense } from 'preact/compat'; import 'preact/debug'; import { setupRerender } from 'preact/test-utils'; import { setupScratch, teardown, serializeHtml } from '../../../test/_util/helpers'; import { vi } from 'vitest'; describe('debug with suspense', () => { /** @type {HTMLDivElement} */ let scratch; let rerender; let errors = []; let warnings = []; beforeEach(() => { errors = []; warnings = []; scratch = setupScratch(); rerender = setupRerender(); vi.spyOn(console, 'error').mockImplementation(e => errors.push(e)); vi.spyOn(console, 'warn').mockImplementation(w => warnings.push(w)); }); afterEach(() => { console.error.mockRestore(); console.warn.mockRestore(); teardown(scratch); }); it('should throw on missing <Suspense>', () => { function Foo() { throw Promise.resolve(); } expect(() => render(<Foo />, scratch)).to.throw; }); it('should throw an error when using lazy and missing Suspense', () => { const Foo = () => <div>Foo</div>; const LazyComp = lazy( () => new Promise(resolve => resolve({ default: Foo })) ); const fn = () => { render(<LazyComp />, scratch); }; expect(fn).to.throw(/Missing Suspense/gi); }); describe('PropTypes', () => { it('should validate propTypes inside lazy()', () => { function Baz(props) { return <h1>{props.unhappy}</h1>; } Baz.propTypes = { unhappy: function alwaysThrows(obj, key) { if (obj[key] === 'signal') throw Error('got prop inside lazy()'); } }; const loader = Promise.resolve({ default: Baz }); const LazyBaz = lazy(() => loader); const suspense = ( <Suspense fallback={<div>fallback...</div>}> <LazyBaz unhappy="signal" /> </Suspense> ); render(suspense, scratch); rerender(); // render fallback expect(console.error).not.toHaveBeenCalled(); expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>'); return loader.then(() => { rerender(); expect(errors.length).to.equal(1); expect(errors[0].includes('got prop')).to.equal(true); expect(serializeHtml(scratch)).to.equal('<h1>signal</h1>'); }); }); describe('warn for PropTypes on lazy()', () => { it('should log the function name', () => { const loader = Promise.resolve({ default: function MyLazyLoaded() { return <div>Hi there</div>; } }); const FakeLazy = lazy(() => loader); FakeLazy.propTypes = {}; const suspense = ( <Suspense fallback={<div>fallback...</div>}> <FakeLazy /> </Suspense> ); render(suspense, scratch); rerender(); // Render fallback expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>'); return loader.then(() => { rerender(); expect(console.warn).toHaveBeenCalledTimes(2); expect(warnings[1].includes('MyLazyLoaded')).to.equal(true); expect(serializeHtml(scratch)).to.equal('<div>Hi there</div>'); }); }); it('should log the displayName', () => { function MyLazyLoadedComponent() { return <div>Hi there</div>; } MyLazyLoadedComponent.displayName = 'HelloLazy'; const loader = Promise.resolve({ default: MyLazyLoadedComponent }); const FakeLazy = lazy(() => loader); FakeLazy.propTypes = {}; const suspense = ( <Suspense fallback={<div>fallback...</div>}> <FakeLazy /> </Suspense> ); render(suspense, scratch); rerender(); // Render fallback expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>'); return loader.then(() => { rerender(); expect(console.warn).toHaveBeenCalledTimes(2); expect(warnings[1].includes('HelloLazy')).to.equal(true); expect(serializeHtml(scratch)).to.equal('<div>Hi there</div>'); }); }); it("should not log a component if lazy loader's Promise rejects", () => { const loader = Promise.reject(new Error('Hey there')); const FakeLazy = lazy(() => loader); FakeLazy.propTypes = {}; render( <Suspense fallback={<div>fallback...</div>}> <FakeLazy /> </Suspense>, scratch ); rerender(); // Render fallback expect(serializeHtml(scratch)).to.equal('<div>fallback...</div>'); return loader.catch(() => { try { rerender(); } catch (e) { // Ignore the loader's bubbling error } // Called once on initial render, and again when promise rejects expect(console.warn).toHaveBeenCalledTimes(2); }); }); it("should not log a component if lazy's loader throws", () => { const FakeLazy = lazy(() => { throw new Error('Hello'); }); FakeLazy.propTypes = {}; let error; try { render( <Suspense fallback={<div>fallback...</div>}> <FakeLazy /> </Suspense>, scratch ); } catch (e) { error = e; } expect(console.warn).toHaveBeenCalledOnce(); expect(error).not.to.be.undefined; expect(error.message).to.eql('Hello'); }); }); }); });