All files browser.js

89.8% Statements 44/49
80% Branches 8/10
100% Functions 7/7
91.67% Lines 44/48
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 982x 2x 2x 2x   2x               2x 8x 8x 8x 8x 8x 8x     2x 10x   10x 5x     5x 5x 5x             2x 8x 8x     2x 8x   8x           8x 3x 3x         5x     8x       8x   8x 5x 5x 5x 5x 5x     8x     2x 8x 8x                     2x 10x     2x  
const path = require('path');
const React = require('react');
const { parse } = require('url');
const { renderToString } = require('react-dom/server');
 
const browserConfig = {
  features: {
    FetchExternalResources: ['script'],
    ProcessExternalResources: ['script'],
    SkipExternalResources: false,
  },
};
 
const Browser = function(jsdom, fs, buildDirectory, pathname, html) {
  this.fs = fs;
  this.jsdom = jsdom;
  this.html = html;
  this.pathname = pathname;
  this.host = parse(`http://${pathname}`).host;
  this.buildDirectory = buildDirectory;
}
 
Browser.prototype.resourceLoader = async function(resource, callback) {
  const resourcePathname = path.join(this.buildDirectory, resource.url.pathname);
 
  if (resource.url.host !== this.host) {
    return callback();
  }
 
  try {
    const content = await this.fs.readFileSync(resourcePathname)
    callback(null, content);
  } catch(error) {
    console.error(error);
    callback(error);
  }
}
 
Browser.prototype.created = function(resolve, reject, error, window) {
  Iif (error) { console.error(error) }
  this.jsdom.changeURL(window, 'http://' + this.pathname);
}
 
Browser.prototype.done = async function(resolve, reject, error, window) {
  const app = window.app;
 
  Iif (!app) {
    return reject('No application found.');
  }
 
  let initialProps;
 
  if (typeof app.getInitialProps === 'function') {
    try {
      initialProps = await app.getInitialProps();
    } catch (error) {
      return reject(error);
    }
  } else {
    initialProps = {};
  }
 
  const content = renderToString(
    React.createElement(app, initialProps)
  );
 
  window.document.getElementById('root').innerHTML = content;
 
  if (initialProps) {
    const script = window.document.createElement('script');
    const stringifiedProps = JSON.stringify(initialProps);
    script.text = `window.__INITIAL_PROPS__ = ${stringifiedProps}`;
    const firstScript = window.document.body.getElementsByTagName('script')[0];
    window.document.body.insertBefore(script, firstScript);
  }
 
  resolve(window.document.documentElement.outerHTML);
}
 
Browser.prototype.execute = function() {
  return new Promise((resolve, reject) => {
    this.jsdom.env({
      html: this.html,
      ...browserConfig,
      resourceLoader: this.resourceLoader.bind(this),
      virtualConsole: this.jsdom.createVirtualConsole().sendTo(console),
      created: this.created.bind(this, resolve, reject),
      done: this.done.bind(this, resolve, reject),
    });
  });
}
 
const BrowserFactory = function(jsdom, fs, buildDirectory) {
  return Browser.bind(null, jsdom, fs, buildDirectory);
};
 
module.exports = BrowserFactory;