Skip to content

Commit

Permalink
- Use @testing-library/dom for testing brahmos
Browse files Browse the repository at this point in the history
- Fixed input event onChange call.
- Fixed nested array rendering issue.
- Fixed attribute setting for tag elements.
- Fixed duplicate method issues in bundle due to separate jsx import.
- Fixed issue with update on tag element
- Call setState callback with same update source.
- Call component lifecycle with Immidiate update source to avoid flicker.
- Return component instance from render method.
- Fixed bug multiple sync update happening together in different component hierarchy
  • Loading branch information
s-yadav committed Dec 6, 2020
1 parent 23fe6a7 commit 203209c
Show file tree
Hide file tree
Showing 27 changed files with 1,159 additions and 128 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,6 +4,7 @@ dist
lib
*.log
reference
.DS_Store

# editor specific files
.vscode
Expand Down
7 changes: 6 additions & 1 deletion jest.config.js
Expand Up @@ -2,5 +2,10 @@ module.exports = {
rootDir: './src',
transform: {
'^.+\\.js$': 'babel-jest',
}
},
moduleNameMapper: {
'^brahmos$': '<rootDir>/index.js',
},
setupFilesAfterEnv: ['<rootDir>/__tests__/jest.setup.js'],
testPathIgnorePatterns: ['jest.setup.js', 'testUtils.js'],
};
19 changes: 11 additions & 8 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "brahmos",
"version": "0.11.0-alpha3",
"version": "0.11.0-alpha5",
"description": "Super charged UI library with modern React API and native templates.",
"main": "dist/brahmos.js",
"module": "dist/brahmos.es.js",
Expand All @@ -10,7 +10,7 @@
"flow": "flow",
"test": "jest",
"test:watch": "jest --watch",
"test:debug": "node --inspect-brk ./node_modules/.bin/jest --runInBand --watch",
"test:debug": "node --inspect-brk ./node_modules/.bin/jest --runInBand --watch --collect-coverage=false",
"test:bundlesize": "yarn bundle && bundlesize",
"start": "webpack-dev-server --open",
"build": "babel src --out-dir lib",
Expand All @@ -35,10 +35,16 @@
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/runtime": "^7.11.2",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-replace": "^2.3.3",
"@testing-library/dom": "^7.26.6",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.3.0",
"babel-loader": "^8.1.0",
"babel-plugin-brahmos": "0.6.0-alpha5",
"babel-plugin-brahmos": "0.6.0-alpha6",
"bulma": "^0.9.0",
"bundlesize": "^0.18.0",
"cross-env": "^7.0.2",
Expand All @@ -56,16 +62,13 @@
"google-closure-compiler": "^20200830.0.0",
"html-webpack-plugin": "^4.4.1",
"jest": "^26.4.2",
"js-beautify": "^1.13.0",
"prettier": "^2.1.2",
"recharts": "^1.8.5",
"rollup": "^2.27.1",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-commonjs": "^15.0.0",
"rollup-plugin-filesize": "^9.0.2",
"rollup-plugin-flow": "^1.1.1",
"@rollup/plugin-json": "^4.1.0",
"rollup-plugin-license": "^2.2.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-replace": "^2.3.3",
"rollup-plugin-terser": "^7.0.2",
"sass": "^1.26.11",
"sass-loader": "^10.0.2",
Expand Down
2 changes: 1 addition & 1 deletion src/TagNode.js
Expand Up @@ -25,7 +25,7 @@ export default function getTagNode(node: BrahmosNode, isSvgPart: boolean): TagNo
};

return {
fragment: domNode,
fragment: [domNode],
domNodes: [domNode],
parts: [nodePart],
};
Expand Down
111 changes: 58 additions & 53 deletions src/__tests__/BrahmosES6class.test.js
@@ -1,8 +1,11 @@
/*
Forked from -
https://github.com/facebook/react/blob/master/packages/react/src/__tests__/ReactES6Class-test.js
TODO: Simplify this specs.
*/
import Brahmos, { render } from '..';
import { sleep } from './testUtils';

