Skip to content

Commit

Permalink
Test-util: Fix issue where text nodes caused crash when renderingVNod…
Browse files Browse the repository at this point in the history
…eToSnapshot Github infernojs#1404
  • Loading branch information
Havunen committed Oct 29, 2018
1 parent 61960b5 commit 5ae9461
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ Array [
]
`;

exports[`Snapshots JSX Should not fail when returning children array from component root, which contains text node. Github #1404 1`] = `
Array [
<label />,
<span>
o
</span>,
<span>
k
</span>,
"asd",
"1",
]
`;

exports[`Snapshots JSX Should render attributes and className 1`] = `
<div
className="Testing"
Expand Down
67 changes: 34 additions & 33 deletions packages/inferno-test-utils/__tests__/snapshots.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ describe('Snapshots', () => {
});

it('Should render fragment root', () => {
debugger;

expect(
renderToSnapshot(
<Fragment>
Expand All @@ -118,7 +116,7 @@ describe('Snapshots', () => {
it('Should render fragment from component root', () => {
class Comp extends Component {
render() {
return <>{this.props.children}</>
return <>{this.props.children}</>;
}
}

Expand All @@ -128,31 +126,43 @@ describe('Snapshots', () => {
<div>1</div>
</Comp>
)
).toMatchSnapshot()
).toMatchSnapshot();
});

it('Should not fail when returning children array from component root, which contains text node. Github #1404', () => {
const Label = ({ label, htmlFor, children, optional = false, ...props }) => {
if (optional && !label) {
return children;
}
return (
<>
<label {...props} htmlFor={htmlFor}>
{label}
</label>
{children}
</>
);
};
expect(renderToSnapshot(<Label>{[<span>o</span>, <span>k</span>, 'asd', 1, null, false, true, void 0]}</Label>)).toMatchSnapshot();
});

it('Should not fail when returning children array from component root, Github #1404', () => {
const Label = ({label, htmlFor, children, optional = false, ...props}) => {
if(optional && !label) {
const Label = ({ label, htmlFor, children, optional = false, ...props }) => {
if (optional && !label) {
return children;
}

return <>
<label {...props} htmlFor={htmlFor}>{label}</label>
{children}
</>;
return (
<>
<label {...props} htmlFor={htmlFor}>
{label}
</label>
{children}
</>
);
};

expect(
renderToSnapshot(
<Label>
{[
<span>o</span>,
<span>k</span>
]}
</Label>
)
).toMatchSnapshot();
expect(renderToSnapshot(<Label>{[<span>o</span>, <span>k</span>]}</Label>)).toMatchSnapshot();
});

it('Should flush setStates before building snapshot', () => {
Expand All @@ -168,7 +178,7 @@ describe('Snapshots', () => {
componentDidMount() {
this.setState({
foo: '##BAR##'
})
});
}

render() {
Expand All @@ -179,12 +189,7 @@ describe('Snapshots', () => {
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
{this.state.foo}
</a>
</header>
Expand All @@ -193,12 +198,8 @@ describe('Snapshots', () => {
}
}

expect(
renderToSnapshot(
<App/>
)
).toMatchSnapshot();
})
expect(renderToSnapshot(<App />)).toMatchSnapshot();
});
}
});
});
10 changes: 7 additions & 3 deletions packages/inferno-test-utils/src/jest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, VNode, rerender } from 'inferno';
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { isArray, isNullOrUndef } from 'inferno-shared';
import { isArray, isNullOrUndef, isObject } from 'inferno-shared';
import { getTagNameOfVNode } from './utils';

// Jest Snapshot Utilities
Expand Down Expand Up @@ -90,9 +90,13 @@ export function renderToSnapshot(input: VNode) {

if (isArray(snapshot)) {
for (let i = 0; i < snapshot.length; i++) {
delete snapshot[i].props.children;
const _snapshot = snapshot[i];

if (typeof _snapshot === 'object' && _snapshot.props) {
delete _snapshot.props.children;
}
}
} else {
} else if (typeof snapshot === 'object' && snapshot.props) {
delete snapshot.props.children;
}

Expand Down
61 changes: 28 additions & 33 deletions packages/inferno/__tests__/lifecycle.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,16 +256,12 @@ describe('ComponentDidUpdate', () => {

testHack.callback = () => {
callbackCalled++;
this.setState({a: 112});
}
this.setState({ a: 112 });
};
}

render() {
return (
<div>
A
</div>
);
return <div>A</div>;
}
}

Expand All @@ -279,22 +275,21 @@ describe('ComponentDidUpdate', () => {
}

componentWillMount() {
this.setState({
foo: 'bar'
}, function () {
setState1Called++;
expect(this.state.foo).toBe('bar');
});
this.setState(
{
foo: 'bar'
},
function() {
setState1Called++;
expect(this.state.foo).toBe('bar');
}
);

testHack.callback();
}

render() {
return (
<div>
Tester One
</div>
)
return <div>Tester One</div>;
}
}

Expand All @@ -310,38 +305,38 @@ describe('ComponentDidUpdate', () => {
}

_handleClick() {
this.setState({
bool: true
}, function () {
setState2Called++;
expect(this.state.bool).toBe(true);
})
this.setState(
{
bool: true
},
function() {
setState2Called++;
expect(this.state.bool).toBe(true);
}
);
}

render() {
return (
<div id="tester" onClick={this._handleClick}>
{this.state.bool ? (
<TesterOne/>
) : <span/>}
{this.state.bool ? <TesterOne /> : <span />}
</div>
)
);
}
}

class App extends Component {
render() {
return (
<div>
<Outsider/>
<Another/>
<Outsider />
<Another />
</div>
)
);
}
}

