import React, { createElement, render, Component, hydrate, createContext } from 'preact/compat'; import { setupRerender, act } from 'preact/test-utils'; import { setupScratch, teardown, serializeHtml, createEvent } from '../../../test/_util/helpers'; describe('compat render', () => { /** @type {HTMLDivElement} */ let scratch; /** @type {() => void} */ let rerender; const ce = type => document.createElement(type); const text = text => document.createTextNode(text); beforeEach(() => { scratch = setupScratch(); rerender = setupRerender(); }); afterEach(() => { teardown(scratch); }); it('should render react-style jsx', () => { let jsx = (
inner! {['a', 'b']}
); expect(jsx.props).to.have.property('className', 'foo bar'); React.render(jsx, scratch); expect(serializeHtml(scratch)).to.equal( '
inner!ab
' ); }); it('should replace isomorphic content', () => { let root = ce('div'); let initialChild = ce('div'); initialChild.appendChild(text('initial content')); root.appendChild(initialChild); render(
dynamic content
, root); expect(root) .to.have.property('textContent') .that.is.a('string') .that.equals('dynamic content'); }); it('should remove extra elements', () => { let root = ce('div'); let inner = ce('div'); root.appendChild(inner); let c1 = ce('div'); c1.appendChild(text('isomorphic content')); inner.appendChild(c1); let c2 = ce('div'); c2.appendChild(text('extra content')); inner.appendChild(c2); render(
dynamic content
, root); expect(root) .to.have.property('textContent') .that.is.a('string') .that.equals('dynamic content'); }); // Note: Replacing text nodes inside the root itself is currently unsupported. // We do replace them everywhere else, though. it('should remove text nodes', () => { let root = ce('div'); let div = ce('div'); root.appendChild(div); div.appendChild(text('Text Content')); div.appendChild(text('More Text Content')); render(
dynamic content
, root); expect(root) .to.have.property('textContent') .that.is.a('string') .that.equals('dynamic content'); }); it('should ignore maxLength / minLength when is null', () => { render(, scratch); expect(scratch.firstElementChild.getAttribute('maxlength')).to.equal(null); expect(scratch.firstElementChild.getAttribute('minlength')).to.equal(null); }); it('should support defaultValue', () => { render(, scratch); expect(scratch.firstElementChild).to.have.property('value', 'foo'); }); it('should add defaultValue when value is null/undefined', () => { render(, scratch); expect(scratch.firstElementChild).to.have.property('value', 'foo'); render(, scratch); expect(scratch.firstElementChild).to.have.property('value', 'foo'); }); it('should support defaultValue for select tag', () => { function App() { return ( ); } render(, scratch); const options = scratch.firstChild.children; expect(options[0]).to.have.property('selected', false); expect(options[1]).to.have.property('selected', true); }); it('should support defaultValue for select tag when using multi selection', () => { function App() { return ( ); } render(, scratch); const options = scratch.firstChild.children; expect(options[0]).to.have.property('selected', true); expect(options[1]).to.have.property('selected', false); expect(options[2]).to.have.property('selected', true); }); it('should ignore defaultValue when value is 0', () => { render(, scratch); expect(scratch.firstElementChild.value).to.equal('0'); }); it('should keep value of uncontrolled inputs using defaultValue', () => { // See https://github.com/preactjs/preact/issues/2391 const spy = sinon.spy(); class Input extends Component { render() { return ( { spy(); this.forceUpdate(); }} /> ); } } render(, scratch); expect(scratch.firstChild.value).to.equal('bar'); scratch.firstChild.focus(); scratch.firstChild.value = 'foo'; scratch.firstChild.dispatchEvent(createEvent('input')); rerender(); expect(scratch.firstChild.value).to.equal('foo'); expect(spy).to.be.calledOnce; }); it('should call the callback', () => { let spy = sinon.spy(); render(
, scratch, spy); expect(spy).to.be.calledOnce; expect(spy).to.be.calledWithExactly(); }); // Issue #1727 it('should destroy the any existing DOM nodes inside the container', () => { scratch.appendChild(document.createElement('div')); scratch.appendChild(document.createElement('div')); render(foo, scratch); expect(scratch.innerHTML).to.equal('foo'); }); it('should only destroy existing DOM nodes on first render', () => { scratch.appendChild(document.createElement('div')); scratch.appendChild(document.createElement('div')); render(, scratch); let child = scratch.firstChild; child.focus(); render(, scratch); expect(document.activeElement.nodeName).to.equal('INPUT'); }); it('should normalize class+className even on components', () => { function Foo(props) { return (
foo
); } render(, scratch); expect(scratch.firstChild.className).to.equal('foo'); render(null, scratch); render(, scratch); expect(scratch.firstChild.className).to.equal('foo'); }); it('should normalize className when it has an empty string', () => { function Foo(props) { expect(props.className).to.equal(''); return
foo
; } render(, scratch); }); // Issue #2275 it('should normalize class+className + DOM properties', () => { function Foo(props) { return