react-html-document
Version:
A foundational React component useful for rendering full html documents on the server.
235 lines (212 loc) • 7.41 kB
JavaScript
import React from 'react';
import path from 'path';
import fs from 'fs';
import { expect } from 'chai';
import { STATE_SCRIPT_ID } from '../src/constants';
import { renderAndGetQuerySelector } from './utils';
import TestApp from './TestApp';
describe('HTMLDocument', () => {
it('should render with default props', () => {
const props = { };
const qs = renderAndGetQuerySelector(props);
expect(qs('html').length).to.equal(1);
});
it('should render page title', () => {
const props = {
title: 'My Title'
};
const qs = renderAndGetQuerySelector(props);
expect(qs('title').html()).to.equal(props.title);
});
it('should render html attributes', () => {
const props = {
htmlAttributes: {
lang: 'es'
}
};
const qs = renderAndGetQuerySelector(props);
expect(qs('html').attr('lang')).to.equal(props.htmlAttributes.lang);
});
it('should render favicon link', () => {
const props = {
favicon: 'path/to/favicon.ico'
};
const qs = renderAndGetQuerySelector(props);
const $links = qs('link');
expect($links.length).to.equal(1);
expect($links.attr('rel')).to.equal('icon');
expect($links.attr('href')).to.equal(props.favicon);
});
describe('Metatags', () => {
it('should render metatags', () => {
const props = {
metatags: [
{ name: 'description', content: 'My Description' },
{ name: 'title', content: 'My Title' }
]
};
const qs = renderAndGetQuerySelector(props);
const $metatags = qs('meta');
expect($metatags.length).to.equal(2);
$metatags.each((index, metatag) => {
expect(metatag.attribs).to.deep.equal(props.metatags[index]);
});
});
});
describe('Stylesheets', () => {
it('should render linked stylesheets from a list of strings', () => {
const props = {
stylesheets: ['mysite.com/styles.css']
};
const qs = renderAndGetQuerySelector(props);
const $links = qs('link');
expect($links.length).to.equal(1);
expect($links.attr('href')).to.equal(props.stylesheets[0]);
});
it('should render linked stylesheet from a list of objects', () => {
const props = {
stylesheets: [
{ href: 'mysite.com/styles.css' }
]
};
const qs = renderAndGetQuerySelector(props);
const $links = qs('link');
expect($links.length).to.equal(1);
expect($links.attr('href')).to.equal(props.stylesheets[0].href);
});
it('should render inline styles', () => {
const props = {
stylesheets: [
{ inline: '.body { color: #333 }' }
]
};
const qs = renderAndGetQuerySelector(props);
const $styles = qs('style');
expect($styles.length).to.equal(1);
expect($styles.html()).to.equal(props.stylesheets[0].inline);
});
it('should render stylesheets from files', () => {
const file = path.join(__dirname, 'test-css.css');
const props = {
stylesheets: [
{ file }
]
};
const styleSheetContents = fs.readFileSync(file, 'utf-8');
const qs = renderAndGetQuerySelector(props);
const $styles = qs('style');
expect($styles.length).to.equal(1);
expect($styles.html()).to.equal(styleSheetContents);
});
});
describe('State', () => {
it('should render universalState script', () => {
const universalState = {
user: {
name: 'Professor Charles Xavier'
}
};
const props = {
universalState
};
const qs = renderAndGetQuerySelector(props);
const universalStateFromDOM = JSON.parse(qs(`script#${STATE_SCRIPT_ID}`).text());
expect(universalStateFromDOM).to.deep.equal(universalState);
});
it('should use internal universalState key as universalState script id', () => {
const props = {
universalState: { myuniversalState: true }
};
const qs = renderAndGetQuerySelector(props);
expect(qs(`script#${STATE_SCRIPT_ID}`).length).to.equal(1);
});
});
describe('Scripts', () => {
it('should render script tags from a list of strings', () => {
const props = {
scripts: [
'mysite.com/main.js'
],
universalStateKey: '__universalState'
};
const qs = renderAndGetQuerySelector(props);
const $scripts = qs('script').not(`[data-${props.universalStateKey}]`);
expect($scripts.length).to.equal(1);
expect($scripts.get(0).attribs.src).to.equal(props.scripts[0]);
});
it('should render script tags from a list of objects', () => {
const props = {
scripts: [
{ src: 'mysite.com/main.js' }
],
universalStateKey: '__universalState'
};
const qs = renderAndGetQuerySelector(props);
const $scripts = qs('script').not(`script[data-${props.universalStateKey}]`);
expect($scripts.length).to.equal(1);
expect($scripts.get(0).attribs.src).to.equal(props.scripts[0].src);
});
it('should render inline scripts', () => {
const props = {
scripts: [
{ inline: 'window.myApp = true;' }
]
};
const qs = renderAndGetQuerySelector(props);
const $scripts = qs('script').not(`script#${STATE_SCRIPT_ID}`);
expect($scripts.length).to.equal(1);
expect($scripts.html()).to.equal(props.scripts[0].inline);
});
it('should render scripts from files', () => {
const file = path.join(__dirname, 'test-script.js');
const props = {
scripts: [
{ file }
]
};
const scriptContents = fs.readFileSync(file, 'utf-8');
const qs = renderAndGetQuerySelector(props);
const $scripts = qs('script').not(`script#${STATE_SCRIPT_ID}`);
expect($scripts.length).to.equal(1);
expect($scripts.html()).to.equal(scriptContents);
});
});
describe('Children', () => {
it('should use right children container id', () => {
const childrenContainerId = 'my-app';
const props = {
childrenContainerId
};
const children = <TestApp />;
const qs = renderAndGetQuerySelector(props, children);
expect(qs(`#${childrenContainerId}`).length).to.equal(1);
});
it('should render children with own props', () => {
const props = {
childrenContainerId: 'app'
};
const testAppProps = {
message: 'Sahp'
};
const children = <TestApp {...testAppProps} />;
const qs = renderAndGetQuerySelector(props, children);
expect(qs(`#${props.childrenContainerId}`).text()).to.equal(testAppProps.message);
});
it('should render children statically when given no universalState', () => {
const props = { };
const children = <TestApp />;
const qs = renderAndGetQuerySelector(props, children);
const reactSelector = '[data-reactid]';
expect(qs(reactSelector).length).to.equal(0);
});
it('should render children with react ids for client mounting when given universalState', () => {
const props = {
universalState: { myuniversalState: true }
};
const children = <TestApp />;
const qs = renderAndGetQuerySelector(props, children);
const reactSelector = '[data-reactid]';
expect(qs(reactSelector).length).to.equal(1);
});
});
});