render(<App/>, container);

render(<App />, container);

expect(callbackCalled).toBe(0);
expect(setState1Called).toBe(0);
Expand Down
34 changes: 21 additions & 13 deletions packages/inferno/src/DOM/patching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,7 @@ import { directClone } from '../core/implementation';
import { VNode } from '../core/types';
import { mount, mountArrayChildren, mountTextContent } from './mounting';
import { clearDOM, remove, removeAllChildren, unmount, unmountAllChildren } from './unmounting';
import {
appendChild,
createDerivedState,
EMPTY_OBJ,
findDOMfromVNode,
moveVNodeDOM,
options,
removeChild,
removeVNodeDOM,
replaceChild
} from './utils/common';
import { appendChild, createDerivedState, EMPTY_OBJ, findDOMfromVNode, moveVNodeDOM, options, removeChild, removeVNodeDOM, replaceChild } from './utils/common';
import { isControlledFormElement, processElement } from './wrappers/processElement';
import { patchProp } from './props';
import { handleComponentInput, renderNewInput } from './utils/componentutil';
Expand All @@ -35,7 +25,15 @@ function replaceWithNewNode(lastVNode, nextVNode, parentDOM: Element, context: O
}
}

export function patch(lastVNode: VNode, nextVNode: VNode, parentDOM: Element, context: Object, isSVG: boolean, nextNode: Element | null, lifecycle: Function[]) {
export function patch(
lastVNode: VNode,
nextVNode: VNode,
parentDOM: Element,
context: Object,
isSVG: boolean,
nextNode: Element | null,
lifecycle: Function[]
) {
const nextFlags = (nextVNode.flags |= VNodeFlags.InUse);

if (process.env.NODE_ENV !== 'production') {
Expand Down Expand Up @@ -319,7 +317,17 @@ function createDidUpdate(instance, lastProps, lastState, snapshot, lifecycle) {
lifecycle.push(() => instance.componentDidUpdate(lastProps, lastState, snapshot));
}

export function updateClassComponent(instance, nextState, nextProps, parentDOM: Element, context, isSVG: boolean, force: boolean, nextNode: Element | null, lifecycle: Function[]) {
export function updateClassComponent(
instance,
nextState,
nextProps,
parentDOM: Element,
context,
isSVG: boolean,
force: boolean,
nextNode: Element | null,
lifecycle: Function[]
) {
const lastState = instance.state;
const lastProps = instance.props;
const usesNewAPI = Boolean(instance.$N);
Expand Down

0 comments on commit 5ae9461

Please sign in to comment.