'use strict'; /* eslint-disable react/prop-types */ /* eslint-disable react/no-children-prop */ const assert = require('assert'); const jsdom = require('jsdom-global'); const sinon = require('sinon'); const React = require('react'); const ReactTestRenderer = require('react-test-renderer'); const Preact = require('preact/compat'); const PreactTestRenderer = require('@testing-library/preact'); const equal = require('../..'); const tests = require('./tests'); // `jsdom-global` does a lazy require under the hood to `jsdom` which is // super expensive. We deliberately call + cleanup to take the require hit // early and seed the require cache so subsequent calls are fast. jsdom()(); class ReactChild extends React.Component { shouldComponentUpdate(nextProps) { // this.props.children is a h1 with a circular reference to its owner, Container return !equal(this.props, nextProps); } render() { return null; } } class ReactContainer extends React.Component { render() { return React.createElement(ReactChild, { children: [ React.createElement('h1', this.props.title || ''), React.createElement('h2', this.props.subtitle || ''), ], }); } } class PreactChild extends Preact.Component { shouldComponentUpdate(nextProps) { // this.props.children is a h1 with a circular reference to its owner, Container return !equal(this.props, nextProps); } render() { return null; } } class PreactContainer extends Preact.Component { render() { return Preact.createElement(PreactChild, { children: [ Preact.createElement('h1', this.props.title || ''), Preact.createElement('h2', this.props.subtitle || ''), ], }); } } describe('advanced', () => { let sandbox; let warnStub; beforeEach(() => { sandbox = sinon.createSandbox(); warnStub = sandbox.stub(console, 'warn'); }); afterEach(() => { sandbox.restore(); }); describe('React', () => { let reactChildRenderSpy; beforeEach(() => { reactChildRenderSpy = sandbox.spy(ReactChild.prototype, 'render'); }); describe('element (with circular references)', () => { it('compares without warning or errors', () => { const reactApp = ReactTestRenderer.create( React.createElement(ReactContainer) ); reactApp.update(React.createElement(ReactContainer)); assert.strictEqual(warnStub.callCount, 0); }); it('elements of same type and props are equal', () => { const reactApp = ReactTestRenderer.create( React.createElement(ReactContainer) ); reactApp.update(React.createElement(ReactContainer)); assert.strictEqual(reactChildRenderSpy.callCount, 1); }); it('elements of same type with different props are not equal', () => { const reactApp = ReactTestRenderer.create( React.createElement(ReactContainer) ); reactApp.update(React.createElement(ReactContainer, { title: 'New' })); assert.strictEqual(reactChildRenderSpy.callCount, 2); }); }); }); describe('Preact', () => { let cleanupJsDom; let preactChildRenderSpy; beforeEach(() => { cleanupJsDom = jsdom(); preactChildRenderSpy = sandbox.spy(PreactChild.prototype, 'render'); }); afterEach(() => { PreactTestRenderer.cleanup(); if (cleanupJsDom) cleanupJsDom(); }); describe('element (with circular references)', () => { it('compares without warning or errors', () => { const { rerender } = PreactTestRenderer.render( Preact.createElement(PreactContainer) ); rerender(Preact.createElement(PreactContainer)); assert.strictEqual(warnStub.callCount, 0); }); it('elements of same type and props are equal', () => { const { rerender } = PreactTestRenderer.render( Preact.createElement(PreactContainer) ); rerender(Preact.createElement(PreactContainer)); assert.strictEqual(preactChildRenderSpy.callCount, 1); }); it('elements of same type with different props are not equal', () => { const { rerender } = PreactTestRenderer.render( Preact.createElement(PreactContainer) ); rerender(Preact.createElement(PreactContainer, { title: 'New' })); assert.strictEqual(preactChildRenderSpy.callCount, 2); }); }); }); describe('warnings', () => { describe('circular reference', () => { it('warns on circular refs but do not throw', () => { const circularA = { a: 1 }; circularA.self = circularA; const circularB = { a: 1 }; circularB.self = circularB; equal(circularA, circularB); assert.strictEqual(warnStub.callCount, 1); }); }); describe('basics usage', () => { it('never warns', () => { tests.generic.forEach((suite) => { suite.tests.forEach((test) => { assert.strictEqual( equal(test.value1, test.value2), test.equal, test.description ); }); }); assert.strictEqual( warnStub.callCount, 0, `console.warn called ${ warnStub.callCount } with arguments: ${JSON.stringify(warnStub.args)}` ); }); }); }); });