Skip to content

Commit

Permalink
Add debug logging for propTypes on lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Tschui committed May 6, 2019
1 parent 7b8ea43 commit 8677fa7
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
16 changes: 16 additions & 0 deletions debug/src/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ export function initDebug() {

// Check prop-types if available
if (typeof vnode.type==='function' && vnode.type.propTypes) {
if (vnode.type.name === 'Lazy') {
const m = 'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
try {
const lazied = vnode.type();
console.warn(m + 'Component wrapped in lazy() is ' + lazied.then.displayName || lazied.then.name);
}
catch (promise) {
console.warn(m + 'We will log the wrapped component\'s name once it is loaded.');
if (promise.then) {
promise.then((exports) => {
console.warn('Component wrapped in lazy() is ' + (exports.default.displayName || exports.default.name));
});
}

}
}
checkPropTypes(vnode.type.propTypes, vnode.props, getDisplayName(vnode), serializeVNode(vnode));
}

Expand Down
52 changes: 50 additions & 2 deletions debug/test/browser/debug.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createElement as h, options, render, createRef, Component, Fragment } from 'preact';
import { createElement as h, options, render, createRef, Component, Fragment, lazy, Suspense } from 'preact';
import { useState, useEffect, useLayoutEffect, useMemo, useCallback } from 'preact/hooks';
import { act } from 'preact/test-utils';
import { act, setupRerender } from 'preact/test-utils';
import { setupScratch, teardown, clearOptions, serializeHtml } from '../../../test/_util/helpers';
import { serializeVNode, initDebug } from '../../src/debug';
import * as PropTypes from 'prop-types';
Expand Down Expand Up @@ -392,5 +392,53 @@ describe('debug', () => {
render(<Bar text="foo" />, scratch);
expect(console.error).to.not.be.called;
});

it('should validate propTypes inside lazy()', () => {
const rerender = setupRerender();

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);

render(
<Suspense fallback={<div>fallback...</div>}>
<LazyBaz unhappy="signal" />
</Suspense>,
scratch
);

expect(console.error).to.not.be.called;

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>');
});
});

it('should warn for PropTypes on lazy()', () => {
const loader = Promise.resolve({ default: function MyLazyLoadedComponent() { return <div>Hi there</div> } });
const FakeLazy = lazy(() => loader);
FakeLazy.propTypes = {};
render(
<Suspense fallback={<div>fallback...</div>} >
<FakeLazy />
</Suspense>,
scratch
);
return loader.then(() => {
expect(console.warn).to.be.calledTwice;
expect(warnings[1].includes('MyLazyLoadedComponent')).to.equal(true);
});
});
});
});

0 comments on commit 8677fa7

Please sign in to comment.