Skip to content
This repository has been archived by the owner on Feb 3, 2021. It is now read-only.

Commit

Permalink
support hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Edgar committed Apr 10, 2019
1 parent f297112 commit 313d1c8
Show file tree
Hide file tree
Showing 10 changed files with 8,682 additions and 80 deletions.
8,432 changes: 8,432 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
"@babel/preset-env": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"babel-jest": "^24.1.0",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.10.0",
"jest": "^24.1.0",
"react": "^16.8.0",
"react-dom": "^16.8.0"
"react-dom": "^16.8.0",
"react-testing-library": "^6.1.2"
},
"main": "build/index.js",
"scripts": {
Expand Down
51 changes: 51 additions & 0 deletions src/Comparator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class Comparator {
constructor(logger) {
this._renderCount = 0;

this._prevProps = null;
this._prevState = null;

this._logger = logger;
}

processChanges(nextProps, nextState) {
const isFirstRender = !this._renderCount;
if (isFirstRender) {
this._logger.printInit();
} else {
const propsChanges = this._shallowCompare(this._prevProps, nextProps);
const stateChanges = this._shallowCompare(this._prevState, nextState);

this._logger.printComparisonsResults(propsChanges, stateChanges);
}

this._renderCount += 1;
this._prevState = nextState;
this._prevProps = nextProps;
}

_shallowCompare(oldObj = {}, nextObj = {}) {
if (!nextObj || !oldObj || oldObj === nextObj) {
return [];
}

let difference = [];

Object.keys(nextObj).forEach(key => {
if (nextObj[key] !== oldObj[key]) {
const type = typeof nextObj[key];

difference.push({
key,
type,
oldValue: oldObj[key],
nextValue: nextObj[key],
});
}
});

return difference;
}
}

export default Comparator;
12 changes: 8 additions & 4 deletions src/__tests__/components/Checkbox.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

export default class Checkbox extends React.Component {
class Checkbox extends React.Component {
constructor(props) {
super(props);
this.state = { isChecked: false };
Expand All @@ -13,18 +13,22 @@ export default class Checkbox extends React.Component {
}

render() {
const { label } = this.props;
const { title, description } = this.props;

return (
<div>
<input
type="checkbox"
data-testid="checkbox"
checked={this.state.isChecked}
onChange={this.onChange}
/>
<label>{this.state.isChecked ? 'On' : 'Off'}</label>
<span>{label}</span>
<label data-testid="state-isChecked">{this.state.isChecked ? '1' : '0'}</label>
<span data-testid="props-title">{title}</span>
<span>{description}</span>
</div>
);
}
}

export default Checkbox;
7 changes: 4 additions & 3 deletions src/__tests__/components/Counter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import React, { useState } from 'react';
export default function Counter(props) {
const [count, setCount] = useState(0);

const { label } = props;
const { title, description } = props;

return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
<label>{label}</label>
<button onClick={() => setCount(count + 1)} data-testid="button">{count}</button>
<span data-testid="props-title">{title}</span>
<span>{description}</span>
</div>
);
}
26 changes: 26 additions & 0 deletions src/__tests__/components/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

class Input extends React.Component {
constructor(props) {
super(props);
}

render() {
const { value, onChange, title, description } = this.props;

return (
<div>
<input
type="text"
data-testid="text"
value={value}
onChange={onChange}
/>
<span data-testid="props-title">{title}</span>
<span>{description}</span>
</div>
);
}
}

export default Input;
142 changes: 118 additions & 24 deletions src/__tests__/patch.spec.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,143 @@
import React from 'react';
import Enzyme, { shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });
import { render, fireEvent, cleanup } from 'react-testing-library'

// React class component with state
import Checkbox from './components/Checkbox';
// React class component without state
import Input from './components/Input';
// React function component, with hooks
import Counter from './components/Counter';

import Comparator from '../Comparator';

import patch from '../patch';

const noop = () => {};
const defaultProps = {
title: "ping",
description: "text",
}

beforeEach(() => {

});

const fakeLogger = {
log: noop,
group: noop,
groupCollapsed: noop,
groupEnd: noop,
};
afterEach(() => {
cleanup();
});

it('patched checkbox working', () => {
test('Checkbox, detect changed state', () => {
// Arrange
const PatchedCheckbox = patch(Checkbox, 'test-name', fakeLogger);
const fakeLogger = {
printInit: jest.fn(),
printComparisonsResults: jest.fn(),
};
const comparator = new Comparator(fakeLogger);
const PatchedCheckbox = patch(Checkbox, comparator);

// Act
const { getByTestId } = render(<PatchedCheckbox {...defaultProps} />);

const checkbox = shallow(<PatchedCheckbox label="ping" />);
fireEvent.click(getByTestId('checkbox'));

// Assert
expect(fakeLogger.printInit.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual(
[[], [{"key": "isChecked", "nextValue": true, "oldValue": false, "type": "boolean"}]]
);
expect(getByTestId('state-isChecked').textContent).toBe('1');
});

test('Checkbox, detect changed props', () => {
// Arrange
const fakeLogger = {
printInit: jest.fn(),
printComparisonsResults: jest.fn(),
};
const comparator = new Comparator(fakeLogger);
const PatchedCheckbox = patch(Checkbox, comparator);

// Act
checkbox.find('input').simulate('change');
checkbox.setProps({ label: 'pong' });
const { rerender, getByTestId } = render(<PatchedCheckbox {...defaultProps} />);

rerender(<PatchedCheckbox {...defaultProps} title='pong' />);

// Assert
expect(checkbox.find('label').text()).toEqual('On');
expect(checkbox.find('span').text()).toEqual('pong');
expect(fakeLogger.printInit.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual(
[[{"key":"title","type":"string","oldValue":"ping","nextValue":"pong"}],[]]
);

expect(getByTestId('props-title').textContent).toBe('pong');
});

it('patched counter working', () => {
test('Counter, detect changed props re-render', () => {
// Arrange
// const PatchedCounter = patch(Counter, 'test-name', console);
const fakeLogger = {
printInit: jest.fn(),
printComparisonsResults: jest.fn(),
};
const comparator = new Comparator(fakeLogger);
const PatchedCounter= patch(Counter, comparator);

const counter = mount(<Counter label="ping" />);
// Act
const { rerender, getByTestId } = render(<PatchedCounter {...defaultProps} />);

rerender(<PatchedCounter {...defaultProps} title='pong' />);

// Assert
expect(fakeLogger.printInit.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual(
[[{"key":"title","type":"string","oldValue":"ping","nextValue":"pong"}],[]]
);
expect(getByTestId('props-title').textContent).toBe('pong');
});

test('Counter, used hooks', () => {
// Arrange
const fakeLogger = {
printInit: jest.fn(),
printComparisonsResults: jest.fn(),
};
const comparator = new Comparator(fakeLogger);
const PatchedCounter= patch(Counter, comparator);

// Act
counter.setProps({ label: 'pong' });
counter.find('button').simulate('click');
const { rerender, getByTestId } = render(<PatchedCounter {...defaultProps} />);

fireEvent.click(getByTestId('button'));

// Assert
expect(counter.find('label').text()).toEqual('pong');
expect(counter.find('button').text()).toEqual('1');
expect(fakeLogger.printInit.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1);
});

test('Input, detect changed props re-render', () => {
// Arrange
const fakeLogger = {
printInit: jest.fn(),
printComparisonsResults: jest.fn(),
};
const comparator = new Comparator(fakeLogger);
const PatchedInput= patch(Input, comparator);

const inputDefaultProps = {
...defaultProps,
value: "",
onChange: () => {},
}
// Act
const { rerender, getByTestId } = render(<PatchedInput {...inputDefaultProps} />);

rerender(<PatchedInput {...inputDefaultProps} value='i type ...' />);

// Assert
expect(fakeLogger.printInit.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1);
expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual(
[[{"key":"value","type":"string","oldValue":"","nextValue":"i type ..."}],[]]
);
});
16 changes: 11 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import patch from './patch';

import Logger from './Logger';
import Comparator from './Comparator';

export default (...args) => {
if (args.length > 2) {
console.error('[clear-render] Error: Too many arguments');
Expand All @@ -14,19 +17,19 @@ export default (...args) => {
let ComponentClass = null;
let forcedDisplayedName = null;

args.forEach(arg => {
const type = typeof arg;
args.forEach(argument => {
const type = typeof argument;

switch (type) {
case 'symbol':
case 'string':
{
forcedDisplayedName = arg;
forcedDisplayedName = argument;
}
break;
default:
{
ComponentClass = arg;
ComponentClass = argument;
}
break;
}
Expand All @@ -39,5 +42,8 @@ export default (...args) => {

const name = forcedDisplayedName || ComponentClass.name;

return patch(ComponentClass, name, console);
const logger = new Logger(name, console);
const comparator = new Comparator(logger);

return patch(ComponentClass, comparator);
};
Loading

0 comments on commit 313d1c8

Please sign in to comment.