describe('BrahmosES6Class', () => {
let container;
Expand All @@ -20,11 +23,11 @@ describe('BrahmosES6Class', () => {
renderedName = null;
container = document.createElement('div');
Inner = class extends Brahmos.Component {
getName () {
getName() {
return this.props.name;
}

render () {
render() {
attachedListenerWithCallback = (callback) => this.props.onClick(callback);
attachedListener = this.props.onClick;
renderedName = this.props.name;
Expand All @@ -33,7 +36,7 @@ describe('BrahmosES6Class', () => {
};
});

function test (element, expectedTag, expectedClassName) {
function test(element, expectedTag, expectedClassName) {
const instance = render(element, container);
expect(container.firstChild).not.toBeNull();
expect(container.firstChild.tagName).toBe(expectedTag);
Expand All @@ -48,7 +51,7 @@ describe('BrahmosES6Class', () => {

it('renders a simple stateless component with prop', () => {
class Foo extends Brahmos.Component {
render () {
render() {
return <Inner name={this.props.bar} />;
}
}
Expand All @@ -58,12 +61,12 @@ describe('BrahmosES6Class', () => {

it('renders based on state using initial values in this.props', () => {
class Foo extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.state = { bar: this.props.initialValue };
}

render () {
render() {
return <span className={this.state.bar} />;
}
}
Expand All @@ -72,16 +75,16 @@ describe('BrahmosES6Class', () => {

it('renders based on state using props in the constructor', () => {
class Foo extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.state = { bar: props.initialValue };
}

changeState () {
changeState() {
this.setState({ bar: 'bar' });
}

render () {
render() {
if (this.state.bar === 'foo') {
return <div className="foo" />;
}
Expand All @@ -97,14 +100,14 @@ describe('BrahmosES6Class', () => {
class Foo extends Brahmos.Component {
state = {};

static getDerivedStateFromProps (nextProps, prevState) {
static getDerivedStateFromProps(nextProps, prevState) {
return {
foo: nextProps.foo,
bar: 'bar',
};
}

render () {
render() {
return <div className={`${this.state.foo} ${this.state.bar}`} />;
}
}
Expand All @@ -118,13 +121,13 @@ describe('BrahmosES6Class', () => {
bar: 'bar',
};

static getDerivedStateFromProps (nextProps, prevState) {
static getDerivedStateFromProps(nextProps, prevState) {
return {
foo: `not-${prevState.foo}`,
};
}

render () {
render() {
return <div className={`${this.state.foo} ${this.state.bar}`} />;
}
}
Expand All @@ -137,7 +140,7 @@ describe('BrahmosES6Class', () => {
value: 'initial',
};

static getDerivedStateFromProps (nextProps, prevState) {
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.update) {
return {
value: 'updated',
Expand All @@ -146,7 +149,7 @@ describe('BrahmosES6Class', () => {
return null;
}

render () {
render() {
return <div className={this.state.value} />;
}
}
Expand All @@ -156,12 +159,12 @@ describe('BrahmosES6Class', () => {

it('should render with null in the initial state property', () => {
class Foo extends Brahmos.Component {
constructor () {
constructor() {
super();
this.state = null;
}

render () {
render() {
return <span />;
}
}
Expand All @@ -170,19 +173,17 @@ describe('BrahmosES6Class', () => {

it('setState through an event handler', () => {
class Foo extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.state = { bar: props.initialValue };
}

handleClick (callback) {
handleClick(callback) {
this.setState({ bar: 'bar' }, () => callback());
}

render () {
return (
<Inner name={this.state.bar} onClick={this.handleClick.bind(this)} />
);
render() {
return <Inner name={this.state.bar} onClick={this.handleClick.bind(this)} />;
}
}
test(<Foo initialValue="foo" />, 'DIV', 'foo');
Expand All @@ -192,16 +193,16 @@ describe('BrahmosES6Class', () => {

it('should not implicitly bind event handlers', () => {
class Foo extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.state = { bar: props.initialValue };
}

handleClick () {
handleClick() {
this.setState({ bar: 'bar' });
}

render () {
render() {
return <Inner name={this.state.bar} onClick={this.handleClick} />;
}
}
Expand All @@ -212,87 +213,91 @@ describe('BrahmosES6Class', () => {
it('will call all the normal life cycle methods', () => {
let lifeCycles = [];
class Foo extends Brahmos.Component {
constructor () {
constructor() {
super();
this.state = {};
}

componentDidMount () {
componentDidMount() {
lifeCycles.push('did-mount');
}

shouldComponentUpdate (nextProps, nextState) {
shouldComponentUpdate(nextProps, nextState) {
lifeCycles.push('should-update', nextProps, nextState);
return true;
}

componentDidUpdate (prevProps, prevState) {
componentDidUpdate(prevProps, prevState) {
lifeCycles.push('did-update', prevProps, prevState);
}

componentWillUnmount () {
componentWillUnmount() {
lifeCycles.push('will-unmount');
}

render () {
render() {
return <span className={this.props.value} />;
}
}
class Outer extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.state = {
isFooVisible: this.props.visible,
};
}

unmountFoo (callback) {
this.setState({
isFooVisible: false,
}, () => callback);
unmountFoo(callback) {
this.setState(
{
isFooVisible: false,
},
() => callback,
);
}

render () {
render() {
if (this.state.isFooVisible) {
return <Foo value={this.props.value}/>;
return <Foo value={this.props.value} />;
}
return <div/>;
return <div />;
}
}
test(<Outer visible value="foo" />, 'SPAN', 'foo');
expect(lifeCycles).toEqual(['did-mount']);
lifeCycles = []; // reset
const instance = test(<Outer visible value="bar" />, 'SPAN', 'bar');
expect(lifeCycles).toEqual([
'should-update', freeze({ value: 'bar' }), {},
'did-update', freeze({ value: 'foo' }), {},
'should-update',
freeze({ value: 'bar' }),
{},
'did-update',
freeze({ value: 'foo' }),
{},
]);
lifeCycles = []; // reset
instance.unmountFoo(() => expect(lifeCycles).toEqual(['will-unmount']));
});

it('renders using forceUpdate even when there is no state', () => {
it('renders using forceUpdate even when there is no state', async () => {
class Foo extends Brahmos.Component {
constructor (props) {
constructor(props) {
super(props);
this.mutativeValue = props.initialValue;
}

handleClick (callback) {
handleClick(callback) {
this.mutativeValue = 'bar';
this.forceUpdate(() => callback());
}

render () {
return (
<Inner
name={this.mutativeValue}
onClick={this.handleClick.bind(this)}
/>
);
render() {
return <Inner name={this.mutativeValue} onClick={this.handleClick.bind(this)} />;
}
}
test(<Foo initialValue="foo" />, 'DIV', 'foo');
attachedListenerWithCallback(() => expect(renderedName).toBe('bar'));
attachedListenerWithCallback(() => {});
await sleep(10);
expect(renderedName).toBe('bar');
});
});

0 comments on commit 203209c

Please sign in to comment.