import { h, render, rerender, Component } from 'preact';
import assertJsx from 'preact-jsx-chai';
import sinonChai from 'sinon-chai';
chai.use(assertJsx);
chai.use(sinonChai);
import Markup from 'src';
/*eslint-env browser,mocha*/
/*global sinon,expect,chai*/
describe('Markup', () => {
let scratch;
before( () => {
scratch = document.createElement('div');
(document.body || document.documentElement).appendChild(scratch);
});
beforeEach( () => {
scratch.innerHTML = '';
});
after( () => {
scratch.parentNode.removeChild(scratch);
scratch = null;
});
it('should render valid JSX', () => {
expect(
).to.eql(
hello!
asdflkj
);
});
it('should render simple static markup', () => {
let markup = `hello!asdflkj
`;
render(, scratch);
expect(scratch.firstChild.innerHTML).to.equal(markup);
});
it('should render xml', () => {
render(, scratch);
expect(scratch.firstChild.innerHTML).to.equal('
');
});
it('should call onError for invalid XML', () => {
let onError = sinon.spy();
render(, scratch);
expect(scratch.firstChild.innerHTML).to.equal('');
expect(onError).to.have.been.calledOnce;
expect(onError.firstCall.args[0])
.to.have.property('error')
.that.is.an('error')
.with.property('message')
.that.is.a('string')
.that.matches(/(failed|invalid|parse)/i);
});
it('should render html', () => {
let markup = '';
render(, scratch);
expect(scratch.firstChild.innerHTML).to.equal(markup);
});
it('should mercilessly render invalid HTML as one does', () => {
let onError = sinon.spy();
render(, scratch);
expect(onError).not.to.have.been.called;
expect(scratch.firstChild.innerHTML).to.equal('<2-element> <2/>');
});
it('should render invalid HTML to the correct JSX', () => {
expect(
).to.eql(
);
});
it('should render mapped components from XML', () => {
const Foo = ({ a, b, camelCasedProperty, children }) =>
({ children }
);
expect(
).to.eql(
);
let markup = `italicbold`;
expect(
).to.eql(
);
});
it('should correctly map XML properties', () => {
const Foo = ({camelCasedProperty, children}) =>
({ children }
);
expect(
).to.eql(
);
expect(
).to.eql(
);
expect(
).to.eql(
);
});
it('should correctly map HTML properties', () => {
const Foo = ({camelCasedProperty, children}) =>
({ children }
);
//Notice that camelCasedProperty is gone in the output cause it's mapped in `prop.camelcasedproperty`
// and Foo isn't aware of it
expect(
).to.eql(
);
expect(
).to.eql(
);
expect(
).to.eql(
);
});
it('should render mapped components from HTML', () => {
const XFoo = ({ p, camelCasedProperty, children }) =>
(hello { children }
);
expect(
).to.eql(
);
let markup = `italicbold`;
expect(
).to.eql(
);
});
describe('allow-scripts option', () => {
before( () => {
window.stub = sinon.stub();
});
beforeEach( () => {
window.stub.reset();
});
after( () => {
delete window.stub;
});
it('should ignore script tags by default', () => {
let markup = `hello!asdflkj
`;
render(, scratch);
markup = `hello!asdflkj
`;
render(, scratch);
expect(window.stub).not.to.have.been.called;
});
it('should allow script tags if allow-scripts is enabled', () => {
let markup = `hello!asdflkj
`;
render(, scratch);
expect(window.stub).to.have.been.calledOnce;
});
});
describe('allow-events option', () => {
before( () => {
window.stub = sinon.stub();
});
beforeEach( () => {
window.stub.reset();
});
after( () => {
delete window.stub;
});
it('should correctly proxy on* handlers defined as strings', () => {
let markup = `Hello world
`;
render(, scratch);
let element = scratch.childNodes[0];
let ev = document.createEvent("MouseEvent");
ev.initMouseEvent("click");
expect(window.stub.called,"stub should not be called before click handler").to.equal(false);
element.dispatchEvent(ev);
expect(window.stub.called,"stub should be called from click handler").to.equal(true);
expect(window.stub, "click handler should be supplied event as argument").to.have.been.calledWithExactly(ev);
});
it('should NOT proxy on* handlers if allow-events is not enabled', (done) => {
let markup = `Hello world
`;
let error = null;
render(, scratch);
let element = scratch.childNodes[0];
let ev = document.createEvent("MouseEvent");
ev.initMouseEvent("click");
// Errors thrown by dispatchEvent are always uncaught exceptions
window.onerror = (e) => {
expect(window.stub.called,"stub should NOT be called from click handler").to.equal(false);
done();
};
element.dispatchEvent(ev);
});
});
it('should pipe parse errors to console', () => {
sinon.stub(console, 'error');
let invalidXml = `Test with & symbol
`;
render(, scratch);
expect(console.error)
.to.have.been.calledOnce
.and.calledWithMatch('preact-markup: Error: error on line 2 at column 21: xmlParseEntityRef: no name');
console.error.restore();
});
it('should trim whitespace by default', () => {
expect(
).to.eql(
);
expect(
).to.eql(
{' '}
);
});
it('should trim all whitespace for trim="all"', () => {
expect(
).to.eql(
hello!
asdflkj
);
expect(
).to.eql(
);
});
});