Skip to content

Commit a90a845

Browse files
eps1lonljharb
authored andcommitted
[enzyme-adapter-react-16] [new] Add support for wrapping Profiler
1 parent 970779f commit a90a845

File tree

4 files changed

+239
-0
lines changed

4 files changed

+239
-0
lines changed

packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ function toTree(vnode) {
216216
case FiberTags.ContextProvider:
217217
case FiberTags.ContextConsumer:
218218
return childrenToTree(node.child);
219+
case FiberTags.Profiler:
219220
case FiberTags.ForwardRef: {
220221
return {
221222
nodeType: 'function',

packages/enzyme-adapter-react-16/src/detectFiberTags.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = function detectFiberTags() {
1919
const supportsContext = typeof React.createContext !== 'undefined';
2020
const supportsForwardRef = typeof React.forwardRef !== 'undefined';
2121
const supportsMemo = typeof React.memo !== 'undefined';
22+
const supportsProfiler = typeof React.unstable_Profiler !== 'undefined';
2223

2324
function Fn() {
2425
return null;
@@ -66,5 +67,8 @@ module.exports = function detectFiberTags() {
6667
ForwardRef: supportsForwardRef
6768
? getFiber(React.createElement(FwdRef)).tag
6869
: -1,
70+
Profiler: supportsProfiler
71+
? getFiber(React.createElement(React.unstable_Profiler, { id: 'mock', onRender: () => {} })).tag
72+
: -1,
6973
};
7074
};

packages/enzyme-test-suite/test/ReactWrapper-spec.jsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
Fragment,
2525
forwardRef,
2626
memo,
27+
Profiler,
2728
PureComponent,
2829
useEffect,
2930
useState,
@@ -844,6 +845,122 @@ describeWithDOM('mount', () => {
844845
});
845846
});
846847

848+
describeIf(is('>= 16.4'), 'Profiler', () => {
849+
function SomeComponent() {
850+
return (
851+
<Profiler id="SomeComponent" onRender={() => {}}>
852+
<main>
853+
<div className="child" />
854+
</main>
855+
</Profiler>
856+
);
857+
}
858+
859+
wrap()
860+
.withConsoleThrows()
861+
.it('mounts without complaint', () => {
862+
expect(() => mount(<SomeComponent />)).not.to.throw();
863+
});
864+
865+
it('renders', () => {
866+
const wrapper = mount(<SomeComponent />);
867+
expect(wrapper.debug()).to.equal(`<SomeComponent>
868+
<Profiler id="SomeComponent" onRender={[Function: onRender]}>
869+
<main>
870+
<div className="child" />
871+
</main>
872+
</Profiler>
873+
</SomeComponent>`);
874+
});
875+
876+
it('finds elements through Profiler elements', () => {
877+
const wrapper = mount(<SomeComponent />);
878+
879+
expect(wrapper.find('.child')).to.have.lengthOf(1);
880+
});
881+
882+
it('finds Profiler element', () => {
883+
const Parent = () => <span><SomeComponent foo="hello" /></span>;
884+
885+
const wrapper = mount(<Parent foo="hello" />);
886+
const results = wrapper.find(SomeComponent);
887+
888+
expect(results).to.have.lengthOf(1);
889+
expect(results.type()).to.equal(SomeComponent);
890+
expect(results.props()).to.eql({ foo: 'hello' });
891+
});
892+
893+
it('can find Profiler by id', () => {
894+
const wrapper = mount(<SomeComponent />);
895+
expect(wrapper.find('[id="SomeComponent"]').exists()).to.equal(true);
896+
});
897+
898+
it('can find Profiler by display name', () => {
899+
const wrapper = mount(<SomeComponent />);
900+
const profiler = wrapper.find('Profiler');
901+
expect(profiler).to.have.lengthOf(1);
902+
expect(profiler.type()).to.equal(Profiler);
903+
});
904+
905+
it('recognizes render phases', () => {
906+
const handleRender = sinon.spy();
907+
function AnotherComponent() {
908+
return (
909+
<Profiler id="AnotherComponent" onRender={handleRender}>
910+
<div />
911+
</Profiler>
912+
);
913+
}
914+
915+
const wrapper = mount(<AnotherComponent />);
916+
expect(handleRender).to.have.property('callCount', 1);
917+
expect(handleRender.args[0][1]).to.equal('mount');
918+
919+
wrapper.setProps({ unusedProp: true });
920+
expect(handleRender).to.have.property('callCount', 2);
921+
expect(handleRender.args[1][1]).to.equal('update');
922+
});
923+
924+
it('measures timings', () => {
925+
/**
926+
* test environment has no access to the performance API at which point
927+
* the profiling API has to fallback to Date.now() which isn't precise enough
928+
* which results in 0 duration for these simple examples most of the time.
929+
* With performance API it should test for greaterThan(0) instead of least(0)
930+
*/
931+
const handleRender = sinon.spy();
932+
function AnotherComponent() {
933+
return (
934+
<Profiler id="AnotherComponent" onRender={handleRender}>
935+
<div />
936+
</Profiler>
937+
);
938+
}
939+
940+
const wrapper = mount(<AnotherComponent />);
941+
expect(handleRender).to.have.property('callCount', 1);
942+
const [firstArgs] = handleRender.args;
943+
if (typeof performance === 'undefined') {
944+
expect(firstArgs[2]).to.be.least(0);
945+
expect(firstArgs[3]).to.be.least(0);
946+
} else {
947+
expect(firstArgs[2]).to.be.greaterThan(0);
948+
expect(firstArgs[3]).to.be.greaterThan(0);
949+
}
950+
951+
wrapper.setProps({ unusedProp: true });
952+
expect(handleRender).to.have.property('callCount', 2);
953+
const [, secondArgs] = handleRender.args;
954+
if (typeof performance === 'undefined') {
955+
expect(secondArgs[2]).to.be.least(0);
956+
expect(secondArgs[3]).to.be.least(0);
957+
} else {
958+
expect(secondArgs[2]).to.be.greaterThan(0);
959+
expect(secondArgs[3]).to.be.greaterThan(0);
960+
}
961+
});
962+
});
963+
847964
describeIf(is('>= 16.8'), 'hooks', () => {
848965
it('works with `useEffect`', (done) => {
849966
function ComponentUsingEffectHook() {

packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
PureComponent,
2626
useEffect,
2727
useState,
28+
Profiler,
2829
} from './_helpers/react-compat';
2930
import {
3031
describeIf,
@@ -1007,6 +1008,122 @@ describe('shallow', () => {
10071008
});
10081009
});
10091010

1011+
describeIf(is('>= 16.4'), 'Profiler', () => {
1012+
function SomeComponent() {
1013+
return (
1014+
<Profiler id="SomeComponent" onRender={() => {}}>
1015+
<main>
1016+
<div className="child" />
1017+
</main>
1018+
</Profiler>
1019+
);
1020+
}
1021+
1022+
wrap()
1023+
.withConsoleThrows()
1024+
.it('mounts without complaint', () => {
1025+
expect(() => shallow(<SomeComponent />)).not.to.throw();
1026+
});
1027+
1028+
it('renders', () => {
1029+
const wrapper = shallow(<SomeComponent />);
1030+
expect(wrapper.debug()).to.equal(`<Profiler id="SomeComponent" onRender={[Function: onRender]}>
1031+
<main>
1032+
<div className="child" />
1033+
</main>
1034+
</Profiler>`);
1035+
});
1036+
1037+
it('finds elements through Profiler elements', () => {
1038+
const wrapper = shallow(<SomeComponent />);
1039+
1040+
expect(wrapper.find('.child')).to.have.lengthOf(1);
1041+
});
1042+
1043+
it('finds Profiler element', () => {
1044+
const Parent = () => <span><SomeComponent foo="hello" /></span>;
1045+
1046+
const wrapper = shallow(<Parent foo="hello" />);
1047+
const results = wrapper.find(SomeComponent);
1048+
1049+
expect(results).to.have.lengthOf(1);
1050+
expect(results.type()).to.equal(SomeComponent);
1051+
expect(results.props()).to.eql({ foo: 'hello' });
1052+
});
1053+
1054+
it('can find Profiler by id', () => {
1055+
const wrapper = shallow(<SomeComponent />);
1056+
expect(wrapper.find('[id="SomeComponent"]').exists()).to.equal(true);
1057+
});
1058+
1059+
it('can find Profiler by display name', () => {
1060+
const wrapper = shallow(<SomeComponent />);
1061+
const profiler = wrapper.find('Profiler');
1062+
expect(profiler).to.have.lengthOf(1);
1063+
expect(profiler.type()).to.equal(Profiler);
1064+
});
1065+
1066+
// TODO: enable when Profiler is no longer unstable
1067+
it.skip('recognizes render phases', () => {
1068+
const handleRender = sinon.spy();
1069+
function AnotherComponent() {
1070+
return (
1071+
<Profiler id="AnotherComponent" onRender={handleRender}>
1072+
<div />
1073+
</Profiler>
1074+
);
1075+
}
1076+
1077+
const wrapper = shallow(<AnotherComponent />);
1078+
expect(handleRender).to.have.property('callCount', 1);
1079+
expect(handleRender.args[0][1]).to.equal('mount');
1080+
1081+
wrapper.setProps({ unusedProp: true });
1082+
expect(handleRender).to.have.property('callCount', 2);
1083+
expect(handleRender.args[1][1]).to.equal('update');
1084+
});
1085+
1086+
// TODO: enable when Profiler is no longer unstable
1087+
it.skip('measures timings', () => {
1088+
/**
1089+
* test environment has no access to the performance API at which point
1090+
* the profiling API has to fallback to Date.now() which isn't precise enough
1091+
* which results in 0 duration for these simple examples most of the time.
1092+
* With performance API it should test for greaterThan(0) instead of least(0)
1093+
*/
1094+
const handleRender = sinon.spy();
1095+
function AnotherComponent() {
1096+
return (
1097+
<Profiler id="AnotherComponent" onRender={handleRender}>
1098+
<div />
1099+
</Profiler>
1100+
);
1101+
}
1102+
1103+
const wrapper = shallow(<AnotherComponent />);
1104+
expect(handleRender).to.have.property('callCount', 1);
1105+
const [firstArgs] = handleRender.args;
1106+
if (typeof performance === 'undefined') {
1107+
expect(firstArgs[2]).to.be.least(0);
1108+
expect(firstArgs[3]).to.be.least(0);
1109+
} else {
1110+
expect(firstArgs[2]).to.be.greaterThan(0);
1111+
expect(firstArgs[3]).to.be.greaterThan(0);
1112+
}
1113+
1114+
wrapper.setProps({ unusedProp: true });
1115+
expect(handleRender).to.have.property('callCount', 2);
1116+
const [, secondArgs] = handleRender.args;
1117+
if (typeof performance === 'undefined') {
1118+
expect(secondArgs[2]).to.be.least(0);
1119+
expect(secondArgs[3]).to.be.least(0);
1120+
} else {
1121+
expect(secondArgs[2]).to.be.greaterThan(0);
1122+
expect(secondArgs[3]).to.be.greaterThan(0);
1123+
}
1124+
});
1125+
});
1126+
10101127
describeIf(is('>= 16.8.5'), 'hooks', () => {
10111128
// TODO: enable when the shallow renderer fixes its bug
10121129
it.skip('works with `useEffect`', (done) => {

0 commit comments

Comments
 (0)