diff --git a/packages/electrode-react-webapp/.babelrc b/packages/electrode-react-webapp/.babelrc
deleted file mode 100644
index 24b086f24..000000000
--- a/packages/electrode-react-webapp/.babelrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "node": "8"
- }
- }
- ],
- "@babel/preset-react"
- ]
-}
diff --git a/packages/electrode-react-webapp/.eslintignore b/packages/electrode-react-webapp/.eslintignore
deleted file mode 100644
index c528e9065..000000000
--- a/packages/electrode-react-webapp/.eslintignore
+++ /dev/null
@@ -1,5 +0,0 @@
-coverage
-resources
-node_modules
-lib/templates
-test/data
\ No newline at end of file
diff --git a/packages/electrode-react-webapp/.eslintrc b/packages/electrode-react-webapp/.eslintrc
deleted file mode 100644
index 5f6ea6525..000000000
--- a/packages/electrode-react-webapp/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
----
-extends:
- - "./node_modules/electrode-archetype-njs-module-dev/config/eslint/.eslintrc-node"
diff --git a/packages/electrode-react-webapp/.gitignore b/packages/electrode-react-webapp/.gitignore
deleted file mode 100644
index 3236cba6d..000000000
--- a/packages/electrode-react-webapp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-template
diff --git a/packages/electrode-react-webapp/CHANGELOG.json b/packages/electrode-react-webapp/CHANGELOG.json
deleted file mode 100644
index 547a073c6..000000000
--- a/packages/electrode-react-webapp/CHANGELOG.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "name": "electrode-react-webapp",
- "entries": [
- {
- "version": "5.1.1",
- "tag": "electrode-react-webapp_v5.1.1",
- "date": "Tue, 29 Aug 2023 14:57:37 GMT",
- "comments": {
- "patch": [
- {
- "comment": "Update dev dependencies"
- }
- ]
- }
- },
- {
- "version": "5.1.0",
- "tag": "electrode-react-webapp_v5.1.0",
- "date": "Thu, 04 May 2023 21:08:31 GMT",
- "comments": {
- "minor": [
- {
- "comment": "`bable/*` minor version upgrades"
- }
- ]
- }
- }
- ]
-}
diff --git a/packages/electrode-react-webapp/CHANGELOG.md b/packages/electrode-react-webapp/CHANGELOG.md
deleted file mode 100644
index 8a4c35aa5..000000000
--- a/packages/electrode-react-webapp/CHANGELOG.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Change Log - electrode-react-webapp
-
-This log was last generated on Tue, 29 Aug 2023 14:57:37 GMT and should not be manually modified.
-
-## 5.1.1
-Tue, 29 Aug 2023 14:57:37 GMT
-
-### Patches
-
-- Update dev dependencies
-
-## 5.1.0
-Thu, 04 May 2023 21:08:31 GMT
-
-### Minor changes
-
-- `bable/*` minor version upgrades
-
diff --git a/packages/electrode-react-webapp/DESIGN.md b/packages/electrode-react-webapp/DESIGN.md
deleted file mode 100644
index 8ac7d106a..000000000
--- a/packages/electrode-react-webapp/DESIGN.md
+++ /dev/null
@@ -1,330 +0,0 @@
-# Design of the index.html rendering flow
-
-## Table of Contents
-
-* [Considerations](#considerations)
-* [Tokens](#tokens)
- + [Token Example](#token-example)
- + [Invoking token handler/process functions](#invoking-token-handlerprocess-functions)
- + [Token Props](#token-props)
- + [Internal Props](#internal-props)
-* [Predefined Tokens and Handler](#predefined-tokens-and-handler)
-* [Custom Processing](#custom-processing)
- + [Handler](#handler)
- + [Custom Processor Module](#custom-processor-module)
- + [The Process Function](#the-process-function)
- + [`context`](#context)
- + [Concurrent Token and Async Output](#concurrent-token-and-async-output)
- + [routeData](#routedata)
-
-## Considerations
-
-The design of the rendering flow took the following into consideration.
-
-- A simple token base template rendering
-
-- The document output to be a stream and allow any token to trigger a flush at any time.
-
-- Allow tokens to be async so it can call services etc to produce the data.
-
-- Allow token proccessor to open a spot in the output for update later. A flush will wait for open spots to close. This enables concurrently processing tokens that can send text to fixed spots in the output doc.
-
-## Tokens
-
-**Token is the basic building block on how your `index` page will be built. Following are details about how they work and the types of tokens.**
-
-- **Syntax** Within your template file, special tokens can be specified with ``, or `/*--%{token}--*/`
-
- - Where `token` is the string referring to a token or name of a processor module.
-
- - Tokens can also be multi lines.
-
- - **Comments** can be added as lines that start with `//`.
-
- - must be in their own lines only.
-
- - **Props** Just like HTML tags, [props](#token-props) can be specified for a token.
-
-- **Token Module**: To specify a processor module, start the token with `#`. ie: ``, where `module_name` specifies a name for a [Custom Processor Module](#custom-processor-module).
-
- - The module will be loaded with `require`. If the `module_name` starts with `.`, then the module is required from where the template file is. For example, `` will load the module `./lib/custom` relative to the dir the template is located.
-
-### Token Example
-
-```html
-
-
-
-
-
blah
-
-```
-
-### Invoking token handler/process functions
-
-The **token** has either a handler function or a module with a process function.
-
-The function are invoked with the token object instance as `this`.
-
-So for example, to access the [Token props](#token-props) you can access `this.props` which is an object with props specified in the template.
-
-### Token Props
-
-- You can specify Key Value Pair props for your tokens in the form of `name=value`
-
- - ie: ``
-
- - String prop values must be enclosed in `"` or `'`.
-
- - Values started with `[` will be parsed with [string-array](https://www.npmjs.com/package/string-array)
-
- - Any other values will be parsed with `JSON.parse`, so only `false`, `true`, numbers, `null`, or a stringified JSON that has absolutely no spaces anywhere.
-
-- If you want, you can specify a single JSON object following the token to act as the props object.
-
-For example:
-
-```html
-
-```
-
-### Internal Props
-
-Some props with leading `_` may be used to control the template engine. These are supported:
-
-- `_call="function_name"` - Tells the template engine what function from a token module to call.
-
- - Expect your token loads a custom processor module that instead of exporting a setup funtion, exports an object with setup functions.
- - The `_call` prop specifies the name of a function from that module to call.
-
-For example:
-
-```html
-
-```
-
-You can also use a [string-array](https://www.npmjs.com/package/string-array) to have additional strings params passed to the function.
-
-For example:
-
-```html
-
-```
-
-This will call the function `setup1(options, tokenInstance, a, b)` from your module like this:
-
-```js
-tokenModule.setup1(options, tokenObj, "param1", "param2");
-```
-
-Where `tokenObj` is the your token's instance object.
-
-Your token's `props` object is accesible through `tokenObj.props`.
-
-## Predefined Tokens and Handler
-
-These are tokens that are automatically processed internally:
-
-- `INITIALIZE`
-- `META_TAGS`
-- `PAGE_TITLE`
-- `CRITICAL_CSS`
-- `WEBAPP_HEADER_BUNDLES`
-- `HEAD_CLOSED`
-- `SSR_CONTENT`
-- `AFTER_SSR_CONTENT`
-- `PREFETCH_BUNDLES`
-- `WEBAPP_BODY_BUNDLES`
-- `BODY_CLOSED`
-- `HTML_CLOSED`
-
-A builtin token handler is used to process these.
-
-If you've registered your own [handler](#handler) for any of them, you can still access the builtin token handler as `context.user.routeData.tokenHandler`.
-
-## Custom Processing
-
-There are two ways to provide your own processor for tokens.
-
-1. Provide a handler that can process tokens
-2. Provide a custom processor module
-
-### Handler
-
-You can register a token handler for each route. The token handler should export a function `setup` that returns an object with the names of your custom tokens each associated with its own handler function.
-
-For example, you can replace the predefined `SSR_CONTENT` token with your own handler, and define a new token `MY_NEW_TOKEN`.
-
-```js
-module.exports = function setup(options, tokenObj) {
- return {
- SSR_CONTENT: (context, [next]) => {},
- MY_NEW_TOKEN: context => `hello from MY_NEW_TOKEN`
- };
-};
-```
-
-- `options` will contain the following:
-
- - `routeOptions` - original options passed in
- - `routeData` - global data for the route
-
-- `tokenObj` is the instance object for your token.
-
- - Your token's `props` object is accesible through `tokenObj.props`.
-
-### Custom Processor Module
-
-- The custom processor module should export an initialize function as below:
-
-```js
-module.exports = function setup(options, tokenObj) {
- return {
- process: function(context, [next]) {}
- };
-};
-```
-
-- You can also export an object with multiple setup functions and use the `_call` prop to call specific ones:
-
-```js
-function setup1(options, tokenObj) {
- return {
- process: function(context, [next]) {}
- };
-}
-
-function setup2(options, tokenObj) {
- return {
- process: function(context, [next]) {}
- };
-}
-
-module.exports = {
- setup1,
- setup2
-};
-```
-
-And you can load the same module but call different setup function with the `_call` prop.
-
-```html
-Calling setup1 of lib/my-handlers.js
-
-
-Calling setup2 of lib/my-handlers.js
-
-```
-
-### The Process Function
-
-As shown above, the token handler or custom process function should have the following signature:
-
-```js
-function (context, [next]) {}
-```
-
-> Note that the setup is only called once for each route. The instance returned is reused for every request. So be sure to avoid any global state. Everything should operate on the `context` passed in.
-
-Parameters:
-
-- If `next` is specified then it's async and rendering will only continue when it's called.
-
-- The function can return a Promise to be async if it doesn't want to take a next callback.
-
-- If function returns a string it will be added to the output stream.
-
-- Other return values are ignored.
-
-### `context`
-
-`context` will contain an `output` object with the following methods:
-
-- `add(string)` - Adds `string` to the output stream.
-- `reserve()` - Reserves a spot in the output stream. Returns a Spot object.
-- `flush()` - Flush output stream. Will wait for all open spots to close.
-
-Spot object has the follow methods:
-
-- `add(string)` - Adds `string` to the spot.
-- `close()` - Close the spot. Must be called once done else rendering will be stuck.
-
-`context.user` will contain the following:
-
-- `request` - the server request object
-- `routeOptions` - options for the route
-- `routeData` - global data for the route
-- `content` - the content from your route
-- `mode` - Render Mode (nojs, noss, datass)
-- `renderJs` - Render JS bundle
-- `renderSs` - Do SSR
-- `sriptNonce` - nonce for script tags
-- `chunkNames` - webpack asset chunks
-- `devCSSBundle`
-- `devJSBundle`
-- `jsChunk`
-- `cssChunk`
-
-### Concurrent Token and Async Output
-
-Note that a token handler that takes `next` or returns Promise is only async, but not concurrent. Meaning the renderer will still wait for it to finish before continuing to the next token.
-
-If you want the renderer to continue while your token generates output concurrently, you have two options:
-
-1. Reserve a spot with `context.output.reserve()` and use `process.nextTick` to invoke another async function.
-
-2. Return a [node.js stream] for your output.
-
-For example, reserving a spot:
-
-```js
-module.exports = function setup(options) {
- return {
- process: (context, token) => {
- const spot = context.output.reserve();
- const concurrentProc = async () => {
- const myData = await getMyData();
- spot.add(myData.stringify());
- spot.close();
- };
- process.nextTick(concurrentProc);
- }
- };
-};
-```
-
-### routeData
-
-The `context.user.routeData` contains the following:
-
-- WEBPACK_DEV - true if webpack dev server running
-- RENDER_JS - render JS bundle (could be override by request)
-- RENDER_SS - do SSR (could be override by request)
-- html - The html template
-- assets - The webpack bundle assets
-- devBundleBase - URL base for dev bundle
-- prodBundleBase - URL base for prod bundle
-- chunkSelector - callback to select webpack bundle
-- iconStats - webpack icon stats
-- htmlTokens - html template parsed into tokens
-
-[node.js stream]: https://nodejs.org/docs/latest-v10.x/api/stream.html#stream_stream
diff --git a/packages/electrode-react-webapp/LICENSE b/packages/electrode-react-webapp/LICENSE
deleted file mode 100644
index bd35f4e89..000000000
--- a/packages/electrode-react-webapp/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2016 WalmartLabs
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/packages/electrode-react-webapp/README.md b/packages/electrode-react-webapp/README.md
deleted file mode 100644
index 4a4440928..000000000
--- a/packages/electrode-react-webapp/README.md
+++ /dev/null
@@ -1,290 +0,0 @@
-# Electrode React Webapp
-
-[![NPM version][npm-image]][npm-url] [![Dependency Status][daviddm-image]][daviddm-url] [![devDependency Status][daviddm-dev-image]][daviddm-dev-url] [![npm downloads][npm-downloads-image]][npm-downloads-url]
-
-This module helps render and serve your Electrode React application's `index.html`. It will handle doing server side rendering and embedding all the necessary JS and CSS bundles for your application.
-
-All the defaults are configured out of the box, but your index page is extensible. You can specify your own index template file with the `htmlFile` or `selectTemplate` options.
-
-See [design](/packages/electrode-react-webapp/DESIGN.md) for details on how the template can be extended.
-
-## Installing
-
-```bash
-$ npm install electrode-react-webapp --save
-```
-
-## Usage
-
-### Registering with Hapi
-
-You can use this plugin by registering it with your Hapi server.
-
-```js
-const reactWebapp = server.register({
- register: require("electrode-react-webapp"),
- options: {
- pageTitle: "My Awesome React WebApp",
- paths: {
- "/{args*}": {
- content: "Hello React! "
- }
- }
- }
-});
-```
-
-### Registering with electrode-server
-
-To use this with electrode-server, add to the config you pass to `electrode-server`:
-
-```js
-const config = {
- plugins: {
- "electrode-react-webapp": {
- options: {
- pageTitle: "My Awesome React WebApp",
- paths: {
- "/{args*}": {
- content: "Hello React! "
- }
- },
- unbundledJS: {
- enterHead: [{ src: "http://cdn.com/js/lib.js" }]
- }
- }
- }
- }
-};
-
-require("electrode-server")(config);
-```
-
-## Default options
-
-This plugin has some default options but you can override them by setting your own value.
-
-The current defaults are:
-
-```js
-{
- pageTitle: "Untitled Electrode Web Application",
- webpackDev: process.env.WEBPACK_DEV === "true",
- renderJS: true,
- serverSideRendering: true,
- htmlFile: "node_modules/electrode-react-webapp/lib/index.html",
- devServer: {
- host: "127.0.0.1",
- port: "2992"
- },
- paths: {},
- stats: "dist/server/stats.json"
-}
-```
-
-## Options
-
-| name | type | default | description |
-| -------------------------------------------- | ---------------------------- | -------- | ---------------------------------------------------------- |
-| `pageTitle` | `String` | | The value to be shown in the browser's title bar |
-| `htmlFile` | `String` | `*1` | Absolute or relative path to the HTML template. |
-| [`selectTemplate`](#selecttemplate-function) | `Function` | | Callback to selecte HTML template base on `request` |
-| `serverSideRendering` | `Boolean` | `false` | Toggle server side rendering. |
-| `webpackDev` | `Boolean` | `false` | Running with webpack-dev-server |
-| `paths` | `Object` | | Specify [route paths and content](#paths-and-content) |
-| `unbundledJS` | `Object` | | [Load external JavaScript](#unbundledJS-details) into page |
-| `devServer` | `Object` | | webpack Dev Server Options |
-| `prodBundleBase` | `String` | `"/js/"` | Base path to the JavaScript, CSS and manifest bundles |
-| `cspNonceValue` | [`varies`](#csp-nonce-value) | | Used to retrieve a CSP nonce value. |
-
-> `*1`: Default for `htmlFile` is to use this module's built-in [`index.html`](./lib/index.html)
-
-### Paths and Content
-
-Example:
-
-```js
-{
- paths: {
- "/test": {
- // route specific options
- }
- }
-}
-```
-
-Route speicific options can be:
-
-| name | type | description |
-| ---------------------- | ---------- | ----------------------------------------------------------------- |
-| `htmlFile` | `String` | Absolute or relative path to the HTML template file. |
-| `templateFile` | `String` | |
-| `insertTokenIds` | `Boolean` | |
-| `pageTitle` | `String` | |
-| `selectTemplate` | `Function` | Callback to selecte HTML template for the route base on `request` |
-| `responseForBadStatus` | `Function` | |
-| `responseForError` | `Function` | |
-
-| `content` | [`varies`](#content-details) | [Content generator](#content-details) for server-side rendering |
-| `overrideOptions` | `Object` | Specify any config for the given path to override top level options |
-
-### `unbundledJS` Details
-
-Example:
-
-```js
-{
- unbundledJS: {
- enterHead: [],
- preBundle: []
- }
-}
-```
-
-- `enterHead` - Array of script entries to be inserted in `` before anything else
-- `preBundle` - Array of script entries to be inserted in `` before the application's bundled JavaScript
-
-The script entries can be:
-
-- object - `{ src: "path to file" }` to insert a `
- *
- *
- * The output will be:
- *
- *
- */
-module.exports = function groupScripts(data) {
- const output = data.filter(x => x).reduce(
- (acc, x) => {
- const update = src => {
- if (acc.src !== src || !acc.current) {
- joinScripts(acc);
- acc.current = [x];
- acc.src = src;
- } else {
- acc.current.push(x);
- }
- };
-
- update(!!x.src);
-
- return acc;
- },
- { src: false, scripts: [] }
- );
-
- joinScripts(output);
-
- return output;
-};
diff --git a/packages/electrode-react-webapp/lib/hapi/index.js b/packages/electrode-react-webapp/lib/hapi/index.js
deleted file mode 100644
index d71ab62f8..000000000
--- a/packages/electrode-react-webapp/lib/hapi/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-"use strict";
-
-const { universalHapiPlugin, isHapi17 } = require("electrode-hapi-compat");
-
-const hapi16 = require("./plugin16");
-const hapi17 = require("./plugin17");
-const pkg = require("../../package.json");
-
-module.exports = universalHapiPlugin(
- {
- hapi16: hapi16.register,
- hapi17: hapi17.register
- },
- pkg
-);
-
-const registerRoutes = isHapi17() ? hapi17.registerRoutes : hapi16.registerRoutes;
-
-//
-// ensure extra props are not enumerable so Hapi's Joi about it
-//
-Object.defineProperty(module.exports, "registerRoutes", {
- enumerable: false,
- value: registerRoutes
-});
diff --git a/packages/electrode-react-webapp/lib/hapi/plugin16.js b/packages/electrode-react-webapp/lib/hapi/plugin16.js
deleted file mode 100644
index 9678d3d8d..000000000
--- a/packages/electrode-react-webapp/lib/hapi/plugin16.js
+++ /dev/null
@@ -1,83 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, max-params, max-statements, complexity */
-
-const HttpStatusCodes = require("http-status-codes");
-const HttpStatus = require("../http-status");
-
-const getDataHtml = data => (data.html !== undefined ? data.html : data);
-
-const DefaultHandleRoute = (request, reply, handler, content, routeOptions) => {
- return handler({
- content,
- mode: request.query.__mode || "",
- template: request.indexPageTemplate,
- request
- })
- .then(context => {
- const data = context.result;
- const html = getDataHtml(data);
-
- if (html instanceof Error) {
- throw html;
- }
-
- let respond;
- let status = data.status;
-
- if (data.verbatim || status === undefined) {
- // if no status, fallback to context.status, and then 200
- status = status || context.status || HttpStatusCodes.OK;
- respond = reply(html);
- } else if (HttpStatus.redirect[status]) {
- respond = reply.redirect(data.path);
- return respond.code(status);
- } else if (status >= HttpStatusCodes.OK && status < 300) {
- respond = reply(html);
- } else if (routeOptions.responseForBadStatus) {
- const output = routeOptions.responseForBadStatus(request, routeOptions, data);
- status = output.status;
- respond = reply(output.html);
- } else {
- // should not reach here w/o html because user returned content
- // would have to return a literal string that has no `.status`
- // and html being undefined to be able to skip all the cases above
- respond = reply(html);
- }
-
- const response = context.user && context.user.response;
-
- if (response) {
- Object.assign(respond.headers, response.headers);
- }
-
- return respond.code(status);
- })
- .catch(err => {
- const output = routeOptions.responseForError(request, routeOptions, err);
-
- reply(output.html).code(output.status);
- });
-};
-
-const _registerRoutes = require("./register-routes");
-
-const registerRoutes = (server, options) => _registerRoutes(server, options, DefaultHandleRoute);
-
-const register = (server, options, next) => {
- try {
- registerRoutes(server, options);
- return next();
- } catch (err) {
- return next(err);
- }
-};
-
-const pkg = require("../../package.json");
-
-register.attributes = { pkg };
-
-module.exports = {
- register,
- registerRoutes
-};
diff --git a/packages/electrode-react-webapp/lib/hapi/plugin17.js b/packages/electrode-react-webapp/lib/hapi/plugin17.js
deleted file mode 100644
index aa131b3cc..000000000
--- a/packages/electrode-react-webapp/lib/hapi/plugin17.js
+++ /dev/null
@@ -1,77 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, max-params, max-statements, complexity */
-
-const HttpStatusCodes = require("http-status-codes");
-const HttpStatus = require("../http-status");
-
-const getDataHtml = data => (data.html !== undefined ? data.html : data);
-
-const DefaultHandleRoute = (request, h, handler, content, routeOptions) => {
- return handler({
- content,
- mode: request.query.__mode || "",
- template: request.indexPageTemplate,
- request
- })
- .then(context => {
- if (context._intercepted) {
- return context._intercepted.responseHandler(request, h, context);
- }
-
- const data = context.result;
- const html = getDataHtml(data);
-
- if (html instanceof Error) {
- throw html;
- }
-
- let respond;
- let status = data.status;
-
- if (data.verbatim || status === undefined) {
- // if no status, fallback to context.status, and then 200
- status = status || context.status || HttpStatusCodes.OK;
- respond = h.response(html);
- } else if (HttpStatus.redirect[status]) {
- respond = h.redirect(data.path);
- return respond.code(status);
- } else if (status >= HttpStatusCodes.OK && status < 300) {
- respond = h.response(html);
- } else if (routeOptions.responseForBadStatus) {
- const output = routeOptions.responseForBadStatus(request, routeOptions, data);
- status = output.status;
- respond = h.response(output.html);
- } else {
- // should not reach here w/o html because user returned content
- // would have to return a literal string that has no `.status`
- // and html being undefined to be able to skip all the cases above
- respond = h.response(html);
- }
-
- const response = context.user && context.user.response;
-
- if (response) {
- Object.assign(respond.headers, response.headers);
- }
-
- return respond.code(status);
- })
- .catch(err => {
- const output = routeOptions.responseForError(request, routeOptions, err);
-
- return h.response(output.html).code(output.status);
- });
-};
-
-const registerRoutes = require("./register-routes");
-
-const register = (server, options) => registerRoutes(server, options, DefaultHandleRoute);
-
-const pkg = require("../../package.json");
-
-module.exports = {
- register,
- registerRoutes: register,
- pkg
-};
diff --git a/packages/electrode-react-webapp/lib/hapi/register-routes.js b/packages/electrode-react-webapp/lib/hapi/register-routes.js
deleted file mode 100644
index 99f27ed8f..000000000
--- a/packages/electrode-react-webapp/lib/hapi/register-routes.js
+++ /dev/null
@@ -1,42 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, max-params, max-statements, complexity */
-
-const _ = require("lodash");
-const Path = require("path");
-const ReactWebapp = require("../react-webapp");
-const { responseForError, responseForBadStatus } = require("../utils");
-
-const registerRoutes = (server, options, defaultRouteHandler) => {
- const registerOptions = ReactWebapp.setupOptions(options);
-
- _.each(registerOptions.paths, (pathData, path) => {
- const routeOptions = ReactWebapp.setupPathOptions(registerOptions, path);
- const routeHandler = ReactWebapp.makeRouteHandler(routeOptions);
-
- routeOptions.uiConfig = Object.assign(
- { webappPrefix: "" },
- _.get(server, "settings.app.config.ui", {}),
- routeOptions.uiConfig
- );
-
- const basePath = routeOptions.uiConfig.basePath || "/";
-
- const handleRoute = options.handleRoute || defaultRouteHandler;
- _.defaults(routeOptions, { responseForError, responseForBadStatus });
- const contentResolver = ReactWebapp.getContentResolver(registerOptions, pathData, path);
- routeOptions.path = path;
- routeOptions.pathData = pathData;
- server.route({
- method: pathData.method || "GET",
- path: Path.posix.join(basePath, path),
- config: pathData.config || {},
- handler: (req, hOrReply) => {
- const content = contentResolver(req.app.webpackDev);
- return handleRoute(req, hOrReply, routeHandler, content, routeOptions);
- }
- });
- });
-};
-
-module.exports = registerRoutes;
diff --git a/packages/electrode-react-webapp/lib/http-status.js b/packages/electrode-react-webapp/lib/http-status.js
deleted file mode 100644
index 471d1a045..000000000
--- a/packages/electrode-react-webapp/lib/http-status.js
+++ /dev/null
@@ -1,13 +0,0 @@
-"use strict";
-
-const HttpStatusCodes = require("http-status-codes");
-
-module.exports = {
- // Status codes where we want to redirect the user
- redirect: {
- [HttpStatusCodes.MOVED_PERMANENTLY]: true,
- [HttpStatusCodes.MOVED_TEMPORARILY]: true,
- [HttpStatusCodes.PERMANENT_REDIRECT]: true,
- [HttpStatusCodes.TEMPORARY_REDIRECT]: true
- }
-};
diff --git a/packages/electrode-react-webapp/lib/index.html b/packages/electrode-react-webapp/lib/index.html
deleted file mode 100644
index cdb99e53c..000000000
--- a/packages/electrode-react-webapp/lib/index.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/lib/jsx/Component.js b/packages/electrode-react-webapp/lib/jsx/Component.js
deleted file mode 100644
index f1518de8c..000000000
--- a/packages/electrode-react-webapp/lib/jsx/Component.js
+++ /dev/null
@@ -1,18 +0,0 @@
-"use strict";
-
-class Component {
- constructor(props, context) {
- this.props = props;
- this.context = context;
- }
-
- isComponent() {
- return true;
- }
-
- render() {
- return "component";
- }
-}
-
-module.exports = Component;
diff --git a/packages/electrode-react-webapp/lib/jsx/IndexPage.js b/packages/electrode-react-webapp/lib/jsx/IndexPage.js
deleted file mode 100644
index 51d1316ce..000000000
--- a/packages/electrode-react-webapp/lib/jsx/IndexPage.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict";
-
-const Component = require("./Component");
-
-class IndexPage extends Component {
- static memoize(props) {
- return ``;
- }
-}
-
-module.exports = IndexPage;
diff --git a/packages/electrode-react-webapp/lib/jsx/JsxRenderer.js b/packages/electrode-react-webapp/lib/jsx/JsxRenderer.js
deleted file mode 100644
index 657447647..000000000
--- a/packages/electrode-react-webapp/lib/jsx/JsxRenderer.js
+++ /dev/null
@@ -1,272 +0,0 @@
-"use strict";
-
-/* eslint-disable max-statements, max-params, prefer-template, complexity */
-
-const assert = require("assert");
-const _ = require("lodash");
-const loadHandler = require("../load-handler");
-const RenderContext = require("../render-context");
-const { omittedCloseTags, expandProps } = require("./utils");
-const Token = require("../token");
-const { TOKEN_HANDLER } = require("../symbols");
-const xaa = require("xaa");
-
-class JsxRenderer {
- constructor(options) {
- this._options = options;
-
- this._tokenHandlers = [].concat(this._options.tokenHandlers).filter(x => x);
- this._handlersMap = {};
- this._tokens = {};
- // the same context that gets passed to each token handler's setup function
- this._handlerContext = _.merge(
- {
- user: {
- // set routeOptions in user also for consistency
- routeOptions: options.routeOptions
- }
- },
- options
- );
- this._template = options.template;
- }
-
- get insertTokenIds() {
- return this._options.insertTokenIds;
- }
-
- get templateFullPath() {
- return this._options.templateFullPath;
- }
-
- render(options) {
- const defer = xaa.makeDefer();
- const context = new RenderContext(options, this);
-
- return xaa
- .each(this._beforeRenders, r => r.beforeRender(context))
- .then(() => {
- return this._render(this._template, context, 0, defer);
- })
- .then(() => {
- return defer.promise
- .then(() => context.output.close())
- .then(result => {
- /* istanbul ignore next */
- return xaa
- .each(this._afterRenders, r => r.afterRender(context))
- .then(() => {
- context.result = context.isVoidStop ? context.voidResult : result;
-
- return context;
- });
- });
- })
- .catch(err => {
- context.result = err;
- return context;
- });
- }
-
- _render(element, context, depth, defer) {
- /* istanbul ignore next */
- const done = () => defer && defer.resolve();
-
- if (context.isFullStop || context.isVoidStop) {
- return done();
- }
-
- if (typeof element === "string") {
- context.output.add(`${element}\n`);
- return done();
- } else if (!element) {
- return done();
- }
-
- let close;
-
- const handleClose = () => {
- if (close) {
- context.output.add(`${close}\n`);
- } else {
- context.output.add(`\n`);
- }
-
- return defer && defer.resolve();
- };
-
- const handleElementChildren = () => {
- if (!element.children) {
- return handleClose();
- }
-
- let ix = 0;
-
- const nextChild = () => {
- if (ix >= element.children.length) {
- return handleClose();
- } else {
- const child = element.children[ix++];
-
- try {
- const promise = this._render(child, context, depth);
- if (promise) {
- return promise.then(nextChild);
- } else {
- return nextChild();
- }
- } catch (err) {
- if (defer) return defer.reject(err);
-
- throw err;
- }
- }
- };
-
- const promise = nextChild();
-
- return !defer && promise;
- };
-
- const handleElementResult = rendered => {
- if (!rendered) {
- return handleClose();
- }
-
- if (typeof rendered === "string") {
- context.output.add(rendered);
- return handleClose();
- } else if (rendered.then) {
- return rendered
- .then(asyncRendered => {
- return this._render(asyncRendered, context, depth + 1);
- })
- .then(handleClose)
- .catch(err => {
- context.handleError(err);
- });
- } else {
- // TODO: is try/catch needed for this block? Need test case.
- const promise = this._render(rendered, context, depth + 1);
- if (promise) {
- return promise
- .then(asyncRendered => {
- return this._render(asyncRendered, context, depth + 1);
- })
- .then(handleClose);
- } else {
- return handleClose();
- }
- }
- };
-
- if (element.memoize) {
- context.output.add(`${element.memoize}\n`);
- } else if (element.tag) {
- if (!omittedCloseTags[element.tag]) {
- close = `${element.tag}>`;
- context.output.add(`<${element.tag}${expandProps(element.props, context)}>`);
- } else {
- context.output.add(`<${element.tag}${expandProps(element.props, context)}/>`);
- }
- } else if (!element.type) {
- return handleElementResult(
- element(element.props, context, { element, depth, output: context.output })
- );
- } else if (element.Construct) {
- const inst = new element.Construct(element.props, context);
- return handleElementResult(
- inst.render(element.props, context, { depth, output: context.output })
- );
- } else {
- const r = element.type(element.props, context, { element, depth, output: context.output });
- return handleElementResult(r);
- }
-
- return handleElementChildren();
- }
-
- initializeRenderer(reset) {
- if (reset || !this._handlersLookup) {
- this._initializeTokenHandlers(this._tokenHandlers);
- this._handlersLookup = this._tokenHandlers.reverse();
- }
- }
-
- _loadTokenHandler(path) {
- const mod = loadHandler(path);
- return mod(this._handlerContext, this);
- }
-
- _applyTokenLoad(element, inst) {
- inst.load(this._options);
-
- if (inst[TOKEN_HANDLER]) return;
-
- const handler = this._handlersLookup.find(h => h.tokens.hasOwnProperty(inst.id));
- if (!handler) return;
-
- const tkFunc = handler.tokens[inst.id];
- if (typeof tkFunc === "function") {
- inst.setHandler(tkFunc);
- } else {
- element.memoize = tkFunc;
- }
- }
-
- setupTokenInst(element, scope, forRequire) {
- let tokenInst;
- let memId;
-
- if (scope.depth < 1) {
- memId = `${element.props._id}_${element.id}`;
- tokenInst = this._tokens[memId];
-
- if (tokenInst) {
- return tokenInst;
- }
- }
-
- const id = forRequire ? `require(${element.props._id})` : element.props._id;
-
- tokenInst = new Token(id, 0, element.props, this.templateFullPath);
-
- if (memId) {
- this._tokens[memId] = tokenInst;
- }
-
- this._applyTokenLoad(element, tokenInst);
-
- return tokenInst;
- }
-
- getTokenInst(element) {
- return this._tokens[element.props._id];
- }
-
- _initializeTokenHandlers(filenames) {
- this._tokenHandlers = filenames.map(fname => {
- let handler;
- if (typeof fname === "string") {
- handler = this._loadTokenHandler(fname);
- } else {
- handler = fname;
- assert(handler.name, "electrode-react-webapp Template token handler missing name");
- }
- if (!handler.name) {
- handler = {
- name: fname,
- tokens: handler
- };
- }
- assert(handler.tokens, "electrode-react-webapp Template token handler missing tokens");
- this._handlersMap[handler.name] = handler;
- return handler;
- });
-
- this._beforeRenders = this._tokenHandlers.filter(x => x.beforeRender);
- this._afterRenders = this._tokenHandlers.filter(x => x.afterRender);
- }
-}
-
-module.exports = JsxRenderer;
diff --git a/packages/electrode-react-webapp/lib/jsx/Literal.js b/packages/electrode-react-webapp/lib/jsx/Literal.js
deleted file mode 100644
index e29d22a0a..000000000
--- a/packages/electrode-react-webapp/lib/jsx/Literal.js
+++ /dev/null
@@ -1,42 +0,0 @@
-"use strict";
-
-/* eslint-disable no-unused-vars, no-magic-numbers */
-
-const Path = require("path");
-const Fs = require("fs");
-const _ = require("lodash");
-
-const MEMOIZE = {};
-
-function Literal(props, context, scope) {
- const renderer = context.asyncTemplate;
-
- let data;
-
- if (props.file) {
- const fp = Path.resolve(props.file);
-
- if (MEMOIZE[fp]) {
- data = MEMOIZE[fp];
- } else {
- try {
- data = Fs.readFileSync(fp, _.get(props, "encoding", "utf8"));
- } catch (err) {
- const cwd = process.cwd();
- /* istanbul ignore next */
- const msg = cwd.length > 3 ? err.message.replace(cwd, "CWD") : err.message;
- data = `Literal reading file failed: ${msg} `;
- }
- }
-
- if (props._memoize !== false) {
- MEMOIZE[fp] = data;
- }
- } else {
- data = "Literal props missing file ";
- }
-
- return data;
-}
-
-module.exports = Literal;
diff --git a/packages/electrode-react-webapp/lib/jsx/Require.js b/packages/electrode-react-webapp/lib/jsx/Require.js
deleted file mode 100644
index 63bd77e5c..000000000
--- a/packages/electrode-react-webapp/lib/jsx/Require.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-const processToken = require("./process-token");
-
-function Require(props, context, scope) {
- return processToken(props, context, scope, true);
-}
-
-module.exports = Require;
diff --git a/packages/electrode-react-webapp/lib/jsx/Token.js b/packages/electrode-react-webapp/lib/jsx/Token.js
deleted file mode 100644
index 187acb462..000000000
--- a/packages/electrode-react-webapp/lib/jsx/Token.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-const processToken = require("./process-token");
-
-function Token(props, context, scope) {
- return processToken(props, context, scope);
-}
-
-module.exports = Token;
diff --git a/packages/electrode-react-webapp/lib/jsx/index.js b/packages/electrode-react-webapp/lib/jsx/index.js
deleted file mode 100644
index 04331874c..000000000
--- a/packages/electrode-react-webapp/lib/jsx/index.js
+++ /dev/null
@@ -1,55 +0,0 @@
-"use strict";
-
-const Component = require("./Component");
-const Token = require("./Token");
-const IndexPage = require("./IndexPage");
-const Require = require("./Require");
-const Literal = require("./Literal");
-const JsxRenderer = require("./JsxRenderer");
-
-let ELEMENT_ID = 0;
-
-function createElement(type, props, ...children) {
- children = children.length > 0 ? children : undefined;
-
- if (children) {
- children = children.reduce((a, c) => a.concat(c), []);
- }
-
- if (!props) {
- props = { children };
- } else {
- props = Object.assign({ children }, props);
- }
-
- const element = {
- id: ELEMENT_ID++,
- type,
- children,
- props
- };
-
- const literal = typeof type === "string";
-
- if (literal) {
- element.tag = type.toLowerCase();
- } else if (type.prototype && type.prototype.isComponent) {
- element.Construct = type;
- }
-
- if (!literal && type.memoize && props._memoize !== false) {
- element.memoize = type.memoize(props, children);
- }
-
- return element;
-}
-
-module.exports = {
- Component,
- Token,
- Literal,
- IndexPage,
- Require,
- JsxRenderer,
- createElement
-};
diff --git a/packages/electrode-react-webapp/lib/jsx/process-token.js b/packages/electrode-react-webapp/lib/jsx/process-token.js
deleted file mode 100644
index 273882107..000000000
--- a/packages/electrode-react-webapp/lib/jsx/process-token.js
+++ /dev/null
@@ -1,46 +0,0 @@
-"use strict";
-
-/* eslint-disable max-params */
-
-const { TOKEN_HANDLER } = require("../symbols");
-
-const _ = require("lodash");
-
-function processToken(props, context, scope, forRequire = false) {
- const renderer = context.asyncTemplate;
-
- const tokenInst = renderer.setupTokenInst(scope.element, scope, forRequire);
-
- if (scope.element.memoize) {
- return scope.output.add(scope.element.memoize);
- }
-
- if (tokenInst[TOKEN_HANDLER] === null) {
- if (renderer.insertTokenIds) {
- return ``;
- }
- return null;
- }
-
- const insertTokenIds =
- props._insertTokenIds !== false && (props._insertTokenIds || renderer.insertTokenIds);
-
- if (insertTokenIds) {
- scope.output.add(
- `\n`
- );
- }
-
- const r = tokenInst[TOKEN_HANDLER](context, tokenInst);
- return context.handleTokenResult(tokenInst.id, r, err => {
- if (insertTokenIds) {
- scope.output.add(``);
- }
- // if err, then handler has caused/returned an error
- if (err) {
- throw err;
- }
- });
-}
-
-module.exports = processToken;
diff --git a/packages/electrode-react-webapp/lib/jsx/utils.js b/packages/electrode-react-webapp/lib/jsx/utils.js
deleted file mode 100644
index c721d0a65..000000000
--- a/packages/electrode-react-webapp/lib/jsx/utils.js
+++ /dev/null
@@ -1,45 +0,0 @@
-"use strict";
-
-function expandProps(props, context) {
- let s = "";
-
- for (const key in props) {
- if (key !== "children") {
- let v = props[key];
- if (typeof v === "function") {
- v = v(context);
- }
-
- s = `${s} ${key}="${v}"`;
- }
- }
- return s;
-}
-
-module.exports = {
- expandProps,
-
- // For HTML, certain tags should omit their close tag. We keep a whitelist for
- // those special-case tags.
-
- // copied from react-dom/server
-
- omittedCloseTags: {
- area: true,
- base: true,
- br: true,
- col: true,
- embed: true,
- hr: true,
- img: true,
- input: true,
- keygen: true,
- link: true,
- meta: true,
- param: true,
- source: true,
- track: true,
- wbr: true
- // NOTE: menuitem's close tag should be omitted, but that causes problems.
- }
-};
diff --git a/packages/electrode-react-webapp/lib/koa/index.js b/packages/electrode-react-webapp/lib/koa/index.js
deleted file mode 100644
index bf4821ad7..000000000
--- a/packages/electrode-react-webapp/lib/koa/index.js
+++ /dev/null
@@ -1,84 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, max-params */
-
-const _ = require("lodash");
-const ReactWebapp = require("../react-webapp");
-const HttpStatus = require("../http-status");
-const { responseForError, responseForBadStatus } = require("../utils");
-
-const getDataHtml = data => (data.html !== undefined ? data.html : data);
-
-const DefaultHandleRoute = (request, response, handler, content, routeOptions) => {
- return handler({ content, mode: request.query.__mode || "", request })
- .then(context => {
- const data = context.result;
- if (data instanceof Error) {
- throw data;
- }
-
- if (data.status === undefined) {
- response.status = 200;
- response.body = data;
- } else if (HttpStatus.redirect[data.status]) {
- response.redirect(data.path);
- response.status = data.status;
- } else if (data.status >= 200 && data.status < 300) {
- response.body = getDataHtml(data);
- } else if (routeOptions.responseForBadStatus) {
- const output = routeOptions.responseForBadStatus(request, routeOptions, data);
- response.status = output.status;
- response.body = output.html;
- } else {
- response.status = data.status;
- response.body = getDataHtml(data);
- }
- return response;
- })
- .catch(err => {
- const output = routeOptions.responseForError(request, routeOptions, err);
- response.status = output.status;
- response.body = output.html;
- });
-};
-
-const registerRoutes = (router, options, next = () => {}) => {
- const registerOptions = ReactWebapp.setupOptions(options);
-
- _.each(registerOptions.paths, (v, path) => {
- const routeOptions = _.defaults({ htmlFile: v.htmlFile }, registerOptions);
- const routeHandler = ReactWebapp.makeRouteHandler(routeOptions);
-
- routeOptions.uiConfig = Object.assign(
- {},
- _.get(router, "config.ui", {}),
- routeOptions.uiConfig
- );
-
- const handleRoute = options.handleRoute || DefaultHandleRoute;
- _.defaults(routeOptions, { responseForError, responseForBadStatus });
-
- let methods = v.method || ["GET"];
- if (!Array.isArray(methods)) {
- methods = [methods];
- }
-
- const contentResolver = ReactWebapp.getContentResolver(registerOptions, v.content, path);
-
- _.each(methods, method => {
- if (method === "*") {
- method = "ALL";
- }
-
- router[method.toLowerCase()](path, async (ctx, next1) => {
- const content = contentResolver(ctx.webpackDev);
- await handleRoute(ctx.request, ctx.response, routeHandler, content, routeOptions);
- return next1();
- });
- });
- });
-
- next();
-};
-
-module.exports = registerRoutes;
diff --git a/packages/electrode-react-webapp/lib/load-handler.js b/packages/electrode-react-webapp/lib/load-handler.js
deleted file mode 100644
index 66b840555..000000000
--- a/packages/electrode-react-webapp/lib/load-handler.js
+++ /dev/null
@@ -1,46 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, no-console */
-
-const Path = require("path");
-const requireAt = require("require-at");
-const optionalRequire = require("optional-require");
-
-const failLoadTokenModule = (m, e) => {
- console.error(
- `error: electrode-react-webapp failed to load token process module ${m}`,
- `Error:`,
- e
- );
- return () => ({ process: () => `\ntoken process module ${m} failed to load\n` });
-};
-
-const notFoundLoadTokenModule = m => {
- console.error(`error: electrode-react-webapp can't find token process module ${m}`);
- return () => ({ process: () => `\ntoken process module ${m} not found\n` });
-};
-
-module.exports = (path, tmplDir, customCall) => {
- const tokenMod = optionalRequire(requireAt(Path.resolve(tmplDir || "")))(path, {
- fail: e => failLoadTokenModule(path, e),
- notFound: () => notFoundLoadTokenModule(path)
- });
-
- if (typeof tokenMod === "function") {
- return tokenMod;
- }
- if (tokenMod.tokenHandler) {
- return tokenMod.tokenHandler;
- }
- if (tokenMod.default) {
- return tokenMod.default;
- }
-
- if (customCall && tokenMod[customCall]) {
- return tokenMod;
- }
- throw new Error(
- `electrode-react-webapp: token module invalid - should export a function directly \
-or as 'default' or 'tokenHandler'`
- );
-};
diff --git a/packages/electrode-react-webapp/lib/react-webapp.js b/packages/electrode-react-webapp/lib/react-webapp.js
deleted file mode 100644
index c5a4fab47..000000000
--- a/packages/electrode-react-webapp/lib/react-webapp.js
+++ /dev/null
@@ -1,313 +0,0 @@
-"use strict";
-
-/* eslint-disable max-statements, global-require */
-
-const _ = require("lodash");
-const Path = require("path");
-const assert = require("assert");
-const AsyncTemplate = require("./async-template");
-const { JsxRenderer } = require("./jsx");
-
-const {
- getOtherStats,
- getOtherAssets,
- resolveChunkSelector,
- loadAssetsFromStats,
- getStatsPath,
- invokeTemplateProcessor,
- makeDevBundleBase
-} = require("./utils");
-
-const otherStats = getOtherStats();
-
-function initializeTemplate(
- { htmlFile, templateFile, tokenHandlers, cacheId, cacheKey, options },
- routeOptions
-) {
- const tmplFile = templateFile || htmlFile;
- cacheKey = cacheKey || (cacheId && `${tmplFile}#${cacheId}`) || tmplFile;
-
- let asyncTemplate = routeOptions._templateCache[cacheKey];
- if (asyncTemplate) {
- return asyncTemplate;
- }
-
- if (options) {
- routeOptions = Object.assign({}, routeOptions, options);
- }
-
- const userTokenHandlers = []
- .concat(tokenHandlers, routeOptions.tokenHandler, routeOptions.tokenHandlers)
- .filter(x => x);
-
- let finalTokenHandlers = userTokenHandlers;
-
- // Inject the built-in react/token-handlers if it is not in user's handlers
- // and replaceTokenHandlers option is false
- if (!routeOptions.replaceTokenHandlers) {
- const reactTokenHandlers = Path.join(__dirname, "react/token-handlers");
- finalTokenHandlers =
- userTokenHandlers.indexOf(reactTokenHandlers) < 0
- ? [reactTokenHandlers].concat(userTokenHandlers)
- : userTokenHandlers;
- }
-
- if (!templateFile) {
- asyncTemplate = new AsyncTemplate({
- htmlFile,
- tokenHandlers: finalTokenHandlers.filter(x => x),
- insertTokenIds: routeOptions.insertTokenIds,
- routeOptions
- });
-
- invokeTemplateProcessor(asyncTemplate, routeOptions);
- asyncTemplate.initializeRenderer();
- } else {
- const templateFullPath = require.resolve(tmplFile);
- const template = require(tmplFile);
- asyncTemplate = new JsxRenderer({
- templateFullPath: Path.dirname(templateFullPath),
- template: _.get(template, "default", template),
- tokenHandlers: finalTokenHandlers.filter(x => x),
- insertTokenIds: routeOptions.insertTokenIds,
- routeOptions
- });
- asyncTemplate.initializeRenderer();
- }
-
- return (routeOptions._templateCache[cacheKey] = asyncTemplate);
-}
-
-function makeRouteHandler(routeOptions) {
- routeOptions._templateCache = {};
- let defaultSelection;
-
- if (routeOptions.templateFile) {
- defaultSelection = {
- templateFile:
- typeof routeOptions.templateFile === "string"
- ? Path.resolve(routeOptions.templateFile)
- : Path.join(__dirname, "../template/index")
- };
- } else {
- defaultSelection = { htmlFile: routeOptions.htmlFile };
- }
-
- const render = (options, templateSelection) => {
- let selection = templateSelection || defaultSelection;
- if (templateSelection && !templateSelection.templateFile && !templateSelection.htmlFile) {
- selection = Object.assign({}, templateSelection, defaultSelection);
- }
- const asyncTemplate = initializeTemplate(selection, routeOptions);
- return asyncTemplate.render(options);
- };
-
- return options => {
- if (routeOptions.selectTemplate) {
- const selection = routeOptions.selectTemplate(options.request, routeOptions);
-
- if (selection && selection.then) {
- return selection.then(x => render(options, x));
- }
-
- return render(options, selection);
- }
-
- const asyncTemplate = initializeTemplate(defaultSelection, routeOptions);
- return asyncTemplate.render(options);
- };
-}
-
-const setupOptions = options => {
- const https = process.env.WEBPACK_DEV_HTTPS && process.env.WEBPACK_DEV_HTTPS !== "false";
-
- const pluginOptionsDefaults = {
- pageTitle: "Untitled Electrode Web Application",
- webpackDev: process.env.WEBPACK_DEV === "true",
- renderJS: true,
- serverSideRendering: true,
- htmlFile: Path.join(__dirname, "index.html"),
- devServer: {
- protocol: https ? "https" : "http",
- host: process.env.WEBPACK_DEV_HOST || process.env.WEBPACK_HOST || "localhost",
- port: process.env.WEBPACK_DEV_PORT || "2992",
- https
- },
- unbundledJS: {
- enterHead: [],
- preBundle: [],
- postBundle: []
- },
- paths: {},
- stats: "dist/server/stats.json",
- otherStats,
- iconStats: "dist/server/iconstats.json",
- criticalCSS: "dist/js/critical.css",
- buildArtifacts: ".build",
- prodBundleBase: "/js/",
- cspNonceValue: undefined
- };
-
- const pluginOptions = _.defaultsDeep({}, options, pluginOptionsDefaults);
- const chunkSelector = resolveChunkSelector(pluginOptions);
- const devBundleBase = makeDevBundleBase(pluginOptions.devServer);
- const statsPath = getStatsPath(pluginOptions.stats, pluginOptions.buildArtifacts);
-
- const assets = loadAssetsFromStats(statsPath);
- const otherAssets = getOtherAssets(pluginOptions);
- pluginOptions.__internals = _.defaultsDeep({}, pluginOptions.__internals, {
- assets,
- otherAssets,
- chunkSelector,
- devBundleBase
- });
-
- return pluginOptions;
-};
-
-const pathSpecificOptions = [
- "htmlFile",
- "templateFile",
- "insertTokenIds",
- "pageTitle",
- "selectTemplate",
- "responseForBadStatus",
- "responseForError"
-];
-
-const setupPathOptions = (routeOptions, path) => {
- const pathData = _.get(routeOptions, ["paths", path], {});
- const pathOverride = _.get(routeOptions, ["paths", path, "overrideOptions"], {});
- const pathOptions = pathData.options;
- return _.defaultsDeep(
- _.pick(pathData, pathSpecificOptions),
- {
- tokenHandler: [].concat(routeOptions.tokenHandler, pathData.tokenHandler),
- tokenHandlers: [].concat(routeOptions.tokenHandlers, pathData.tokenHandlers)
- },
- pathOptions,
- _.omit(pathOverride, "paths"),
- routeOptions
- );
-};
-
-//
-// The route path can supply:
-//
-// - a literal string
-// - a function
-// - an object
-//
-// If it's an object:
-// -- if it doesn't contain content, then it's assume to be the content.
-//
-// If it contains content, then it can contain:
-//
-// - method: HTTP method for the route
-// - config: route config (applicable for framework like Hapi)
-// - content: second level field to define content
-//
-// content can be:
-//
-// - a literal string
-// - a function
-// - an object
-//
-// If content is an object, it can contain module, a path to the JS module to require
-// to load the content.
-//
-const resolveContent = (pathData, xrequire) => {
- const resolveTime = Date.now();
-
- let content = pathData;
-
- // If it's an object, see if contains content field
- if (_.isObject(pathData) && pathData.hasOwnProperty("content")) {
- content = pathData.content;
- }
-
- if (!content && !_.isString(content)) return null;
-
- // content has module field, require it.
- if (!_.isString(content) && !_.isFunction(content) && content.module) {
- const mod = content.module.startsWith(".") ? Path.resolve(content.module) : content.module;
-
- xrequire = xrequire || require;
-
- try {
- return {
- fullPath: xrequire.resolve(mod),
- xrequire,
- resolveTime,
- content: xrequire(mod)
- };
- } catch (error) {
- const msg = `electrode-react-webapp: failed to load SSR content from module ${mod}`;
- console.error(msg, "\n", error); // eslint-disable-line
- return {
- fullPath: null,
- error,
- resolveTime,
- content: `electrode-react-webapp: SSR failed
-${msg}
-${error.stack}
-`
- };
- }
- }
-
- return {
- fullPath: null,
- resolveTime,
- content
- };
-};
-
-const getContentResolver = (registerOptions, pathData, path) => {
- let resolved;
-
- const resolveWithDev = (webpackDev, xrequire) => {
- if (!webpackDev.valid) {
- resolved = resolveContent("");
- } else if (webpackDev.hasErrors) {
- resolved = resolveContent("");
- } else if (!resolved || resolved.resolveTime < webpackDev.compileTime) {
- if (resolved && resolved.fullPath) {
- delete resolved.xrequire.cache[resolved.fullPath];
- }
- resolved = resolveContent(pathData, xrequire);
- }
-
- return resolved.content;
- };
-
- return (webpackDev, xrequire) => {
- if (webpackDev && registerOptions.serverSideRendering !== false) {
- return resolveWithDev(webpackDev, xrequire);
- }
-
- if (resolved) return resolved.content;
-
- if (registerOptions.serverSideRendering !== false) {
- resolved = resolveContent(pathData);
- assert(resolved, `You must define content for the webapp plugin path ${path}`);
- } else {
- resolved = {
- content: {
- status: 200,
- html: ""
- }
- };
- }
-
- return resolved.content;
- };
-};
-
-module.exports = {
- setupOptions,
- setupPathOptions,
- makeRouteHandler,
- resolveContent,
- getContentResolver
-};
diff --git a/packages/electrode-react-webapp/lib/react/content.js b/packages/electrode-react-webapp/lib/react/content.js
deleted file mode 100644
index dc17a2b5a..000000000
--- a/packages/electrode-react-webapp/lib/react/content.js
+++ /dev/null
@@ -1,92 +0,0 @@
-"use strict";
-
-const Fs = require("fs");
-const Path = require("path");
-const HttpStatusCodes = require("http-status-codes");
-
-const HTTP_ERROR_500 = 500;
-
-function getContent(renderSs, options, context) {
- let userContent = options.content;
-
- // prepare user content for container of SSR output
-
- if (typeof userContent === "string") {
- return Promise.resolve({ status: 200, html: userContent });
- }
-
- if (typeof userContent !== "function") return Promise.resolve(userContent);
-
- if (!renderSs) return Promise.resolve({ status: 200, html: "" });
-
- // invoke user content as a function, which could return any content
- // as static html or generated from react's renderToString
- userContent = userContent(options.request, options, context);
-
- if (userContent.catch) {
- // user function needs to generate the content async, so wait for it.
- return userContent.catch(err => {
- if (!err.status) err.status = HTTP_ERROR_500;
- throw err;
- });
- }
-
- return Promise.resolve(userContent);
-}
-
-function transformOutput(result, context) {
- const content = context.user.content;
- if (content && content.status !== HttpStatusCodes.OK) {
- return {
- verbatim: content.verbatim,
- status: content.status,
- path: content.path,
- store: content.store,
- html: result
- };
- }
-
- return result;
-}
-
-const htmlifyScripts = (scripts, scriptNonce) => {
- return scripts
- .map(x =>
- typeof x === "string"
- ? `\n`
- : x.map(n => ``).join("\n")
- )
- .join("\n");
-};
-
-const loadElectrodeDllAssets = routeOptions => {
- const tag = process.env.NODE_ENV === "production" ? "" : ".dev";
- try {
- const file = Path.resolve(
- routeOptions.electrodeDllAssetsPath || `dist/electrode-dll-assets${tag}.json`
- );
- return JSON.parse(Fs.readFileSync(file));
- } catch (err) {
- return {};
- }
-};
-
-const makeElectrodeDllScripts = (dllAssets, nonce) => {
- const scripts = [];
- for (const modName in dllAssets) {
- const cdnMapping = dllAssets[modName].cdnMapping;
- for (const bundle in cdnMapping) {
- scripts.push({ src: cdnMapping[bundle] });
- }
- }
-
- return htmlifyScripts([scripts], nonce);
-};
-
-module.exports = {
- getContent,
- transformOutput,
- htmlifyScripts,
- loadElectrodeDllAssets,
- makeElectrodeDllScripts
-};
diff --git a/packages/electrode-react-webapp/lib/react/handlers/prefetch-bundles.js b/packages/electrode-react-webapp/lib/react/handlers/prefetch-bundles.js
deleted file mode 100644
index 702f44f7d..000000000
--- a/packages/electrode-react-webapp/lib/react/handlers/prefetch-bundles.js
+++ /dev/null
@@ -1,13 +0,0 @@
-"use strict";
-
-module.exports = context => {
- const content = context.user.content;
- if (!content || !content.prefetch) return "";
-
- // allow user to include the `;
- } else {
- return content.prefetch;
- }
-};
diff --git a/packages/electrode-react-webapp/lib/react/token-handlers.js b/packages/electrode-react-webapp/lib/react/token-handlers.js
deleted file mode 100644
index 8f7f25231..000000000
--- a/packages/electrode-react-webapp/lib/react/token-handlers.js
+++ /dev/null
@@ -1,241 +0,0 @@
-"use strict";
-
-/* eslint-disable max-statements, max-depth */
-
-const groupScripts = require("../group-scripts");
-
-const {
- getIconStats,
- getCriticalCSS,
- getDevCssBundle,
- getDevJsBundle,
- getProdBundles,
- processRenderSsMode,
- getCspNonce,
- getBundleJsNameByQuery,
- isReadableStream
-} = require("../utils");
-
-const {
- getContent,
- transformOutput,
- htmlifyScripts,
- loadElectrodeDllAssets,
- makeElectrodeDllScripts
-} = require("./content");
-
-const prefetchBundles = require("./handlers/prefetch-bundles");
-const CONTENT_MARKER = "SSR_CONTENT";
-const HEADER_BUNDLE_MARKER = "WEBAPP_HEADER_BUNDLES";
-const BODY_BUNDLE_MARKER = "WEBAPP_BODY_BUNDLES";
-const DLL_BUNDLE_MARKER = "WEBAPP_DLL_BUNDLES";
-const TITLE_MARKER = "PAGE_TITLE";
-const PREFETCH_MARKER = "PREFETCH_BUNDLES";
-const META_TAGS_MARKER = "META_TAGS";
-const CRITICAL_CSS_MARKER = "CRITICAL_CSS";
-const APP_CONFIG_DATA_MARKER = "APP_CONFIG_DATA";
-const WEBAPP_START_SCRIPT_MARKER = "WEBAPP_START_SCRIPT";
-
-module.exports = function setup(handlerContext /*, asyncTemplate*/) {
- const routeOptions = handlerContext.user.routeOptions;
-
- const WEBPACK_DEV = routeOptions.webpackDev;
- const RENDER_JS = routeOptions.renderJS;
- const RENDER_SS = routeOptions.serverSideRendering;
- const assets = routeOptions.__internals.assets;
- const otherAssets = routeOptions.__internals.otherAssets;
- const devBundleBase = routeOptions.__internals.devBundleBase;
- const prodBundleBase = routeOptions.prodBundleBase;
- const chunkSelector = routeOptions.__internals.chunkSelector;
- const iconStats = getIconStats(routeOptions.iconStats);
- const criticalCSS = getCriticalCSS(routeOptions.criticalCSS);
-
- const routeData = {
- WEBPACK_DEV,
- RENDER_JS,
- RENDER_SS,
- assets,
- otherAssets,
- devBundleBase,
- prodBundleBase,
- chunkSelector,
- iconStats,
- criticalCSS
- };
-
- handlerContext.user.routeData = routeData;
-
- const bundleManifest = () => {
- if (!assets.manifest) {
- return "";
- }
-
- return WEBPACK_DEV
- ? `${devBundleBase}${assets.manifest}`
- : `${prodBundleBase}${assets.manifest}`;
- };
-
- const bundleJs = data => {
- if (!data.renderJs) {
- return "";
- }
- if (WEBPACK_DEV) {
- return data.devJSBundle;
- } else if (data.jsChunk) {
- const bundleJsName = getBundleJsNameByQuery(data, otherAssets);
- return `${prodBundleBase}${bundleJsName}`;
- } else {
- return "";
- }
- };
-
- const INITIALIZE = context => {
- const options = context.options;
- const request = options.request;
- const mode = options.mode;
- const renderSs = processRenderSsMode(request, RENDER_SS, mode);
-
- return getContent(renderSs, options, context).then(content => {
- if (content.render === false || content.html === undefined) {
- return context.voidStop(content);
- }
-
- const chunkNames = chunkSelector(request);
-
- const devCSSBundle = getDevCssBundle(chunkNames, routeData);
- const devJSBundle = getDevJsBundle(chunkNames, routeData);
-
- const { jsChunk, cssChunk } = getProdBundles(chunkNames, routeData);
- const { scriptNonce, styleNonce } = getCspNonce(request, routeOptions.cspNonceValue);
-
- const renderJs = RENDER_JS && mode !== "nojs";
-
- context.user = {
- request: options.request,
- response: {
- headers: {}
- },
- routeOptions,
- routeData,
- content,
- mode,
- renderJs,
- renderSs,
- scriptNonce,
- styleNonce,
- chunkNames,
- devCSSBundle,
- devJSBundle,
- jsChunk,
- cssChunk
- };
-
- if (content.useStream || isReadableStream(content.html)) {
- context.setMunchyOutput();
- }
-
- context.setOutputTransform(transformOutput);
-
- return context;
- });
- };
-
- const windowConfigKey = routeOptions.uiConfigKey || "_config";
-
- const tokenHandlers = {
- [CONTENT_MARKER]: context => {
- return (context.user.content && context.user.content.html) || "";
- },
-
- [TITLE_MARKER]: () => {
- return `${routeOptions.pageTitle} `;
- },
-
- [APP_CONFIG_DATA_MARKER]: context => {
- const { webappPrefix } = context.user.routeOptions.uiConfig;
- const key = `${webappPrefix}${windowConfigKey}`;
-
- return ``;
- },
-
- [HEADER_BUNDLE_MARKER]: context => {
- const manifest = bundleManifest();
- const manifestLink = manifest ? ` \n` : "";
- const css = [].concat(WEBPACK_DEV ? context.user.devCSSBundle : context.user.cssChunk);
-
- const cssLink = css.reduce((acc, file) => {
- file = WEBPACK_DEV ? file : prodBundleBase + file.name;
- return `${acc} `;
- }, "");
-
- const htmlScripts = htmlifyScripts(
- groupScripts(routeOptions.unbundledJS.enterHead).scripts,
- context.user.scriptNonce
- );
-
- return `${manifestLink}${cssLink}${htmlScripts}`;
- },
-
- [BODY_BUNDLE_MARKER]: context => {
- context.user.query = context.user.request.query;
- const js = bundleJs(context.user);
- const jsLink = js ? { src: js } : "";
-
- const ins = routeOptions.unbundledJS.preBundle.concat(
- jsLink,
- routeOptions.unbundledJS.postBundle
- );
- const htmlScripts = htmlifyScripts(groupScripts(ins).scripts, context.user.scriptNonce);
-
- return `${htmlScripts}`;
- },
-
- [DLL_BUNDLE_MARKER]: context => {
- if (WEBPACK_DEV) {
- return makeElectrodeDllScripts(loadElectrodeDllAssets(context.user.routeOptions));
- }
-
- if (context.user.routeData.dllAssetScripts === undefined) {
- context.user.routeData.dllAssetScripts = makeElectrodeDllScripts(
- loadElectrodeDllAssets(context.user.routeOptions),
- context.user.scriptNonce
- );
- }
-
- return context.user.routeData.dllAssetScripts;
- },
-
- [PREFETCH_MARKER]: prefetchBundles,
-
- [META_TAGS_MARKER]: iconStats,
-
- [CRITICAL_CSS_MARKER]: context => {
- return criticalCSS ? `` : "";
- },
-
- [WEBAPP_START_SCRIPT_MARKER]: context => {
- const { webappPrefix } = context.user.routeOptions.uiConfig;
- /* istanbul ignore next */
- const startFuncName = webappPrefix ? `${webappPrefix}WebappStart` : "webappStart";
- return ``;
- },
-
- INITIALIZE,
- HEAD_INITIALIZE: null,
- HEAD_CLOSED: null,
- AFTER_SSR_CONTENT: null,
- BODY_CLOSED: null,
- HTML_CLOSED: null
- };
-
- return {
- name: "electrode-react-token-handlers",
- routeOptions,
- routeData,
- tokens: tokenHandlers
- };
-};
diff --git a/packages/electrode-react-webapp/lib/render-context.js b/packages/electrode-react-webapp/lib/render-context.js
deleted file mode 100644
index 31ca24a3f..000000000
--- a/packages/electrode-react-webapp/lib/render-context.js
+++ /dev/null
@@ -1,133 +0,0 @@
-"use strict";
-
-const RenderOutput = require("./render-output");
-const Munchy = require("munchy");
-const utils = require("./utils");
-
-class RenderContext {
- constructor(options, asyncTemplate) {
- this.user = false;
- this.options = options;
- this.output = new RenderOutput(this);
- this.asyncTemplate = asyncTemplate;
- this._handlersMap = asyncTemplate.handlersMap;
- this.handleError = err => !this.stop && this.voidStop(err);
- this.transform = x => x;
- this._stop = 0;
- }
-
- // return a token handler by name
- getTokenHandler(name) {
- return this._handlersMap[name];
- }
-
- // return the tokens object of a handler by name
- getTokens(name) {
- return this._handlersMap[name].tokens;
- }
-
- // set a send callback for receiving the render output
- // Note: cannot be used with setOutputTransform
- setOutputSend(send) {
- this.send = send;
- }
-
- setMunchyOutput(munchy) {
- this.munchy = munchy || new Munchy({ handleStreamError: utils.munchyHandleStreamError });
- }
-
- // set a callback to take the output result and transform it
- // Note: cannot be used with setOutputSend
- setOutputTransform(transform) {
- this.transform = result => transform(result, this);
- }
-
- get stop() {
- return this._stop;
- }
-
- get status() {
- return this._status;
- }
-
- set status(s) {
- this._status = s;
- }
-
- /*
- * Allow user to intercept handling of the rendering flow and take over the response with handler
- *
- * - If no handler provided, then the error is returned.
- */
- intercept({ responseHandler }) {
- this._intercepted = { responseHandler };
- throw new Error("electrode-react-webapp: render-context - user intercepted");
- }
-
- //
- // set this any time to fully stop and close rendering
- // stop modes:
- // 1 - only process string tokens
- // 2 - fully stop immediately, no more token processing
- // 3 - completely void any render output and stop immediately,
- // replace output with result. This only works if output
- // is buffered and not streaming out immediately.
- //
- set stop(f) {
- this._stop = f;
- }
-
- fullStop() {
- this._stop = RenderContext.FULL_STOP;
- }
-
- get isFullStop() {
- return this._stop === RenderContext.FULL_STOP;
- }
-
- voidStop(result) {
- this._stop = RenderContext.VOID_STOP;
- this.voidResult = result;
- }
-
- get isVoidStop() {
- return this._stop === RenderContext.VOID_STOP;
- }
-
- softStop() {
- this._stop = RenderContext.SOFT_STOP;
- }
-
- get isSoftStop() {
- return this._stop === RenderContext.SOFT_STOP;
- }
-
- // helper to take the result of a token handler and process the returned result
- // according to if it's async or not, and then invoke the callback
- // - If it's a Promise (async), then wait for it before invoking callback
- // - else add it to output if it's a string, and then invoke callback
- // Note: If it's async, then the result from the Promise is not checked because
- // we don't know how token handler wants to deal with it.
- handleTokenResult(id, result, cb) {
- const addToOutput = res => {
- // if it's a string, buffer, or stream, then add to output
- if (typeof res === "string" || Buffer.isBuffer(res) || utils.isReadableStream(res)) {
- this.output.add(res);
- }
- // ignore other return value types
- return cb();
- };
- // it's a promise, wait for it before invoking callback
- if (result && result.then) {
- return result.then(addToOutput).catch(cb);
- } else {
- return addToOutput(result);
- }
- }
-}
-
-RenderContext.VOID_STOP = 3;
-RenderContext.FULL_STOP = 2;
-RenderContext.SOFT_STOP = 1;
-
-module.exports = RenderContext;
diff --git a/packages/electrode-react-webapp/lib/render-execute.js b/packages/electrode-react-webapp/lib/render-execute.js
deleted file mode 100644
index 0a2fa34f2..000000000
--- a/packages/electrode-react-webapp/lib/render-execute.js
+++ /dev/null
@@ -1,69 +0,0 @@
-"use strict";
-
-/* eslint-disable complexity */
-
-const { TOKEN_HANDLER } = require("./symbols");
-
-const executeSteps = {
- STEP_HANDLER: 0,
- STEP_STR_TOKEN: 1,
- STEP_NO_HANDLER: 2,
- STEP_LITERAL_HANDLER: 3
-};
-
-const { STEP_HANDLER, STEP_STR_TOKEN, STEP_NO_HANDLER, STEP_LITERAL_HANDLER } = executeSteps;
-
-function renderNext(err, xt) {
- const { renderSteps, context } = xt;
- if (err) {
- context.handleError(err);
- }
-
- const insertTokenId = tk => {
- context.output.add(`\n`);
- };
-
- const insertTokenIdEnd = tk => {
- context.output.add(`\n`);
- };
-
- if (context.isFullStop || context.isVoidStop || xt.stepIndex >= renderSteps.length) {
- const r = context.output.close();
- xt.resolve(r);
- return null;
- } else {
- // TODO: support soft stop
- const step = renderSteps[xt.stepIndex++];
- const tk = step.tk;
- const withId = step.insertTokenId;
- switch (step.code) {
- case STEP_HANDLER:
- if (withId) insertTokenId(tk);
- return context.handleTokenResult(tk.id, tk[TOKEN_HANDLER](context, tk), e => {
- if (withId) insertTokenIdEnd(tk);
- return renderNext(e, xt);
- });
- case STEP_STR_TOKEN:
- context.output.add(tk.str);
- break;
- case STEP_NO_HANDLER:
- context.output.add(``);
- break;
- case STEP_LITERAL_HANDLER:
- if (withId) insertTokenId(tk);
- context.output.add(step.data);
- if (withId) insertTokenIdEnd(tk);
- break;
- }
- return renderNext(null, xt);
- }
-}
-
-function executeRenderSteps(renderSteps, context) {
- return new Promise(resolve => {
- const xt = { stepIndex: 0, renderSteps, context, resolve };
- return renderNext(null, xt);
- });
-}
-
-module.exports = { executeRenderSteps, renderNext, executeSteps };
diff --git a/packages/electrode-react-webapp/lib/render-output.js b/packages/electrode-react-webapp/lib/render-output.js
deleted file mode 100644
index de5d0da61..000000000
--- a/packages/electrode-react-webapp/lib/render-output.js
+++ /dev/null
@@ -1,231 +0,0 @@
-"use strict";
-
-const assert = require("assert");
-
-class Output {
- constructor() {
- this._items = [];
- }
-
- add(data) {
- const x = this._items.length;
- this._items.push(data);
- return x;
- }
-
- get length() {
- return this._items.length;
- }
-
- stringify() {
- let out = "";
- for (const x of this._items) {
- if (typeof x === "string") {
- out += x;
- } else if (x && x.stringify) {
- out += x.stringify();
- } else {
- const typeName = (x && x.constructor && x.constructor.name) || typeof x;
- const msg = `RenderOutput unable to stringify item of type ${typeName}`;
- console.error("FATAL Error:", msg + "\n"); // eslint-disable-line
- throw new Error(msg);
- }
- }
- return out;
- }
-
- _munchItems(munchy) {
- for (const item of this._items) {
- if (item._munchItems) {
- item._munchItems(munchy);
- } else {
- munchy.munch(item);
- }
- }
- }
-
- sendToMunchy(munchy, done) {
- if (this._items.length > 0) {
- munchy.once("munched", done);
- this._munchItems(munchy);
- } else {
- process.nextTick(done);
- }
- }
-}
-
-class SpotOutput extends Output {
- constructor() {
- super();
- this._open = true;
- this._pos = -1;
- this._closeCb = null;
- }
-
- add(data) {
- assert(this._open, "SpotOutput closed");
- assert(
- typeof data === "string" || Buffer.isBuffer(data) || (data && data._readableState),
- "Must add only string/buffer/stream to SpotOutput"
- );
- return super.add(data);
- }
-
- close() {
- assert(this._open, "closing already closed SpotOutput");
- this._open = false;
- this._closeCb();
- }
-
- _onClose(cb) {
- this._closeCb = cb;
- }
-
- _spotPos() {
- return this._pos;
- }
-
- _setPos(x) {
- this._pos = x;
- }
-}
-
-class MainOutput extends Output {
- constructor() {
- super();
- this._pending = 0;
- }
-
- _addSpot(data) {
- const x = this.add(data);
- this._pending++;
- return x;
- }
-
- _closeSpot(x) {
- assert(this._items[x._spotPos()] === x, "closing unknown pending");
- this._pending--;
- }
-
- _hasPending() {
- return this._pending > 0;
- }
-}
-
-class RenderOutput {
- constructor(context) {
- this._output = new MainOutput();
- this._flushQ = [];
- this._context = context || { transform: x => x };
- this._result = ""; // will hold final result if context doesn't have send
- }
-
- // add data to the end of the output
- add(data) {
- this._output.add(data);
- }
-
- // reserve current end of output as an async fixed spot so data can be appended
- // at that point when they become available async, even if more data has been
- // added to the end of the output after this.
- reserve() {
- let output = this._output;
- const spot = new SpotOutput();
- spot._setPos(output._addSpot(spot));
- spot._onClose(() => {
- output._closeSpot(spot);
- output = undefined;
- this._checkFlushQ();
- });
- return spot;
- }
-
- // flush data so far
- flush() {
- if (this._output && this._output.length > 0) {
- this._flushQ.push(this._output);
- if (!this._end) {
- this._output = new MainOutput();
- } else {
- this._output = undefined;
- }
- }
-
- this._checkFlushQ();
- }
-
- // close the output and returns a promise that waits for all pending
- // spots to close and resolves with the final result
- close() {
- this._end = true;
-
- if (this._context.munchy) {
- this.flush();
- // streaming
- return this._context.transform(this._context.munchy, this);
- } else {
- const promise = new Promise((resolve, reject) => {
- this._resolve = resolve;
- this._reject = reject;
- });
- this.flush();
- return promise;
- }
- }
-
- _finish() {
- try {
- if (this._context.munchy) {
- // terminates munchy stream
- this._result = this._context.munchy;
- this._context.munchy.munch(null);
- }
-
- if (this._resolve) {
- this._resolve(this._context.transform(this._result, this));
- }
- } catch (error) {
- if (this._reject) {
- this._reject(error);
- } else {
- throw error;
- }
- }
-
- this._resolve = this._reject = undefined;
- }
-
- _checkFlushQ() {
- if (this._flushQ.length < 1) {
- if (this._end) {
- this._finish();
- }
- return;
- }
-
- const output = this._flushQ[0];
-
- if (!output._hasPending()) {
- this._flushQ.shift();
- // handle streaming
- // if this._context.munchy stream exist, then pipe output to it.
-
- if (this._context.munchy) {
- // send output to munchy stream
- output.sendToMunchy(this._context.munchy, () => this._checkFlushQ());
- } else {
- const x = output.stringify();
-
- if (this._context.send) {
- this._context.send(x);
- } else {
- this._result += x;
- }
-
- this._checkFlushQ();
- }
- }
- }
-}
-
-module.exports = RenderOutput;
diff --git a/packages/electrode-react-webapp/lib/renderer.js b/packages/electrode-react-webapp/lib/renderer.js
deleted file mode 100644
index d76bbb809..000000000
--- a/packages/electrode-react-webapp/lib/renderer.js
+++ /dev/null
@@ -1,85 +0,0 @@
-"use strict";
-
-const { executeSteps, executeRenderSteps } = require("./render-execute");
-
-const { STEP_HANDLER, STEP_STR_TOKEN, STEP_NO_HANDLER, STEP_LITERAL_HANDLER } = executeSteps;
-
-class Renderer {
- constructor(options) {
- const insertTokenIds = Boolean(options.insertTokenIds);
- // the last handler wins if it contains a token
- const tokenHandlers = options.tokenHandlers.reverse();
-
- const makeNullRemovedStep = (tk, cause) => {
- return {
- tk,
- insertTokenId: false,
- code: STEP_LITERAL_HANDLER,
- data: `\n`
- };
- };
-
- const makeHandlerStep = tk => {
- // look for first handler that has a token function for tk.id
- const handler = tokenHandlers.find(h => h.tokens.hasOwnProperty(tk.id));
-
- // no handler has function for token
- if (!handler) {
- const msg = `electrode-react-webapp: no handler found for token id ${tk.id}`;
- console.error(msg); // eslint-disable-line
- return { tk, code: STEP_NO_HANDLER };
- }
-
- const tkFunc = handler.tokens[tk.id];
-
- if (tkFunc === null) {
- if (insertTokenIds) return makeNullRemovedStep(tk, "handler set to null");
-
- return null;
- }
-
- if (typeof tkFunc !== "function") {
- // not a function, just add it to output
- return {
- tk,
- code: STEP_LITERAL_HANDLER,
- insertTokenId: insertTokenIds && !tk.props._noInsertId,
- data: tkFunc
- };
- }
-
- tk.setHandler(tkFunc);
-
- return { tk, code: STEP_HANDLER, insertTokenId: insertTokenIds && !tk.props._noInsertId };
- };
-
- const makeStep = tk => {
- // token is a literal string, just add it to output
- if (tk.hasOwnProperty("str")) {
- return { tk, code: STEP_STR_TOKEN };
- }
-
- // token is not pointing to a module, so lookup from token handlers
- if (!tk.isModule) return makeHandlerStep(tk);
-
- if (tk.custom === null) {
- if (insertTokenIds) return makeNullRemovedStep(tk, "process return null");
- return null;
- }
-
- return {
- tk,
- code: STEP_HANDLER,
- insertTokenId: options.insertTokenIds && !tk.props._noInsertId
- };
- };
-
- this.renderSteps = options.htmlTokens.map(makeStep).filter(x => x);
- }
-
- render(context) {
- return executeRenderSteps(this.renderSteps, context);
- }
-}
-
-module.exports = Renderer;
diff --git a/packages/electrode-react-webapp/lib/symbols.js b/packages/electrode-react-webapp/lib/symbols.js
deleted file mode 100644
index 23258f817..000000000
--- a/packages/electrode-react-webapp/lib/symbols.js
+++ /dev/null
@@ -1,6 +0,0 @@
-"use strict";
-
-module.exports = {
- TEMPLATE_DIR: Symbol("template dir"),
- TOKEN_HANDLER: Symbol("token handler")
-};
diff --git a/packages/electrode-react-webapp/lib/token.js b/packages/electrode-react-webapp/lib/token.js
deleted file mode 100644
index 08d43f258..000000000
--- a/packages/electrode-react-webapp/lib/token.js
+++ /dev/null
@@ -1,79 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, no-console, max-params, max-statements */
-
-const assert = require("assert");
-const loadHandler = require("./load-handler");
-const { TEMPLATE_DIR, TOKEN_HANDLER } = require("./symbols");
-
-const viewTokenModules = {};
-
-class Token {
- constructor(id, pos, props, templateDir) {
- this.id = id;
-
- // match `require(path/to/module)`
- const match = id.match(/^require\(['"]?([^'"\)]+)['"]?\)/);
- if (match) {
- this.modPath = match[1];
- this.isModule = true;
- } else if (id.startsWith("#")) {
- this.modPath = this.id.substr(1); // remove the leading #
- this.isModule = true;
- } else {
- this.isModule = false;
- }
-
- this.pos = pos;
- this.custom = undefined;
- this.wantsNext = undefined;
- this.props = props || {};
- if (this.props._call) {
- this._modCall = [].concat(this.props._call);
- }
- this[TOKEN_HANDLER] = null;
- this[TEMPLATE_DIR] = this.props[TEMPLATE_DIR] || templateDir || process.cwd();
- }
-
- // if token is a module, then load it
- load(options) {
- if (!this.isModule || this.custom !== undefined) return;
-
- let tokenMod = viewTokenModules[this.id];
-
- if (tokenMod === undefined) {
- tokenMod = loadHandler(this.modPath, this[TEMPLATE_DIR], this._modCall && this._modCall[0]);
- viewTokenModules[this.id] = tokenMod;
- }
-
- if (this._modCall) {
- // call setup function to get an instance
- const params = [options || {}, this].concat(this._modCall[1] || []);
- assert(
- tokenMod[this._modCall[0]],
- `electrode-react-webapp: _call of token ${this.id} - '${this._modCall[0]}' not found`
- );
- this.custom = tokenMod[this._modCall[0]](...params);
- } else {
- this.custom = tokenMod(options || {}, this);
- }
-
- if (this.custom === null) return;
-
- assert(
- this.custom && this.custom.process,
- `custom token ${this.id} module doesn't have process method`
- );
-
- // if process function takes more than one params, then it should take a
- // next callback so it can do async work, and call next after that's done.
- this.wantsNext = this.custom.process.length > 1;
- this.setHandler(context => this.custom.process(context, this));
- }
-
- setHandler(func) {
- this[TOKEN_HANDLER] = func;
- }
-}
-
-module.exports = Token;
diff --git a/packages/electrode-react-webapp/lib/utils.js b/packages/electrode-react-webapp/lib/utils.js
deleted file mode 100644
index 96adc9772..000000000
--- a/packages/electrode-react-webapp/lib/utils.js
+++ /dev/null
@@ -1,339 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers, no-console */
-
-const _ = require("lodash");
-const fs = require("fs");
-const Path = require("path");
-const requireAt = require("require-at");
-const assert = require("assert");
-const Url = require("url");
-
-const HTTP_PORT = "80";
-
-/**
- * Tries to import bundle chunk selector function if the corresponding option is set in the
- * webapp plugin configuration. The function takes a `request` object as an argument and
- * returns the chunk name.
- *
- * @param {Object} options - webapp plugin configuration options
- * @return {Function} function that selects the bundle based on the request object
- */
-function resolveChunkSelector(options) {
- if (options.bundleChunkSelector) {
- return require(Path.resolve(options.bundleChunkSelector)); // eslint-disable-line
- }
-
- return () => ({
- css: "main",
- js: "main"
- });
-}
-
-/**
- * Load stats.json which is created during build.
- * Attempt to load the stats.json file which contains a manifest of
- * The file contains bundle files which are to be loaded on the client side.
- *
- * @param {string} statsPath - path of stats.json
- * @returns {Promise.} an object containing an array of file names
- */
-function loadAssetsFromStats(statsPath) {
- let stats;
- try {
- stats = JSON.parse(fs.readFileSync(Path.resolve(statsPath)).toString());
- } catch (err) {
- return {};
- }
- const assets = {};
- const manifestAsset = _.find(stats.assets, asset => {
- return asset.name.endsWith("manifest.json");
- });
- const jsAssets = stats.assets.filter(asset => {
- return asset.name.endsWith(".js");
- });
- const cssAssets = stats.assets.filter(asset => {
- return asset.name.endsWith(".css");
- });
-
- if (manifestAsset) {
- assets.manifest = manifestAsset.name;
- }
-
- assets.js = jsAssets;
- assets.css = cssAssets;
-
- return assets;
-}
-
-function getIconStats(iconStatsPath) {
- let iconStats;
- try {
- iconStats = fs.readFileSync(Path.resolve(iconStatsPath)).toString();
- iconStats = JSON.parse(iconStats);
- } catch (err) {
- return "";
- }
- if (iconStats && iconStats.html) {
- return iconStats.html.join("");
- }
- return iconStats;
-}
-
-function getCriticalCSS(path) {
- const criticalCSSPath = Path.resolve(process.cwd(), path || "");
-
- try {
- const criticalCSS = fs.readFileSync(criticalCSSPath).toString();
- return criticalCSS;
- } catch (err) {
- return "";
- }
-}
-
-/**
- * Resolves the path to the stats.json file containing our
- * asset list. In dev the stats.json file is written to a
- * build artifacts directory, while in produciton its contained
- * within the dist/server folder
- * @param {string} statsFilePath path to stats.json
- * @param {string} buildArtifactsPath path to stats.json in dev
- * @return {string} current active path
- */
-function getStatsPath(statsFilePath, buildArtifactsPath) {
- return process.env.WEBPACK_DEV === "true"
- ? Path.resolve(buildArtifactsPath, "stats.json")
- : statsFilePath;
-}
-
-function htmlifyError(err, withStack) {
- const html = err.html ? `${err.html}
\n` : "";
- const errMsg = () => {
- if (withStack !== false && err.stack) {
- if (process.env.NODE_ENV !== "production") {
- const rgx = new RegExp(process.cwd(), "g");
- return err.stack.replace(rgx, "CWD");
- } else {
- return `- Not sending Error stack for production\n\nMessage: ${err.message}`;
- }
- } else {
- return err.message;
- }
- };
- return `OOPS
-${html}
-
-${errMsg()}
- `;
-}
-
-function getDevCssBundle(chunkNames, routeData) {
- const devBundleBase = routeData.devBundleBase;
- if (chunkNames.css) {
- const cssChunks = Array.isArray(chunkNames.css) ? chunkNames.css : [chunkNames.css];
- return _.map(cssChunks, chunkName => `${devBundleBase}${chunkName}.style.css`);
- } else {
- return [`${devBundleBase}style.css`];
- }
-}
-
-function getDevJsBundle(chunkNames, routeData) {
- const devBundleBase = routeData.devBundleBase;
-
- return chunkNames.js
- ? `${devBundleBase}${chunkNames.js}.bundle.dev.js`
- : `${devBundleBase}bundle.dev.js`;
-}
-
-function getProdBundles(chunkNames, routeData) {
- if (!routeData || !routeData.assets) {
- return {};
- }
-
- const { assets } = routeData;
-
- return {
- jsChunk: _.find(assets.js, asset => _.includes(asset.chunkNames, chunkNames.js)),
-
- cssChunk: _.filter(assets.css, asset =>
- _.some(asset.chunkNames, assetChunkName => _.includes(chunkNames.css, assetChunkName))
- )
- };
-}
-
-function processRenderSsMode(request, renderSs, mode) {
- if (renderSs) {
- if (mode === "noss") {
- return false;
- } else if (renderSs === "datass" || mode === "datass") {
- renderSs = "datass";
- // signal user content callback to populate prefetch data only and skips actual SSR
- _.set(request, ["app", "ssrPrefetchOnly"], true);
- }
- }
-
- return renderSs;
-}
-
-function getCspNonce(request, cspNonceValue) {
- let scriptNonce = "";
- let styleNonce = "";
-
- if (cspNonceValue) {
- if (typeof cspNonceValue === "function") {
- scriptNonce = cspNonceValue(request, "script");
- styleNonce = cspNonceValue(request, "style");
- } else {
- scriptNonce = _.get(request, cspNonceValue.script);
- styleNonce = _.get(request, cspNonceValue.style);
- }
- scriptNonce = scriptNonce ? ` nonce="${scriptNonce}"` : "";
- styleNonce = styleNonce ? ` nonce="${styleNonce}"` : "";
- }
-
- return { scriptNonce, styleNonce };
-}
-
-const resolvePath = path => (!Path.isAbsolute(path) ? Path.resolve(path) : path);
-
-function responseForError(request, routeOptions, err) {
- return {
- status: err.status || 500,
- html: htmlifyError(err, routeOptions.replyErrorStack)
- };
-}
-
-function responseForBadStatus(request, routeOptions, data) {
- return {
- status: data.status,
- html: (data && data.html) || data
- };
-}
-
-function loadFuncFromModule(modulePath, exportFuncName, requireAtDir) {
- const mod = requireAt(requireAtDir || process.cwd())(modulePath);
- const exportFunc = (exportFuncName && mod[exportFuncName]) || mod;
- assert(
- typeof exportFunc === "function",
- `loadFuncFromModule ${modulePath} doesn't export a usable function`
- );
- return exportFunc;
-}
-
-function invokeTemplateProcessor(asyncTemplate, routeOptions) {
- const tp = routeOptions.templateProcessor;
-
- if (tp) {
- let tpFunc;
- if (typeof tp === "string") {
- tpFunc = loadFuncFromModule(tp, "templateProcessor");
- } else {
- tpFunc = tp;
- assert(typeof tpFunc === "function", `templateProcessor is not a function`);
- }
-
- return tpFunc(asyncTemplate, routeOptions);
- }
-
- return undefined;
-}
-
-function getOtherStats() {
- const otherStats = {};
- if (fs.existsSync("dist/server")) {
- fs.readdirSync("dist/server")
- .filter(x => x.endsWith("-stats.json"))
- .reduce((prev, x) => {
- const k = Path.basename(x).split("-")[0];
- prev[k] = `dist/server/${x}`;
- return prev;
- }, otherStats);
- }
- return otherStats;
-}
-
-function getOtherAssets(pluginOptions) {
- return Object.entries(pluginOptions.otherStats).reduce((prev, [k, v]) => {
- prev[k] = loadAssetsFromStats(getStatsPath(v, pluginOptions.buildArtifacts));
- return prev;
- }, {});
-}
-
-function getBundleJsNameByQuery(data, otherAssets) {
- let { name } = data.jsChunk;
- const { __dist } = data.query;
- if (__dist && otherAssets[__dist]) {
- name = `${__dist}${name.substr(name.indexOf("."))}`;
- }
- return name;
-}
-
-const munchyHandleStreamError = err => {
- let errMsg = (process.env.NODE_ENV !== "production" && err.stack) || err.message;
-
- if (process.cwd().length > 3) {
- errMsg = (errMsg || "").replace(new RegExp(process.cwd(), "g"), "CWD");
- }
-
- return {
- result: `
-
SSR ERROR
-${errMsg}
- `,
- remit: false
- };
-};
-
-const makeDevBundleBase = devServer => {
- const cdnProtocol = process.env.WEBPACK_DEV_CDN_PROTOCOL;
- const cdnHostname = process.env.WEBPACK_DEV_CDN_HOSTNAME;
- const cdnPort = process.env.WEBPACK_DEV_CDN_PORT;
-
- /*
- * If env specified custom CDN protocol/host/port, then generate bundle
- * URL with those.
- */
- if (cdnProtocol !== undefined || cdnHostname !== undefined || cdnPort !== undefined) {
- return Url.format({
- protocol: cdnProtocol || "http",
- hostname: cdnHostname || "localhost",
- // if CDN is also from standard HTTP port 80 then it's not needed in the URL
- port: cdnPort !== HTTP_PORT ? cdnPort : "",
- pathname: "/js/"
- });
- } else if (process.env.APP_SERVER_PORT) {
- return "/js/";
- } else {
- return Url.format({
- protocol: devServer.protocol,
- hostname: devServer.host,
- port: devServer.port,
- pathname: "/js/"
- });
- }
-};
-
-module.exports = {
- resolveChunkSelector,
- loadAssetsFromStats,
- getIconStats,
- getCriticalCSS,
- getStatsPath,
- resolvePath,
- htmlifyError,
- getDevCssBundle,
- getDevJsBundle,
- getProdBundles,
- processRenderSsMode,
- getCspNonce,
- responseForError,
- responseForBadStatus,
- loadFuncFromModule,
- invokeTemplateProcessor,
- getOtherStats,
- getOtherAssets,
- getBundleJsNameByQuery,
- isReadableStream: x => Boolean(x && x.pipe && x.on && x._readableState),
- munchyHandleStreamError,
- makeDevBundleBase
-};
diff --git a/packages/electrode-react-webapp/package.json b/packages/electrode-react-webapp/package.json
deleted file mode 100644
index 39e24ffd4..000000000
--- a/packages/electrode-react-webapp/package.json
+++ /dev/null
@@ -1,156 +0,0 @@
-{
- "name": "electrode-react-webapp",
- "version": "5.1.1",
- "description": "Hapi plugin that provides a default React web app template",
- "main": "index.js",
- "scripts": {
- "build": "echo \"Nothing to build. Just a placeholder\"",
- "lint": "clap lint",
- "pre-test": "clap compile",
- "prepare": "clap compile",
- "test": "clap test-only",
- "coverage": "clap test-cov",
- "check": "clap check",
- "prepublishOnly": "clap check",
- "format": "prettier --write --print-width 100 *.{js,jsx} `find . -type d -d 1 -exec echo '{}/**/*.{js,jsx}' \\; | egrep -v '(/node_modules/|/dist/|/coverage/)'`"
- },
- "xclap": {
- "tasks": {
- "compile": "babel src-template -D -d template",
- "test-only": "~[compile, electrode/test-only]",
- "check": "~[compile, electrode/check]"
- }
- },
- "homepage": "http://www.electrode.io",
- "repository": {
- "type": "git",
- "url": "https://github.com/electrode-io/electrode.git"
- },
- "bugs": {
- "url": "https://github.com/electrode-io/electrode/issues"
- },
- "keywords": [
- "electrode",
- "node",
- "webserver"
- ],
- "author": "Electrode (http://www.electrode.io/)",
- "contributors": [
- {
- "name": "Joel Chen",
- "email": "xchen@walmartlabs.com"
- },
- {
- "name": "Caoyang Shi",
- "email": "cshi@walmartlabs.com"
- },
- {
- "name": "Arpan Nanavati",
- "email": "nanavatiarpan@gmail.com"
- }
- ],
- "license": "Apache-2.0",
- "files": [
- "lib",
- "template",
- "index.js"
- ],
- "dependencies": {
- "electrode-archetype-njs-module-dev": "^3.0.3",
- "electrode-hapi-compat": "^1.2.0",
- "eslint": "^7.32.0",
- "eslint-config-walmart": "^2.2.1",
- "eslint-plugin-filenames": "^1.1.0",
- "eslint-plugin-jsdoc": "^30.7.9",
- "http-status-codes": "^1.3.0",
- "in-publish": "^2.0.0",
- "lodash": "^4.17.10",
- "munchy": "^1.0.9",
- "require-at": "^1.0.6",
- "string-array": "^1.0.0",
- "xaa": "^1.6.0"
- },
- "devDependencies": {
- "@babel/cli": "^7.22.10",
- "@babel/core": "^7.22.11",
- "@babel/preset-env": "^7.22.10",
- "@babel/preset-react": "^7.22.5",
- "@babel/register": "^7.22.5",
- "@xarc/module-dev": "^4.1.0",
- "@xarc/run": "^1.1.1",
- "babel-eslint": "^10.1.0",
- "benchmark": "^2.1.4",
- "chai": "4.3.6",
- "electrode-redux-router-engine": "6.0.0",
- "electrode-server": "^1.8.0",
- "electrode-server2": "npm:electrode-server@^2.0.0",
- "eslint": "^7.32.0",
- "eslint-config-walmart": "^2.2.1",
- "eslint-plugin-filenames": "^1.1.0",
- "eslint-plugin-jsdoc": "^30.7.9",
- "express": "^4.15.4",
- "koa": "^2.3.0",
- "koa-router": "^7.4.0",
- "mocha": "^10.2.0",
- "nyc": "^15.1.0",
- "object-assign": "^4.1.0",
- "prettier": "^1.5.2",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-helmet": "^5.2.0",
- "run-verify": "^1.0.2",
- "stream-to-array": "^2.3.0",
- "superagent": "^1.8.5",
- "uglify-js": "^2.6.2",
- "xclap": "^0.2.0",
- "xstdout": "^0.1.1"
- },
- "nyc": {
- "all": true,
- "check-coverage": true,
- "statements": 100,
- "branches": 98,
- "functions": 100,
- "lines": 100,
- "cache": true,
- "reporter": [
- "lcov",
- "text",
- "text-summary"
- ],
- "exclude": [
- "coverage",
- "*clap.js",
- "gulpfile.js",
- "dist",
- "test",
- "src-template",
- "electrode-server2"
- ],
- "extension": [
- ".jsx"
- ],
- "require": [
- "@babel/register"
- ]
- },
- "@xarc/module-dev": {
- "srcDir": [
- "src",
- "test",
- "scripts"
- ],
- "features": [
- "eslint",
- "eslintTS",
- "mocha",
- "typedoc",
- "typescript"
- ]
- },
- "prettier": {
- "printWidth": 100,
- "trailingComma": "none",
- "arrowParens": "avoid"
- }
-}
diff --git a/packages/electrode-react-webapp/src-template/.babelrc b/packages/electrode-react-webapp/src-template/.babelrc
deleted file mode 100644
index 24b086f24..000000000
--- a/packages/electrode-react-webapp/src-template/.babelrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "node": "8"
- }
- }
- ],
- "@babel/preset-react"
- ]
-}
diff --git a/packages/electrode-react-webapp/src-template/index.jsx b/packages/electrode-react-webapp/src-template/index.jsx
deleted file mode 100644
index da2f06df7..000000000
--- a/packages/electrode-react-webapp/src-template/index.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/* @jsx createElement */
-
-const { IndexPage, createElement, Token } = require("../lib/jsx");
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/.eslintrc b/packages/electrode-react-webapp/test/.eslintrc
deleted file mode 100644
index a4edd1e02..000000000
--- a/packages/electrode-react-webapp/test/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
----
-extends:
- - "../node_modules/electrode-archetype-njs-module-dev/config/eslint/.eslintrc-test"
diff --git a/packages/electrode-react-webapp/test/data/bad-content.js b/packages/electrode-react-webapp/test/data/bad-content.js
deleted file mode 100644
index 2bc93b984..000000000
--- a/packages/electrode-react-webapp/test/data/bad-content.js
+++ /dev/null
@@ -1,3 +0,0 @@
-/* eslint-disable */
-
-require("foo-blah");
diff --git a/packages/electrode-react-webapp/test/data/chunk-selector.js b/packages/electrode-react-webapp/test/data/chunk-selector.js
deleted file mode 100644
index fe9a3b56c..000000000
--- a/packages/electrode-react-webapp/test/data/chunk-selector.js
+++ /dev/null
@@ -1,32 +0,0 @@
-"use strict";
-
-const FOO_BUNDLE = {
- css: "foo",
- js: "foo"
-};
-const BAR_BUNDLE = {
- css: "bar",
- js: "bar"
-};
-const DEFAULT_BUNDLE = {
- css: "home",
- js: "home"
-};
-const MULTI_BUNDLE = {
- css: ["foo", "bar"],
- js: "home"
-};
-
-module.exports = request => {
- if (request.path.endsWith("/foo")) {
- return FOO_BUNDLE;
- } else if (request.path.endsWith("/bar")) {
- return BAR_BUNDLE;
- } else if (request.path.endsWith("/multi-chunk")) {
- return MULTI_BUNDLE;
- } else if (request.path.endsWith("/empty")) {
- return {};
- }
-
- return DEFAULT_BUNDLE;
-};
diff --git a/packages/electrode-react-webapp/test/data/critical.css b/packages/electrode-react-webapp/test/data/critical.css
deleted file mode 100644
index 892782617..000000000
--- a/packages/electrode-react-webapp/test/data/critical.css
+++ /dev/null
@@ -1 +0,0 @@
-body {color: green;}
diff --git a/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.dev.json b/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.dev.json
deleted file mode 100644
index 44442878f..000000000
--- a/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.dev.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "production": false
-}
diff --git a/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.json b/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.json
deleted file mode 100644
index 2da76016b..000000000
--- a/packages/electrode-react-webapp/test/data/dist/electrode-dll-assets.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "production": true
-}
diff --git a/packages/electrode-react-webapp/test/data/foo.js b/packages/electrode-react-webapp/test/data/foo.js
deleted file mode 100644
index 80e295b96..000000000
--- a/packages/electrode-react-webapp/test/data/foo.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = "hello";
diff --git a/packages/electrode-react-webapp/test/data/icon-stats-empty.json b/packages/electrode-react-webapp/test/data/icon-stats-empty.json
deleted file mode 100644
index 6d6f06a49..000000000
--- a/packages/electrode-react-webapp/test/data/icon-stats-empty.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "empty": true
-}
diff --git a/packages/electrode-react-webapp/test/data/icon-stats-test-pwa.json b/packages/electrode-react-webapp/test/data/icon-stats-test-pwa.json
deleted file mode 100644
index 1e2974dc3..000000000
--- a/packages/electrode-react-webapp/test/data/icon-stats-test-pwa.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "html": [
- " ",
- " ",
- " "
- ]
-}
diff --git a/packages/electrode-react-webapp/test/data/index-1.html b/packages/electrode-react-webapp/test/data/index-1.html
deleted file mode 100644
index 25061af8c..000000000
--- a/packages/electrode-react-webapp/test/data/index-1.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test html-1
-
-
-
-
-
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/index-2.html b/packages/electrode-react-webapp/test/data/index-2.html
deleted file mode 100644
index ccac1bb1f..000000000
--- a/packages/electrode-react-webapp/test/data/index-2.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test html-2
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/perf-1.html b/packages/electrode-react-webapp/test/data/perf-1.html
deleted file mode 100644
index 7044a06d7..000000000
--- a/packages/electrode-react-webapp/test/data/perf-1.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test perf 1 html
-
-
-
-
-
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/stats-test-multibundle.json b/packages/electrode-react-webapp/test/data/stats-test-multibundle.json
deleted file mode 100644
index b0c3b1bc9..000000000
--- a/packages/electrode-react-webapp/test/data/stats-test-multibundle.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "assetsByChunkName": {
- "foo": [
- "foo.bundle.f07a873ce87fc904a6a5.js",
- "foo.style.f07a873ce87fc904a6a5.css"
- ],
- "bar": [
- "bar.bundle.f07a873ce87fc904a6a5.js",
- "bar.style.f07a873ce87fc904a6a5.css"
- ],
- "home": [
- "home.bundle.f07a873ce87fc904a6a5.js",
- "home.style.f07a873ce87fc904a6a5.css"
- ]
- },
- "assets": [{
- "name": "foo.style.f07a873ce87fc904a6a5.css",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "foo"
- ]
- }, {
- "name": "foo.bundle.f07a873ce87fc904a6a5.js",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "foo"
- ]
- }, {
- "name": "bar.style.f07a873ce87fc904a6a5.css",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "bar"
- ]
- }, {
- "name": "bar.bundle.f07a873ce87fc904a6a5.js",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "bar"
- ]
- }, {
- "name": "home.style.f07a873ce87fc904a6a5.css",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "home"
- ]
- }, {
- "name": "home.bundle.f07a873ce87fc904a6a5.js",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "home"
- ]
- }]
-}
diff --git a/packages/electrode-react-webapp/test/data/stats-test-one-bundle.json b/packages/electrode-react-webapp/test/data/stats-test-one-bundle.json
deleted file mode 100644
index 42edae47e..000000000
--- a/packages/electrode-react-webapp/test/data/stats-test-one-bundle.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "assetsByChunkName": {
- "bundle": [
- "bundle.f07a873ce87fc904a6a5.js",
- "style.f07a873ce87fc904a6a5.css"
- ]
- },
- "assets": [{
- "name": "style.f07a873ce87fc904a6a5.css",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "main"
- ]
- }, {
- "name": "bundle.f07a873ce87fc904a6a5.js",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "main"
- ]
- }]
-}
diff --git a/packages/electrode-react-webapp/test/data/stats-test-pwa.json b/packages/electrode-react-webapp/test/data/stats-test-pwa.json
deleted file mode 100644
index e937fef13..000000000
--- a/packages/electrode-react-webapp/test/data/stats-test-pwa.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "assetsByChunkName": {
- "bundle": [
- "bundle.f07a873ce87fc904a6a5.js",
- "style.f07a873ce87fc904a6a5.css"
- ],
- "bar": [
- "bar.bundle.f07a873ce87fc904a6a5.js",
- "bar.style.f07a873ce87fc904a6a5.css"
- ]
- },
- "assets": [{
- "name": "style.f07a873ce87fc904a6a5.css",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "bundle"
- ]
- }, {
- "name": "bundle.f07a873ce87fc904a6a5.js",
- "size": 888,
- "chunks": [
- 0
- ],
- "chunkNames": [
- "bundle"
- ]
- }, {
- "name": "manifest.json",
- "size": 888,
- "chunks": [],
- "chunkNames": []
- }]
-}
diff --git a/packages/electrode-react-webapp/test/data/style2.css b/packages/electrode-react-webapp/test/data/style2.css
deleted file mode 100644
index 6446ebfd4..000000000
--- a/packages/electrode-react-webapp/test/data/style2.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.test {
- color: red;
-}
diff --git a/packages/electrode-react-webapp/test/data/template1.html b/packages/electrode-react-webapp/test/data/template1.html
deleted file mode 100644
index f2d6bb644..000000000
--- a/packages/electrode-react-webapp/test/data/template1.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template2.html b/packages/electrode-react-webapp/test/data/template2.html
deleted file mode 100644
index 5de95e820..000000000
--- a/packages/electrode-react-webapp/test/data/template2.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template3.html b/packages/electrode-react-webapp/test/data/template3.html
deleted file mode 100644
index 33c0be87c..000000000
--- a/packages/electrode-react-webapp/test/data/template3.html
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template4.html b/packages/electrode-react-webapp/test/data/template4.html
deleted file mode 100644
index adfea1d08..000000000
--- a/packages/electrode-react-webapp/test/data/template4.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template5.html b/packages/electrode-react-webapp/test/data/template5.html
deleted file mode 100644
index 7856e3bdc..000000000
--- a/packages/electrode-react-webapp/test/data/template5.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template6.html b/packages/electrode-react-webapp/test/data/template6.html
deleted file mode 100644
index 72f9c17e9..000000000
--- a/packages/electrode-react-webapp/test/data/template6.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template7.html b/packages/electrode-react-webapp/test/data/template7.html
deleted file mode 100644
index f08f0f36e..000000000
--- a/packages/electrode-react-webapp/test/data/template7.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/template8.html b/packages/electrode-react-webapp/test/data/template8.html
deleted file mode 100644
index 60e9a22eb..000000000
--- a/packages/electrode-react-webapp/test/data/template8.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/data/test-content.js b/packages/electrode-react-webapp/test/data/test-content.js
deleted file mode 100644
index ae795d49f..000000000
--- a/packages/electrode-react-webapp/test/data/test-content.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- "status": 200,
- "html": "Test1 Electrode
",
- "prefetch": "console.log('test1');"
-};
diff --git a/packages/electrode-react-webapp/test/data/test-content17.js b/packages/electrode-react-webapp/test/data/test-content17.js
deleted file mode 100644
index 463551e68..000000000
--- a/packages/electrode-react-webapp/test/data/test-content17.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- "status": 200,
- "html": "Test1 Electrode17
",
- "prefetch": "console.log('test1');"
-};
diff --git a/packages/electrode-react-webapp/test/data/test-dll-assets.json b/packages/electrode-react-webapp/test/data/test-dll-assets.json
deleted file mode 100644
index 03de32b27..000000000
--- a/packages/electrode-react-webapp/test/data/test-dll-assets.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "foo": {
- "bar": [1]
- }
-}
diff --git a/packages/electrode-react-webapp/test/fixtures/async-error.js b/packages/electrode-react-webapp/test/fixtures/async-error.js
deleted file mode 100644
index a84cb4dc2..000000000
--- a/packages/electrode-react-webapp/test/fixtures/async-error.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- process: function(context) {
- context.output.add("\nfrom async error module");
- return Promise.reject("error from test/fixtures/async-error");
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/async-ok.js b/packages/electrode-react-webapp/test/fixtures/async-ok.js
deleted file mode 100644
index 1d5db1518..000000000
--- a/packages/electrode-react-webapp/test/fixtures/async-ok.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- process: function(context) {
- context.output.add("\nfrom async ok module");
- return Promise.resolve();
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/custom-1.js b/packages/electrode-react-webapp/test/fixtures/custom-1.js
deleted file mode 100644
index 91b977aa4..000000000
--- a/packages/electrode-react-webapp/test/fixtures/custom-1.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-module.exports = function setup() {
- return {
- name: "custom-1",
- process: function(context) {
- context.output.add("from custom-1
");
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/custom-call.js b/packages/electrode-react-webapp/test/fixtures/custom-call.js
deleted file mode 100644
index d9e636021..000000000
--- a/packages/electrode-react-webapp/test/fixtures/custom-call.js
+++ /dev/null
@@ -1,14 +0,0 @@
-"use strict";
-
-function setup() {
- return {
- name: "custom-call",
- process: function() {
- return Promise.resolve(`_call process from custom-call token fixture`);
- }
- };
-}
-
-module.exports = {
- setup
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/custom-count.js b/packages/electrode-react-webapp/test/fixtures/custom-count.js
deleted file mode 100644
index d8f08698a..000000000
--- a/packages/electrode-react-webapp/test/fixtures/custom-count.js
+++ /dev/null
@@ -1,7 +0,0 @@
-let count = 0;
-module.exports = () => {
- count++;
- return {
- process: () => `${count}`
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/custom-fail.js b/packages/electrode-react-webapp/test/fixtures/custom-fail.js
deleted file mode 100644
index 771c2752e..000000000
--- a/packages/electrode-react-webapp/test/fixtures/custom-fail.js
+++ /dev/null
@@ -1 +0,0 @@
-throw new Error("fail");
diff --git a/packages/electrode-react-webapp/test/fixtures/custom-null.js b/packages/electrode-react-webapp/test/fixtures/custom-null.js
deleted file mode 100644
index afb179f85..000000000
--- a/packages/electrode-react-webapp/test/fixtures/custom-null.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = () => {
- return null;
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/dynamic-index-1.html b/packages/electrode-react-webapp/test/fixtures/dynamic-index-1.html
deleted file mode 100644
index 641884356..000000000
--- a/packages/electrode-react-webapp/test/fixtures/dynamic-index-1.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- DYNAMIC_INDEX_1
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/fixtures/dynamic-index-2.html b/packages/electrode-react-webapp/test/fixtures/dynamic-index-2.html
deleted file mode 100644
index 9d449da06..000000000
--- a/packages/electrode-react-webapp/test/fixtures/dynamic-index-2.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- DYNAMIC_INDEX_2
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/fixtures/non-render-error.js b/packages/electrode-react-webapp/test/fixtures/non-render-error.js
deleted file mode 100644
index 004c071e1..000000000
--- a/packages/electrode-react-webapp/test/fixtures/non-render-error.js
+++ /dev/null
@@ -1,11 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- name: "non-render-error",
- beforeRender: () => {
- throw new Error("error from test/fixtures/non-render-error");
- },
- tokens: {}
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/perf-1-handler.js b/packages/electrode-react-webapp/test/fixtures/perf-1-handler.js
deleted file mode 100644
index ca41e548d..000000000
--- a/packages/electrode-react-webapp/test/fixtures/perf-1-handler.js
+++ /dev/null
@@ -1,31 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- "user-token-1": () => {
- return "user-token-1
";
- },
-
- "user-token-2": context => {
- context.output.add("user-token-2
");
- },
-
- "user-spot-token": context => {
- const spot = context.output.reserve();
- process.nextTick(() => {
- spot.add("user-spot-1;");
- spot.add("user-spot-2;");
- spot.add("user-spot-3
");
- spot.close();
- });
- },
-
- "user-promise-token": context => {
- context.output.add("user-promise-token
");
- },
-
- PAGE_TITLE: () => {
- return "user-handler-title ";
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/react-helmet-handler.js b/packages/electrode-react-webapp/test/fixtures/react-helmet-handler.js
deleted file mode 100644
index 6f0b28326..000000000
--- a/packages/electrode-react-webapp/test/fixtures/react-helmet-handler.js
+++ /dev/null
@@ -1,35 +0,0 @@
-"use strict";
-
-const Helmet = require("react-helmet").Helmet;
-
-const emptyTitleRegex = /]*><\/title>/;
-
-module.exports = handlerContext => {
- const routeOptions = handlerContext.user.routeOptions;
- const iconStats = handlerContext.user.routeData.iconStats;
-
- return {
- HEAD_INITIALIZE: context => {
- context.user.helmet = Helmet.renderStatic();
- },
-
- PAGE_TITLE: context => {
- const helmet = context.user.helmet;
- const helmetTitleScript = helmet.title.toString();
- const helmetTitleEmpty = helmetTitleScript.match(emptyTitleRegex);
-
- return helmetTitleEmpty ? `${routeOptions.pageTitle} ` : helmetTitleScript;
- },
-
- REACT_HELMET_SCRIPTS: context => {
- const scriptsFromHelmet = ["link", "style", "script", "noscript"]
- .map(tagName => context.user.helmet[tagName].toString())
- .join("");
- return `${scriptsFromHelmet}`;
- },
-
- META_TAGS: context => {
- return context.user.helmet.meta.toString() + iconStats;
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/return-undefined.js b/packages/electrode-react-webapp/test/fixtures/return-undefined.js
deleted file mode 100644
index d1823ec85..000000000
--- a/packages/electrode-react-webapp/test/fixtures/return-undefined.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- process: function() {}
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/string-only.js b/packages/electrode-react-webapp/test/fixtures/string-only.js
deleted file mode 100644
index 76a7a8aea..000000000
--- a/packages/electrode-react-webapp/test/fixtures/string-only.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- process: function() {
- return "\nfrom string only module";
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/template-processor-1.js b/packages/electrode-react-webapp/test/fixtures/template-processor-1.js
deleted file mode 100644
index 15d6c3e46..000000000
--- a/packages/electrode-react-webapp/test/fixtures/template-processor-1.js
+++ /dev/null
@@ -1,5 +0,0 @@
-"use strict";
-
-module.exports = function() {
- return "template-processor-1";
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/template-processor-2.js b/packages/electrode-react-webapp/test/fixtures/template-processor-2.js
deleted file mode 100644
index 115948f57..000000000
--- a/packages/electrode-react-webapp/test/fixtures/template-processor-2.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- templateProcessor: function() {
- return "template-processor-2";
- }
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/template-processor-3.js b/packages/electrode-react-webapp/test/fixtures/template-processor-3.js
deleted file mode 100644
index eb785eb37..000000000
--- a/packages/electrode-react-webapp/test/fixtures/template-processor-3.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- oops: function() {
- return "template-processor-3";
- }
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/test-render-context.html b/packages/electrode-react-webapp/test/fixtures/test-render-context.html
deleted file mode 100644
index 51f62a08b..000000000
--- a/packages/electrode-react-webapp/test/fixtures/test-render-context.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/fixtures/token-handler.js b/packages/electrode-react-webapp/test/fixtures/token-handler.js
deleted file mode 100644
index 464b94a25..000000000
--- a/packages/electrode-react-webapp/test/fixtures/token-handler.js
+++ /dev/null
@@ -1,50 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers */
-
-module.exports = () => {
- return {
- "user-token-1": () => {
- return "user-token-1
";
- },
-
- "user-token-2": context => {
- context.output.add("user-token-2
");
- },
-
- "user-spot-token": context => {
- const spot = context.output.reserve();
- spot.add("user-spot-1;");
- setTimeout(() => {
- spot.add("user-spot-2;");
- setTimeout(() => {
- spot.add("user-spot-3
");
- spot.close();
- }, 20);
- }, 10);
- },
-
- "user-promise-token": context => {
- return new Promise(resolve => {
- setTimeout(() => {
- context.output.add("user-promise-token
");
- resolve();
- }, 10);
- });
- },
-
- "user-header-token": context => {
- context.user.response.headers = {
- "x-foo-bar": "hello-world"
- };
- },
-
- PAGE_TITLE: () => {
- return "user-handler-title ";
- },
-
- TEST_DYNAMIC_2: () => {
- return "RETURN_BY_TEST_DYANMIC_2";
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/fixtures/token-mod-es6-default.js b/packages/electrode-react-webapp/test/fixtures/token-mod-es6-default.js
deleted file mode 100644
index d7ccbd13c..000000000
--- a/packages/electrode-react-webapp/test/fixtures/token-mod-es6-default.js
+++ /dev/null
@@ -1 +0,0 @@
-exports.default = function es6Default() {};
diff --git a/packages/electrode-react-webapp/test/fixtures/token-mod-handler.js b/packages/electrode-react-webapp/test/fixtures/token-mod-handler.js
deleted file mode 100644
index 4ac2fcecb..000000000
--- a/packages/electrode-react-webapp/test/fixtures/token-mod-handler.js
+++ /dev/null
@@ -1 +0,0 @@
-exports.tokenHandler = function asTokenHandler() {};
diff --git a/packages/electrode-react-webapp/test/fixtures/token-mod-invalid.js b/packages/electrode-react-webapp/test/fixtures/token-mod-invalid.js
deleted file mode 100644
index f8a020c54..000000000
--- a/packages/electrode-react-webapp/test/fixtures/token-mod-invalid.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = "oops";
diff --git a/packages/electrode-react-webapp/test/fixtures/wants-next.js b/packages/electrode-react-webapp/test/fixtures/wants-next.js
deleted file mode 100644
index 0449f4868..000000000
--- a/packages/electrode-react-webapp/test/fixtures/wants-next.js
+++ /dev/null
@@ -1,9 +0,0 @@
-"use strict";
-
-module.exports = () => {
- return {
- process: function(context) {
- context.output.add("\nfrom wants next module");
- }
- };
-};
diff --git a/packages/electrode-react-webapp/test/jsx-templates/.babelrc b/packages/electrode-react-webapp/test/jsx-templates/.babelrc
deleted file mode 100644
index 24b086f24..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/.babelrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "node": "8"
- }
- }
- ],
- "@babel/preset-react"
- ]
-}
diff --git a/packages/electrode-react-webapp/test/jsx-templates/index-1.jsx b/packages/electrode-react-webapp/test/jsx-templates/index-1.jsx
deleted file mode 100644
index 287eb304f..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/index-1.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/* @jsx createElement */
-
-const { IndexPage, createElement, Token, Require } = require("../../lib/jsx");
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test html-1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/index-2.jsx b/packages/electrode-react-webapp/test/jsx-templates/index-2.jsx
deleted file mode 100644
index 9b42c1a3a..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/index-2.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/* @jsx createElement */
-
-const { IndexPage, createElement, Token } = require("../../lib/jsx");
-
-const TestAsync = async () => {
- return `Hello from async tag JSX-2
`;
-};
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test jsx-2
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/index-3.jsx b/packages/electrode-react-webapp/test/jsx-templates/index-3.jsx
deleted file mode 100644
index bc78d0647..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/index-3.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/* @jsx createElement */
-
-const { IndexPage, createElement, Token, Require } = require("../../lib/jsx");
-
-const Test = (props, context) => {
- context.status = 204;
- return `Hello Test JSX-3
`;
-};
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/index-intercept.jsx b/packages/electrode-react-webapp/test/jsx-templates/index-intercept.jsx
deleted file mode 100644
index a827a4a63..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/index-intercept.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/* @jsx createElement */
-
-const { IndexPage, createElement, Token, Require } = require("../../lib/jsx");
-
-const Test = (props, context) => {
- context.intercept({
- responseHandler: (request, h) => {
- return h.response("context intercept handler").takeover();
- }
- });
-};
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/style.css b/packages/electrode-react-webapp/test/jsx-templates/style.css
deleted file mode 100644
index 266cef311..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/style.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.test {
- background: black;
-}
diff --git a/packages/electrode-react-webapp/test/jsx-templates/test-token.js b/packages/electrode-react-webapp/test/jsx-templates/test-token.js
deleted file mode 100644
index da720f10d..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/test-token.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports = function setup(setupContext, token) {
- const props = token.props;
-
- return {
- process: () => props.name
- };
-};
diff --git a/packages/electrode-react-webapp/test/jsx-templates/test1.jsx b/packages/electrode-react-webapp/test/jsx-templates/test1.jsx
deleted file mode 100644
index 57db9e93f..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/test1.jsx
+++ /dev/null
@@ -1,140 +0,0 @@
-/* @jsx createElement */
-
-import { IndexPage, createElement, Token, Require, Literal, Component } from "../../lib/jsx";
-
-const getBogelFontUrl = () => {
- return "bogel";
-};
-
-const MyTest = (props, context) => {
- return (
- 50}>
-
- my test
-
- );
-};
-
-class TestComponent1 extends Component {
- constructor(props, context) {
- super(props, context);
- }
-
- render() {
- return from test component1{this.props.test1}
;
- }
-}
-
-function AsyncComponent(props, context, scope) {
- return new Promise(resolve => {
- setTimeout(() => {
- scope.output.add(`${props.indent}async component ${props.key}\n`);
- resolve(async component children: {props.children}
);
- }, props.delay);
- });
-}
-
-function ChildrenNesting(props) {
- return (
-
- component nesting children
- {props.children}
-
- );
-}
-
-const Template = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test nested async components 1
-
-
- test nested async components 2
-
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-
-
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/test2.jsx b/packages/electrode-react-webapp/test/jsx-templates/test2.jsx
deleted file mode 100644
index 8c8a7a3de..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/test2.jsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/* @jsx createElement */
-
-import { IndexPage, createElement, Token, Require, Literal, Component } from "../../lib/jsx";
-
-const getBogelFontUrl = () => {
- return "bogel";
-};
-
-const MyTest = (props, context) => {
- return (
- 50}>
-
- my test
-
- );
-};
-
-class TestComponent1 extends Component {
- constructor(props, context) {
- super(props, context);
- }
-
- render() {
- return from test component1{this.props.test1}
;
- }
-}
-
-function AsyncComponent(props, context, scope) {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- if (props.fail) {
- reject(new Error("test async component fail"));
- } else {
- scope.output.add(`${props.indent}async component ${props.key}\n`);
- resolve();
- }
- }, props.delay);
- });
-}
-
-function NestAsyncComponent() {
- return (
-
- test nested async components failed
-
- );
-}
-
-const Template = (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- test nested async components 1
-
-
-
-
-
-
-
- JavaScript is Disabled
- Sorry, this webpage requires JavaScript to function correctly.
- Please enable JavaScript in your browser and reload the page.
-
-
-
-
-
-
-
-);
-
-export default Template;
diff --git a/packages/electrode-react-webapp/test/jsx-templates/test3.jsx b/packages/electrode-react-webapp/test/jsx-templates/test3.jsx
deleted file mode 100644
index 87af8c238..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/test3.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/* @jsx createElement */
-
-import { IndexPage, createElement, Token, Require, Literal, Component } from "../../lib/jsx";
-
-function Component1(props) {
- return (
-
- component1 {props.key} {props.children}
-
- );
-}
-
-function AsyncChildren(props) {
- return new Promise(resolve =>
- setTimeout(() => {
- resolve(
-
- async component {props.key} children: {props.children}
-
- );
- }, 10)
- );
-}
-
-function NestChildren(props) {
- return (
-
- nesting children
- {props.children}
-
- inside component1
-
-
- );
-}
-
-export default (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
diff --git a/packages/electrode-react-webapp/test/jsx-templates/test4.jsx b/packages/electrode-react-webapp/test/jsx-templates/test4.jsx
deleted file mode 100644
index 5314acb47..000000000
--- a/packages/electrode-react-webapp/test/jsx-templates/test4.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-/* @jsx createElement */
-
-import { IndexPage, createElement, Require } from "../../lib/jsx";
-
-export default (
-
-
-
-
-
-);
diff --git a/packages/electrode-react-webapp/test/mocha.opts b/packages/electrode-react-webapp/test/mocha.opts
deleted file mode 100644
index 18b18c44e..000000000
--- a/packages/electrode-react-webapp/test/mocha.opts
+++ /dev/null
@@ -1,3 +0,0 @@
---require @babel/register
---require node_modules/electrode-archetype-njs-module-dev/config/test/setup.js
---recursive
\ No newline at end of file
diff --git a/packages/electrode-react-webapp/test/oops.js b/packages/electrode-react-webapp/test/oops.js
deleted file mode 100644
index 27799fc58..000000000
--- a/packages/electrode-react-webapp/test/oops.js
+++ /dev/null
@@ -1,24 +0,0 @@
-"use strict";
-
-const { htmlifyError } = require("../lib/utils");
-
-const electrodeServer = require("electrode-server");
-
-function blah() {
- throw new Error("blah");
-}
-
-electrodeServer().then(server => {
- server.route({
- method: "get",
- path: "/",
- handler: (request, reply) => {
- try {
- blah();
- } catch (err) {
- err.html = "Something went wrong";
- reply(htmlifyError(err));
- }
- }
- });
-});
diff --git a/packages/electrode-react-webapp/test/perf-1.js b/packages/electrode-react-webapp/test/perf-1.js
deleted file mode 100644
index d16c1bbac..000000000
--- a/packages/electrode-react-webapp/test/perf-1.js
+++ /dev/null
@@ -1,40 +0,0 @@
-"use strict";
-
-const Benchmark = require("benchmark");
-const ReactWebapp = require("../lib/react-webapp");
-const Path = require("path");
-
-function test1() {
- const options = ReactWebapp.setupOptions({
- htmlFile: Path.join(__dirname, "data/perf-1.html"),
- tokenHandler: "./test/fixtures/perf-1-handler"
- });
- const content = () => {
- return {
- status: 200,
- html: "testing
",
- prefetch: "window._data = {};"
- };
- };
- const handler = ReactWebapp.makeRouteHandler(options);
- const request = {};
-
- function render(deferred) {
- handler({ request, content }).then(() => {
- deferred.resolve();
- });
- }
-
- const suite = new Benchmark.Suite();
- suite
- .add("test1", {
- defer: true,
- fn: render
- })
- .on("complete", function() {
- console.log(this[0].times, 1 / this[0].times.period);
- })
- .run();
-}
-
-test1();
diff --git a/packages/electrode-react-webapp/test/router-engine/content-verbatim.jsx b/packages/electrode-react-webapp/test/router-engine/content-verbatim.jsx
deleted file mode 100644
index b4a359aeb..000000000
--- a/packages/electrode-react-webapp/test/router-engine/content-verbatim.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import ReduxRouterEngine from "electrode-redux-router-engine";
-import { routes } from "./routes";
-
-let routesEngine;
-
-module.exports = req => {
- if (!routesEngine) {
- routesEngine = new ReduxRouterEngine({ routes, componentRedirect: true });
- }
-
- return routesEngine.render(req).then(data => {
- return Object.assign({}, data, { verbatim: true, status: 560 });
- });
-};
diff --git a/packages/electrode-react-webapp/test/router-engine/content.jsx b/packages/electrode-react-webapp/test/router-engine/content.jsx
deleted file mode 100644
index 55081e336..000000000
--- a/packages/electrode-react-webapp/test/router-engine/content.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import ReduxRouterEngine from "electrode-redux-router-engine";
-import { routes } from "./routes";
-
-let routesEngine;
-
-module.exports = req => {
- if (!routesEngine) {
- routesEngine = new ReduxRouterEngine({ routes, componentRedirect: true });
- }
-
- return routesEngine.render(req);
-};
diff --git a/packages/electrode-react-webapp/test/router-engine/routes.jsx b/packages/electrode-react-webapp/test/router-engine/routes.jsx
deleted file mode 100644
index 157be60cd..000000000
--- a/packages/electrode-react-webapp/test/router-engine/routes.jsx
+++ /dev/null
@@ -1,248 +0,0 @@
-import React from "react";
-import { connect } from "react-redux";
-import { withRouter, Redirect } from "react-router-dom";
-import { renderRoutes } from "react-router-config";
-
-class Home extends React.Component {
- render() {
- const { search } = this.props.location;
- const query = search ? ` - Query: ${search}` : "";
- return Home{query}
;
- }
-}
-
-class Page extends React.Component {
- render() {
- const { route, children } = this.props;
- return (
-
- Page
- {renderRoutes(route.routes)}
- {children}
-
- );
- }
-}
-
-class Test extends React.Component {
- render() {
- return Test
;
- }
-}
-
-class TestRedirect extends React.Component {
- render() {
- return (
-
-
- Test Redirect
-
-
- );
- }
-}
-
-function TestRedux({ inc }) {
- inc();
-
- return Test Redux
;
-}
-
-const ConnectedTestRedux = connect(
- null,
- dispatch => ({ inc: () => dispatch({ type: "INC_NUMBER" }) })
-)(TestRedux);
-
-//
-// Similar React Router 3 routes
-//
-// import { Route, IndexRoute, Redirect } from "react-router";
-//
-// export default (
-//
-//
-//
-//
-//
-//
-//
-// );
-//
-
-//
-// - server only listens to top level routes
-// - each matching route can independently supply its own handler for preparing the
-// initial redux store and reducers
-// - the router engine will take the store and combine all reducers from all matched routes
-// to create a redux store
-// - each route should have a name if it supplies redux reducer
-// - the name must be unique or routes with the same name must have mutually exclusive paths
-// -- ie: a url cannot match multiple routes that have the same name
-// - any route that supplies redux reducer should have a init for initializing its initialState on server
-// - all reducers are combined with combineReducers or the top level route can provide init that returns rootReducer
-//
-
-// init will be passed an object with:
-
-// - request object
-// - location which is the url extracted from request object
-// - match array
-// - route itself
-// - inits that is an array of current list of results from other route init so far
-
-// init should return:
-
-const init1 = {
- reducer: { foo: function() {} },
- initialState: { foo: {} }
-};
-
-// if init is decorated with async or returns a Promise, then it will be awaited
-
-// - the reducers are combined with redux's combineReducers
-// - initialState are merged into a single new object with Object.assign
-
-// - if top level init wants to, it can override the behavior as follows:
-
-// 1. return a reducer that's a function to be use as the sole reducer to create the
-// redux store and to skip the combineReducers behavior
-
-const init2 = {
- reducer: function() {},
- initialState: {}
-};
-
-// 2. return a redux store that's to be used directly
-
-const init3 = {
- store: {}
-};
-
-const routes = [
- {
- name: "Page",
- path: "/test",
- methods: "get",
- init: null,
- component: withRouter(Page),
- routes: [
- {
- // Default, equivalent of RR3's IndexRoute
- path: "/test",
- exact: true,
- component: Home
- },
- {
- path: "/test/init",
- exact: false,
- init: "./test-init",
- component: Test
- },
- {
- name: "woo",
- path: "/test/redux",
- init: "./test-redux",
- component: ConnectedTestRedux
- },
- {
- path: "/test/component-redirect",
- component: TestRedirect
- },
- {
- path: "/test/init-not-found",
- init: "./test-init-not-found"
- }
- ]
- },
- {
- name: "Page",
- path: "/test-init-nm",
- init: "test-init-nm",
- component: Page,
- routes: [
- {
- // Default, equivalent of RR3's IndexRoute
- path: "/test-init-nm",
- exact: true,
- component: Home
- }
- ]
- },
- {
- path: "/top-reducer",
- component: withRouter(Page),
- init: true,
- routes: [
- {
- path: "/top-reducer/init",
- init: "./test-init",
- component: Test
- },
- {
- name: "woo",
- path: "/top-reducer/redux",
- init: "./test-redux",
- component: ConnectedTestRedux
- }
- ]
- },
- {
- path: "/top-wait",
- component: withRouter(Page),
- init: true,
- useSwitch: false,
- routes: [
- {
- name: "bar",
- path: "/top-wait/init",
- init: "./test-init",
- component: Test
- },
- {
- //
- // Not sure why, but potentially it is valid to have another
- // route component that uses the same path.
- // Doing it here to demo that current react-router-config
- // doesn't handle this use case.
- //
- name: "koo",
- path: "/top-wait/init",
- init: "./test-redux",
- component: ConnectedTestRedux
- }
- ]
- },
- {
- path: "/post-only",
- method: "post"
- },
- {
- path: "/invalid-component",
- component: () => {}
- },
- {
- path: "/error-component",
- component: () => {
- throw { status: 404 };
- }
- },
- {
- path: "/throw-error",
- init: "./test-init",
- component: () => {
- throw new Error("failed error");
- }
- },
- {
- path: "/escape-chars",
- init: "./escape-chars",
- component: () => Hello
- },
- {
- path: "/test-init2",
- init: true,
- component: Test
- }
-];
-
-export { routes };
diff --git a/packages/electrode-react-webapp/test/spec/async-template.spec.js b/packages/electrode-react-webapp/test/spec/async-template.spec.js
deleted file mode 100644
index e6ee5b5e1..000000000
--- a/packages/electrode-react-webapp/test/spec/async-template.spec.js
+++ /dev/null
@@ -1,1014 +0,0 @@
-"use strict";
-
-const AsyncTemplate = require("../../lib/async-template");
-const Path = require("path");
-const expect = require("chai").expect;
-const _ = require("lodash");
-const xstdout = require("xstdout");
-
-const silentIntercept = true;
-
-describe("async-template", function() {
- let intercept;
-
- afterEach(() => {
- if (intercept) {
- intercept.restore();
- }
- intercept = undefined;
- });
-
- it("should parse template into tokens", () => {
- const htmlFile = Path.join(__dirname, "../data/template1.html");
- intercept = xstdout.intercept(silentIntercept);
- const asyncTemplate = new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- });
- asyncTemplate.initializeRenderer();
- asyncTemplate.initializeRenderer(); // test re-entry
- intercept.restore();
- const expected = [
- { str: "\n\n" },
- {
- id: "ssr-content",
- isModule: false,
- pos: 17,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "webapp-header-bundles",
- isModule: false,
- pos: 41,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "webapp-body-bundles",
- isModule: false,
- pos: 75,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "page-title",
- isModule: false,
- pos: 107,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "prefetch-bundles",
- isModule: false,
- pos: 130,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- { str: `` },
- {
- id: "meta-tags",
- isModule: false,
- pos: 206,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "#critical-css",
- isModule: true,
- modPath: "critical-css",
- pos: 228,
- custom: undefined,
- wantsNext: false,
- props: {}
- },
- { str: "\n\n" }
- ];
- const criticalCssToken = asyncTemplate.tokens[8];
- expect(criticalCssToken.custom.process()).to.equal(
- `\ntoken process module critical-css not found\n`
- );
- criticalCssToken.custom = undefined;
- expect(asyncTemplate.tokens).to.deep.equal(expected);
- });
-
- const template2Expected = [
- { str: "\n\n" },
- {
- id: "ssr-content",
- isModule: false,
- pos: 17,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "webapp-header-bundles",
- isModule: false,
- pos: 41,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "webapp-body-bundles",
- isModule: false,
- pos: 75,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "prefetch-bundles",
- isModule: false,
- pos: 107,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- { str: `` },
- {
- id: "webapp-body-bundles",
- isModule: false,
- pos: 183,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- {
- id: "meta-tags",
- isModule: false,
- pos: 215,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- },
- { str: "\n\n" },
- {
- id: "page-title",
- isModule: false,
- pos: 252,
- custom: undefined,
- wantsNext: undefined,
- props: {}
- }
- ];
-
- it("should parse template with token at end", () => {
- const htmlFile = Path.join(__dirname, "../data/template2.html");
- intercept = xstdout.intercept(silentIntercept);
- const asyncTemplate = new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- });
- asyncTemplate.initializeRenderer();
- intercept.restore();
-
- expect(asyncTemplate.tokens).to.deep.equal(template2Expected);
- });
-
- it("should parse template multi line tokens with props", () => {
- const htmlFile = Path.join(__dirname, "../data/template3.html");
-
- intercept = xstdout.intercept(silentIntercept);
-
- const asyncTemplate = new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- });
- asyncTemplate.initializeRenderer();
- intercept.restore();
-
- const expected = [
- {
- str: "\n\n"
- },
- {
- id: "ssr-content",
- isModule: false,
- pos: 17,
- props: {
- attr: ["1", "2", "3"],
- args: ["a", "b", "c"],
- empty: "",
- foo: "bar a [b] c",
- hello: "world",
- test: true
- },
- custom: undefined,
- wantsNext: undefined
- },
- {
- id: "prefetch-bundles",
- isModule: false,
- pos: 148,
- props: {},
- custom: undefined,
- wantsNext: undefined
- },
- {
- str: `"
- },
- {
- id: "meta-tags",
- isModule: false,
- pos: 264,
- props: {},
- custom: undefined,
- wantsNext: undefined
- },
-
- {
- str: "\n\n"
- },
- {
- id: "page-title",
- isModule: false,
- pos: 301,
- props: {},
- custom: undefined,
- wantsNext: undefined
- },
- {
- custom: undefined,
- id: "json-prop",
- isModule: false,
- pos: 326,
- props: {
- foo: "bar",
- test: [1, 2, 3]
- },
- wantsNext: undefined
- },
- {
- custom: undefined,
- id: "space-tags",
- isModule: false,
- pos: 396,
- props: {},
- wantsNext: undefined
- },
- {
- custom: undefined,
- id: "new-line-tags",
- isModule: false,
- pos: 421,
- props: {},
- wantsNext: undefined
- },
- {
- custom: undefined,
- id: "space-newline-tag",
- isModule: false,
- pos: 456,
- props: {
- attr1: "hello",
- attr2: "world",
- attr3: "foo"
- },
- wantsNext: undefined
- },
- {
- _modCall: ["setup"],
- custom: {
- name: "custom-call"
- },
- id: `require("../fixtures/custom-call")`,
- isModule: true,
- modPath: "../fixtures/custom-call",
- pos: 536,
- props: {
- _call: "setup"
- },
- wantsNext: false
- }
- ];
- expect(typeof _.last(asyncTemplate.tokens).custom.process).to.equal("function");
- delete _.last(asyncTemplate.tokens).custom.process;
- expect(asyncTemplate.tokens).to.deep.equal(expected);
- });
-
- it("should throw for token with invalid props", () => {
- const htmlFile = Path.join(__dirname, "../data/template4.html");
- expect(
- () =>
- new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- })
- ).to.throw(
- `at line 9 col 3 - 'prefetch-bundles bad-prop' has malformed prop: name must be name=Val;`
- );
- });
-
- it("should throw for token with invalid prop name", () => {
- const htmlFile = Path.join(__dirname, "../data/template5.html");
- expect(
- () =>
- new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- })
- ).to.throw(
- `at line 4 col 3 - 'ssr-content attr[1,2,3]' has malformed prop: name must be name=Val;`
- );
- });
-
- it("should throw for token empty body", () => {
- const htmlFile = Path.join(__dirname, "../data/template7.html");
- expect(
- () =>
- new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- })
- ).to.throw(`at line 3 col 5 - empty token body`);
- });
-
- it("should throw for token missing close tag", () => {
- const htmlFile = Path.join(__dirname, "../data/template8.html");
- expect(
- () =>
- new AsyncTemplate({
- htmlFile,
- tokenHandlers: "./test/fixtures/token-handler"
- })
- ).to.throw(`at line 3 col 5 - Can't find token close tag for '`);
- return server.close(() => resolve());
- });
- });
- });
-
- it("should return Error with status and html", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/fail?status=404&html=html-foo-bar`).end(err => {
- expect(err).to.be.ok;
- expect(err.status).to.equal(404);
- expect(err.response.text).contains("html-foo-bar");
- expect(err.response.text).contains("test fail 404");
- server.close(() => resolve());
- });
- });
- });
-
- it("should return 404 and html, if custom html is provided", () => {
- const server = startServer(webappOptions(null));
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=404&html=NotFoundHTML&render=0`).end(
- (err, resp) => {
- expect(err).to.be.ok;
- expect(resp.status).to.equal(404);
- expect(resp.text).to.equal("NotFoundHTML");
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should return 410 and html, if custom html is provided", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=410&html=GoneHTML&render=0`).end(
- (err, resp) => {
- expect(err).to.be.ok;
- expect(resp.status).to.equal(410);
- expect(resp.text).to.equal("GoneHTML");
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should not fail on 404 if no html is provided", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=404&data=test&render=0`).end(
- (err, resp) => {
- expect(err).to.be.ok;
- expect(resp.status).to.equal(404);
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should return 503 and html, if custom html is provided", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(
- `http://localhost:${port}/status?status=503&html=ServerErrorHTML&render=0`
- ).end((err, resp) => {
- expect(err).to.be.ok;
- expect(resp.status).to.equal(503);
- expect(resp.text).to.equal("ServerErrorHTML");
- server.close(() => resolve());
- });
- });
- });
-
- it("should return 200 and html with render false", () => {
- const server = startServer(webappOptions());
- return new Promise((resolve, reject) => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=200&html=HelloTestHTML&render=0`).end(
- (err, resp) => {
- if (err) reject(err);
- expect(resp.status).to.equal(200);
- expect(resp.text).to.equal("HelloTestHTML");
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should handle and return 500 on non-render errors", () => {
- const options = webappOptions();
- options.tokenHandlers = Path.join(__dirname, "../fixtures/non-render-error");
- const server = startServer(options);
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/`).end(err => {
- expect(err).to.be.ok;
- expect(err.status).to.equal(500);
- expect(err.response.text).contains("error from test/fixtures/non-render-error");
- server.close(() => resolve());
- });
- });
- });
-
- it("should handle replyErrorStack being false", () => {
- const options = webappOptions();
- options.tokenHandlers = Path.join(__dirname, "../fixtures/non-render-error");
- options.replyErrorStack = false;
- const server = startServer(options);
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/`).end(err => {
- expect(err).to.be.ok;
- expect(err.status).to.equal(500);
- expect(err.response.text).contains("error from test/fixtures/non-render-error");
- // should contain no stack
- expect(err.response.text).to.not.contains(
- "packages/electrode-react-webapp/test/fixtures/non-render-error.js"
- );
- server.close(() => resolve());
- });
- });
- });
-
- it("should return 500 on errors", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/fail`).end(err => {
- expect(err).to.be.ok;
- expect(err.status).to.equal(500);
- expect(err.response.text).contains("test fail undefined");
- server.close(() => resolve());
- });
- });
- });
-
- it("should return 302 on redirect", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/redirect`)
- .redirects(0)
- .end((err, resp) => {
- expect(resp.text).includes("/redirect2");
- return server.close(() => resolve());
- });
- });
- });
-
- it("should return non 200 status", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=401&message=HelloTest401`).end(
- (err, resp) => {
- expect(resp.status).to.equal(401);
- expect(resp.body.message).to.equal("HelloTest401");
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should return 200 status with render off", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=200&message=HelloTest200`).end(
- (err, resp) => {
- expect(resp.status).to.equal(200);
- expect(resp.body.message).to.equal("HelloTest200");
- server.close(() => resolve());
- }
- );
- });
- });
-
- it("should handle content as a string", () => {
- const server = startServer(webappOptions());
- return new Promise((resolve, reject) => {
- const port = server.address().port;
- return request(`http://localhost:${port}/string`).end((err, resp) => {
- if (err) reject(err);
- expect(resp.text).includes("");
- expect(resp.text).includes(">test content as a string");
- server.close(() => resolve());
- });
- });
- });
-
- it("@no-html should return JSON with 200 status with ss off", () => {
- const server = startServer(webappOptions());
- return new Promise(resolve => {
- const port = server.address().port;
- return request(`http://localhost:${port}/status?status=200`).end((err, resp) => {
- expect(resp.status).to.equal(200);
- expect(resp.body.message).to.equal("no html");
- server.close(() => resolve());
- });
- });
- });
-
- it("should setup route to all methods", () => {
- const server = startServer(webappOptions());
- return new Promise((resolve, reject) => {
- const port = server.address().port;
- return request
- .post(`http://localhost:${port}/all`)
- .send({})
- .end((err, resp) => {
- if (err) return reject(err);
- expect(resp.text).includes("Test All");
- expect(resp.text).includes("console.log('Hello all');");
- return server.close(() => resolve());
- });
- });
- });
-
- it("should handle option serverSideRendering false", () => {
- const options = webappOptions();
- options.serverSideRendering = false;
- const server = startServer(options);
- return new Promise((resolve, reject) => {
- const port = server.address().port;
- return request.get(`http://localhost:${port}`).end((err, resp) => {
- if (err) return reject(err);
- expect(resp.text).includes("");
- return server.close(() => resolve());
- });
- });
- });
-
- it("should set ssrPrefetchOnly for datass mode", () => {
- const options = webappOptions();
- const app = express();
- registerRoutes(app, options);
- app.use((req, res, next) => {
- req.app = {};
- next();
- });
- const server = app.listen(0);
- return new Promise((resolve, reject) => {
- const port = server.address().port;
- return request.get(`http://localhost:${port}/data_only?__mode=datass`).end((err, resp) => {
- if (err) return reject(err);
- expect(resp.text).includes("ssrPrefetchOnly true");
- expect(resp.text).includes(`
`);
- return server.close(() => resolve());
- });
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/group-scripts.spec.js b/packages/electrode-react-webapp/test/spec/group-scripts.spec.js
deleted file mode 100644
index 455dac07b..000000000
--- a/packages/electrode-react-webapp/test/spec/group-scripts.spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-"use strict";
-
-const data = [
- "a",
- "b",
- "c",
- { src: 1 },
- { src: 5, defer: 1 },
- { src: 2 },
- "d",
- "e",
- "f;",
- "g",
- { src: 3 },
- "h",
- "i",
- "j",
- {
- src: 4,
- async: 1
- },
- { src: 10 },
- "k",
- "l",
- "m"
-];
-
-const groupScripts = require("../../lib/group-scripts");
-const chai = require("chai");
-
-describe("group-scripts", function() {
- it("should group scripts", () => {
- const expected = [
- "a;\n\nb;\n\nc;",
- [
- {
- src: 1
- },
- {
- src: 5,
- defer: 1
- },
- {
- src: 2
- }
- ],
- "d;\n\ne;\n\nf;\n\ng;",
- [
- {
- src: 3
- }
- ],
- "h;\n\ni;\n\nj;",
- [
- {
- src: 4,
- async: 1
- },
- {
- src: 10
- }
- ],
- "k;\n\nl;\n\nm;"
- ];
- const result = groupScripts(data);
- chai.expect(result.scripts).to.deep.equal(expected);
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/hapi.index.spec.js b/packages/electrode-react-webapp/test/spec/hapi.index.spec.js
deleted file mode 100644
index 2e500aefc..000000000
--- a/packages/electrode-react-webapp/test/spec/hapi.index.spec.js
+++ /dev/null
@@ -1,1729 +0,0 @@
-"use strict";
-
-/* eslint-disable quotes */
-
-const Fs = require("fs");
-const assign = require("object-assign");
-const electrodeServer = require("electrode-server");
-const Path = require("path");
-const xstdout = require("xstdout");
-const { expect } = require("chai");
-const webapp = require("../../lib/hapi/plugin16");
-const ReactDOMServer = require("react-dom/server");
-const React = require("react");
-const Helmet = require("react-helmet").Helmet;
-const { runFinally, asyncVerify } = require("run-verify");
-const xaa = require("xaa");
-
-describe("hapi 16 electrode-react-webapp", () => {
- let config;
- let configOptions;
- let mainRoutePathOptions;
- let testServer;
-
- const getConfig = () => {
- return {
- server: {
- useDomains: false
- },
- connections: {
- default: {
- port: 0
- }
- },
- plugins: {
- "react-webapp": {
- module: Path.join(__dirname, "../../lib/hapi/plugin16"),
- options: {
- pageTitle: "Electrode App",
- paths: {
- "/test/component-redirect": {
- content: {
- module: Path.join(__dirname, "../router-engine/content.jsx")
- }
- },
- "/test/verbatim": {
- content: {
- module: Path.join(__dirname, "../router-engine/content-verbatim.jsx")
- }
- },
- "/{args*}": {
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/react-helmet": {}
- }
- }
- }
- },
- electrode: {
- logLevel: "none"
- }
- };
- };
-
- let stdoutIntercept;
-
- const stopServer = server => {
- return new Promise((resolve, reject) =>
- server.stop(stopErr => {
- return stopErr ? reject(stopErr) : resolve();
- })
- );
- };
-
- beforeEach(() => {
- config = getConfig();
- configOptions = config.plugins["react-webapp"].options;
- mainRoutePathOptions = configOptions.paths["/{args*}"];
- });
-
- afterEach(() => {
- if (stdoutIntercept) {
- stdoutIntercept.restore();
- stdoutIntercept = undefined;
- }
-
- if (testServer) {
- return stopServer(testServer).then(() => {
- testServer = undefined;
- });
- }
-
- return Promise.resolve();
- });
-
- it("should fail if registering plugin throws", () => {
- let error;
- webapp.register(
- {},
- {
- paths: {
- error: {
- content: { module: "bad-module" }
- }
- }
- },
- err => {
- error = err;
- }
- );
- expect(error).to.be.ok;
- });
-
- it("should successfully render with enterHead scripts", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-static-markup script", { src: "blah-123" }]
- };
-
- const verify = () => {
- return testServer
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
- return electrodeServer(config).then(server => {
- testServer = server;
- return verify().then(verify);
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with insert IDs", () => {
- configOptions.insertTokenIds = true;
- configOptions.templateProcessor = asyncTemplate => {
- asyncTemplate.addTokens({
- insert: "before",
- id: "PAGE_TITLE",
- tokens: [
- { token: "#./test/fixtures/custom-null" },
- { token: "#./test/fixtures/custom-1" },
- { token: "#./test/fixtures/custom-call", props: { _call: "setup", _noInsertId: true } }
- ]
- });
- };
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- const result = res.result;
- expect(result).to.contain("Electrode App ");
- expect(result).to.contain("Hello Electrode
");
- expect(result).to.contain("");
- expect(result).to.not.contain("Unknown marker");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("_call process from custom-call token fixture");
- expect(result).not.contains("");
- expect(result).contains(
- ""
- );
- expect(result).contains(
- ""
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with content as a function", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully return 302 redirect", () => {
- return electrodeServer(config).then(server => {
- return server
- .inject({ method: "GET", url: "/test/component-redirect" })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect-target");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully use content status verbatim", () => {
- let server;
- return asyncVerify(
- () => electrodeServer(config),
- s => {
- server = s;
- return server.inject({ method: "GET", url: "/test/verbatim" });
- },
- res => {
- expect(res.statusCode).to.equal(560);
- },
- runFinally(() => stopServer(server))
- );
- });
-
- it("should return 500 if content rejects with error", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.reject({
- status: 500,
- message: "Internal server error"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.statusMessage).to.equal("Internal Server Error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - foo", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/foo"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - bar", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("bar.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("home.bundle.f07a873ce87fc904a6a5.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/foo.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/bar.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/home.bundle.dev.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev @empty", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/empty"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/bundle.dev.js");
- expect(res.result).to.contain("http://localhost:2992/js/style.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should handle multiple entry points with a prodBundleBase", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/multi/";
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(
- `user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- expect(res.headers["x-foo-bar"]).to.equal("hello-world");
- expect(res.statusCode).to.equal(200);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- err.html = "test content throw html with status";
- err.status = 401;
- return Promise.reject(err);
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(401);
- expect(res.result).contains("test content throw html with status");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws generic error", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("test content throw");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should reply with error stack if option is not false", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- // configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("/test/spec/hapi.index.spec.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle non-render errors", () => {
- assign(mainRoutePathOptions, {
- content: () => ""
- });
-
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/non-render-error"
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("error from test/fixtures/non-render-error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass options with mode as datass from request to content function", () => {
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=datass"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes("no-ss");
- expect(res.result).includes("prefetch-mode: datass");
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass datass mode from routeOptions to content function", () => {
- configOptions.serverSideRendering = "datass";
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes("no-ss");
- expect(res.result).includes("prefetch-mode: datass");
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle mode as noss from request", () => {
- let contentCalled = false;
- assign(mainRoutePathOptions, {
- content: () => {
- contentCalled = true;
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(contentCalled, "content should not have been called").to.equal(false);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(``);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should use route level htmlFile", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- mainRoutePathOptions.htmlFile = Path.resolve("test/data/index-2.html");
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(`test html-2
`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value, if configuration specifies a path and a value is present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspPlugin(server, options, next) {
- server.ext("onRequest", (request, reply) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return reply.continue();
- });
- next();
- }
- cspPlugin.attributes = {
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value as provided by a function in the config", () => {
- configOptions.cspNonceValue = function(request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain(
- ""
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not add a nonce value, if configuration specifies a path and no value present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspPlugin(server, options, next) {
- server.ext("onRequest", (request, reply) => {
- request.plugins.cspPlugin = {};
- return reply.continue();
- });
- next();
- }
- cspPlugin.attributes = {
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value when provided", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = { style: "plugins.cspPlugin.nonceValue" };
- function cspPlugin(server, options, next) {
- server.ext("onRequest", (request, reply) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return reply.continue();
- });
- next();
- }
- cspPlugin.attributes = {
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value provided by a function", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = function(request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 302 redirect", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 302,
- path: "/redirect2"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect2");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it(`should allow content to be ""`, () => {
- assign(mainRoutePathOptions, {
- content: ""
- });
-
- return electrodeServer(config).then(server => {
- return Promise.resolve(
- server.inject({
- method: "GET",
- url: "/"
- })
- )
- .then(resp => {
- expect(resp.result).contains(`
`);
- })
- .finally(() => {
- stopServer(server);
- });
- });
- });
-
- it("should fail if content is null", () => {
- assign(mainRoutePathOptions, {
- content: null
- });
-
- let error;
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .catch(err => {
- error = err;
- })
- .then(() => {
- stopServer(server);
- expect(error).to.exist;
- expect(error.code).to.equal("ERR_ASSERTION");
- expect(error.message).to.equal(
- `You must define content for the webapp plugin path /{args*}`
- );
- });
- });
- });
-
- it("should handle unexpected errors", () => {
- const content = {
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- };
- Object.defineProperty(content, "status", {
- get: () => {
- throw new Error("unexpected error");
- }
- });
-
- assign(mainRoutePathOptions, { content: () => Promise.resolve(content) });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- stopServer(server);
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("unexpected error");
- });
- });
- });
-
- it("should handle 200 status @noss", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @no-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @has-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "test has html"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).contains(`\n\n`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 200 and direct html with render false", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "html
",
- render: false
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.equal("html
");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle content non 200 status noss mode", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 404,
- message: "status 404 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- expect(res.result.message).to.equal("status 404 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 404 and html, if custom html is provided", () => {
- assign(mainRoutePathOptions, {
- responseForBadStatus: null,
- content: {
- status: 404,
- html: "html content"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- expect(res.result).to.contain('html content
');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not fail on not handled status codes", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 501,
- html: "custom 501 HTML message",
- message: "not implemented"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should render if content has html despite non 200 status", () => {
- assign(mainRoutePathOptions, {
- options: {
- responseForBadStatus: null
- },
- content: {
- status: 501,
- html: null
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle option serverSideRendering false", () => {
- configOptions.serverSideRendering = false;
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).includes("");
- expect(res.result).includes(`window["webappStart"]();`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle nojs mode", () => {
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=nojs"
- })
- .then(res => {
- expect(res.result).to.not.includes(
- ``
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should allow support react-helmet with custom token handler", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-1 script"]
- };
- configOptions.templateProcessor = asyncTemplate => {
- const x = asyncTemplate.addTokens({
- insert: "after",
- id: "WEBAPP_HEADER_BUNDLES",
- tokens: [{ token: "REACT_HELMET_SCRIPTS" }]
- });
- expect(x).to.be.above(0);
- };
- assign(configOptions.paths["/react-helmet"], {
- tokenHandler: "./test/fixtures/react-helmet-handler",
- content: () => {
- return {
- status: 200,
- prefetch: "test-react-helmet",
- html: ReactDOMServer.renderToString(
- React.createElement(
- "div",
- null,
- "hello",
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Helmet Title 1"),
- React.createElement("meta", { name: "description", content: "Helmet application" })
- ),
- React.createElement(
- "div",
- null,
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Nested Title"),
- React.createElement("meta", { name: "description", content: "Nested component" })
- )
- )
- )
- )
- };
- }
- });
- stdoutIntercept = xstdout.intercept(true);
- let server;
-
- return electrodeServer(config)
- .then(s => (server = s))
- .then(() => {
- // route doesn't initialize until a request was sent
- return server.inject({ method: "GET", url: "/" }).then(() => {
- stdoutIntercept.restore();
- // since there are two paths and the react-helment-handler is only register for the
- // main path route, expect the other route's registration to cause a error message
- // to the stderr.
- expect(stdoutIntercept.stderr[0]).contains(
- "electrode-react-webapp: no handler found for token id REACT_HELMET_SCRIPTS"
- );
- });
- })
- .then(() => {
- return server
- .inject({
- method: "GET",
- url: "/react-helmet"
- })
- .then(res => {
- expect(res.result).includes(
- ` ` +
- `Nested Title `
- );
- expect(res.result)
- .includes(`window._config.ui = {"webappPrefix":""};\n
-`);
- stopServer(server);
- })
- .catch(err => {
- stdoutIntercept.restore();
- stopServer(server);
- throw err;
- });
- });
- });
-
- describe("with webpackDev", function() {
- it("should skip if webpack dev is not valid", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, reply) => {
- request.app.webpackDev = { valid: false };
- reply.continue();
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should skip if webpack compile has errors", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, reply) => {
- request.app.webpackDev = { valid: true, hasErrors: true };
- reply.continue();
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, reply) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- reply.continue();
- }
- });
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should refresh content module", () => {
- mainRoutePathOptions.content = {
- module: "./test/data/test-content"
- };
-
- return electrodeServer(config).then(server => {
- let compileTime = Date.now();
-
- const testContent1 = {
- status: 200,
- html: "Test1 Electrode
",
- prefetch: "console.log('test1');"
- };
-
- const testContent2 = {
- status: 200,
- html: "Test2 Electrode
",
- prefetch: "console.log('test2');"
- };
-
- server.ext({
- type: "onRequest",
- method: (request, reply) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- reply.continue();
- }
- });
- const makeRequest = () => {
- return server.inject({
- method: "GET",
- url: "/"
- });
- };
-
- const updateTestContent = obj => {
- Fs.writeFileSync(
- Path.resolve("test/data/test-content.js"),
- `module.exports = ${JSON.stringify(obj, null, 2)};\n`
- );
- };
-
- updateTestContent(testContent1);
-
- return xaa
- .wrap(makeRequest)
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test1 Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- compileTime = Date.now();
- })
- .then(() => makeRequest())
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test2 Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- })
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- })
- .finally(() => {
- updateTestContent(testContent1);
- });
- });
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/hapi17.index.spec.js b/packages/electrode-react-webapp/test/spec/hapi17.index.spec.js
deleted file mode 100644
index 2b547eef7..000000000
--- a/packages/electrode-react-webapp/test/spec/hapi17.index.spec.js
+++ /dev/null
@@ -1,2147 +0,0 @@
-"use strict";
-
-/* eslint-disable quotes */
-
-const Fs = require("fs");
-const assign = require("object-assign");
-const electrodeServer = require("electrode-server2");
-const Path = require("path");
-const xstdout = require("xstdout");
-const { expect } = require("chai");
-const ReactDOMServer = require("react-dom/server");
-const React = require("react");
-const Helmet = require("react-helmet").Helmet;
-const { runFinally, asyncVerify } = require("run-verify");
-const Munchy = require("munchy");
-const xaa = require("xaa");
-
-const getConfig = () => {
- return {
- connections: {
- default: {
- port: 0
- }
- },
- plugins: {
- "react-webapp": {
- module: Path.join(__dirname, "../../lib/hapi/plugin17"),
- options: {
- pageTitle: "Electrode App",
- paths: {
- "/test/component-redirect": {
- content: {
- module: Path.join(__dirname, "../router-engine/content.jsx")
- }
- },
- "/test/verbatim": {
- content: {
- module: Path.join(__dirname, "../router-engine/content-verbatim.jsx")
- }
- },
- "/test/context-status": {
- content: {
- module: Path.join(__dirname, "../router-engine/context-status.jsx")
- }
- },
- "/{args*}": {
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/select": {
- selectTemplate: (request, routeOptions) => {
- request.app.routeOptions = routeOptions;
- if (request.query.template === "1") {
- return {
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-1.html"),
- cacheKey: request.query.cache_key,
- cacheId: request.query.cache_id
- };
- } else if (request.query.template === "2") {
- return Promise.resolve({
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-2.html"),
- tokenHandlers: Path.join(__dirname, "../fixtures/token-handler")
- });
- } else if (request.query.template === "3") {
- return {
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-1.html"),
- cacheId: "page_title_1",
- options: {
- pageTitle: "test page title 1"
- }
- };
- } else if (request.query.template === "4") {
- return {
- templateFile: Path.join(__dirname, "../jsx-templates/index-3.jsx")
- };
- }
- return null; // select default
- },
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/react-helmet": {}
- }
- }
- }
- },
- electrode: {
- logLevel: "none"
- }
- };
-};
-
-describe("hapi index", () => {
- beforeEach(() => {
- delete require.cache[require.resolve("../../lib/hapi")];
- delete require.cache[require.resolve("../..")];
- delete require.cache[require.resolve("../../lib/hapi/plugin16")];
- delete require.cache[require.resolve("../../lib/hapi/plugin17")];
- });
-
- it("with hapi 16", () => {
- const compat = require("electrode-hapi-compat");
- compat._testSetHapi17(false);
- const webapp = require("../..");
- expect(webapp.register).to.be.a("function");
- // expect(webapp.register.attributes.pkg.name).eql("electrode-react-webapp");
- expect(webapp.pkg).undefined;
- });
-
- it.skip("with hapi 17", () => {
- const compat = require("electrode-hapi-compat");
- compat._testSetHapi17(true);
- const hapi17 = require("../../lib/hapi/plugin17");
- const webapp = require("../..");
- expect(webapp.register).eq(hapi17.register);
- expect(webapp.pkg).eq(hapi17.pkg);
- expect(webapp.pkg.name).eql("electrode-react-webapp");
- });
-});
-
-describe("hapi 17 electrode-react-webapp", () => {
- let config;
- let configOptions;
- let mainRoutePathOptions;
- let testServer;
- let compat;
-
- let stdoutIntercept;
-
- const stopServer = server => server && server.stop();
-
- beforeEach(() => {
- delete require.cache[require.resolve("../../lib/hapi")];
- delete require.cache[require.resolve("../..")];
- compat = require("electrode-hapi-compat");
- compat._testSetHapi17(true);
-
- config = getConfig();
- configOptions = config.plugins["react-webapp"].options;
- mainRoutePathOptions = configOptions.paths["/{args*}"];
- });
-
- afterEach(() => {
- if (stdoutIntercept) {
- stdoutIntercept.restore();
- stdoutIntercept = undefined;
- }
-
- if (testServer) {
- return testServer.stop().then(() => {
- testServer = undefined;
- });
- }
-
- return Promise.resolve();
- });
-
- it("should fail if registering plugin throws", done => {
- const hapi17 = require("../../lib/hapi/plugin17");
- try {
- hapi17.register(
- {
- route: () => {
- throw Error("bad-module");
- }
- },
- {
- paths: {
- error: {
- content: { module: "bad-module" }
- }
- }
- }
- );
- } catch (err) {
- expect(err).to.be.ok;
- done();
- }
- });
-
- it("should successfully render with enterHead scripts", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-static-markup script", { src: "blah-123" }]
- };
-
- const verify = () => {
- return testServer
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
- return electrodeServer(config).then(server => {
- testServer = server;
- return verify().then(verify);
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with insert IDs", () => {
- configOptions.insertTokenIds = true;
- configOptions.templateProcessor = asyncTemplate => {
- asyncTemplate.addTokens({
- insert: "before",
- id: "PAGE_TITLE",
- tokens: [
- { token: "#./test/fixtures/custom-null" },
- { token: "#./test/fixtures/custom-1" },
- { token: "#./test/fixtures/custom-call", props: { _call: "setup", _noInsertId: true } }
- ]
- });
- };
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- const result = res.result;
- expect(result).to.contain("Electrode App ");
- expect(result).to.contain("Hello Electrode
");
- expect(result).to.contain("");
- expect(result).to.not.contain("Unknown marker");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("_call process from custom-call token fixture");
- expect(result).not.contains("");
- expect(result).contains(
- ""
- );
- expect(result).contains(
- ""
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with content as a function", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with useStream true", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: "Hello Electrode from munchy
",
- prefetch: "console.log('Hello');",
- useStream: true
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode from munchy
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with content html as stream", () => {
- const munchy = new Munchy(
- {},
- "Hello Electrode from munchy stream
",
- "test 2
",
- null
- );
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: munchy,
- prefetch: "console.log('Hello');",
- useStream: true
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode from munchy stream
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully return 302 redirect", () => {
- return electrodeServer(config).then(server => {
- return server
- .inject({ method: "GET", url: "/test/component-redirect" })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect-target");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully use content status verbatim", () => {
- let server;
- return asyncVerify(
- () => electrodeServer(config),
- s => {
- server = s;
- return server.inject({ method: "GET", url: "/test/verbatim" });
- },
- res => {
- expect(res.statusCode).to.equal(560);
- },
- runFinally(() => stopServer(server))
- );
- });
-
- it("should return 500 if content rejects with error", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.reject({
- status: 500,
- message: "Internal server error"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.statusMessage).to.equal("Internal Server Error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - foo", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/foo"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - bar", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("bar.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("home.bundle.f07a873ce87fc904a6a5.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/foo.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/bar.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/home.bundle.dev.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev @empty", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/empty"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/bundle.dev.js");
- expect(res.result).to.contain("http://localhost:2992/js/style.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should handle multiple entry points with a prodBundleBase", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/multi/";
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(
- `user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- expect(res.headers["x-foo-bar"]).to.equal("hello-world");
- expect(res.statusCode).to.equal(200);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- err.html = "test content throw html with status";
- err.status = 401;
- return Promise.reject(err);
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(401);
- expect(res.result).contains("test content throw html with status");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws generic error", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("test content throw");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should reply with error stack if option is not false", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- // configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("/test/spec/hapi17.index.spec.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle non-render errors", () => {
- assign(mainRoutePathOptions, {
- content: () => ""
- });
-
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/non-render-error"
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("error from test/fixtures/non-render-error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass options with mode as datass from request to content function", () => {
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=datass"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes("no-ss");
- expect(res.result).includes("prefetch-mode: datass");
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass datass mode from routeOptions to content function", () => {
- configOptions.serverSideRendering = "datass";
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes("no-ss");
- expect(res.result).includes("prefetch-mode: datass");
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle mode as noss from request", () => {
- let contentCalled = false;
- assign(mainRoutePathOptions, {
- content: () => {
- contentCalled = true;
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(contentCalled, "content should not have been called").to.equal(false);
- expect(res.statusCode).to.equal(200);
- expect(res.result).includes(`user-handler-title `);
- expect(res.result).includes(``);
- expect(res.result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should use route level htmlFile", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- mainRoutePathOptions.htmlFile = Path.resolve("test/data/index-2.html");
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(`test html-2
`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value, if configuration specifies a path and a value is present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value as provided by a function in the config", () => {
- configOptions.cspNonceValue = function (request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain(
- ""
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not add a nonce value, if configuration specifies a path and no value present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {};
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value when provided", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = { style: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- pkg: {
- name: "cspPlugin"
- }
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value provided by a function", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = function (request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 302 redirect", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 302,
- path: "/redirect2"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect2");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it(`should allow content to be ""`, () => {
- assign(mainRoutePathOptions, {
- content: ""
- });
-
- return electrodeServer(config).then(server => {
- return Promise.resolve(
- server.inject({
- method: "GET",
- url: "/"
- })
- )
- .then(resp => {
- expect(resp.result).contains(`
`);
- })
- .finally(() => {
- stopServer(server);
- });
- });
- });
-
- it("should fail if content is null", () => {
- assign(mainRoutePathOptions, {
- content: null
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(response => {
- stopServer(server);
- expect(response.result.statusCode).eq(500);
- expect(response.result.error).eq("Internal Server Error");
- });
- });
- });
-
- it("should handle unexpected errors", () => {
- const content = {
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- };
- Object.defineProperty(content, "status", {
- get: () => {
- throw new Error("unexpected error");
- }
- });
-
- assign(mainRoutePathOptions, { content: () => Promise.resolve(content) });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- stopServer(server);
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("unexpected error");
- });
- });
- });
-
- it("should handle 200 status @noss", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @no-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @has-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "test has html"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).contains(`\n\n`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 200 and direct html with render false", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "html
",
- render: false
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.equal("html
");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle content non 200 status noss mode", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 404,
- message: "status 404 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- expect(res.result.message).to.equal("status 404 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 404 and html, if custom html is provided", () => {
- assign(mainRoutePathOptions, {
- responseForBadStatus: null,
- content: {
- status: 404,
- html: "html content"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- expect(res.result).to.contain('html content
');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not fail on not handled status codes", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 501,
- html: "custom 501 HTML message",
- message: "not implemented"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should render if content has html despite non 200 status", () => {
- assign(mainRoutePathOptions, {
- options: {
- responseForBadStatus: null
- },
- content: {
- status: 501,
- html: null
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle option serverSideRendering false", () => {
- configOptions.serverSideRendering = false;
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).includes("");
- expect(res.result).includes(`window["webappStart"]();`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle nojs mode", () => {
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=nojs"
- })
- .then(res => {
- expect(res.result).to.not.includes(
- ``
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should allow support react-helmet with custom token handler", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-1 script"]
- };
- configOptions.templateProcessor = asyncTemplate => {
- const x = asyncTemplate.addTokens({
- insert: "after",
- id: "WEBAPP_HEADER_BUNDLES",
- tokens: [{ token: "REACT_HELMET_SCRIPTS" }]
- });
- expect(x).to.be.above(0);
- };
- assign(configOptions.paths["/react-helmet"], {
- tokenHandler: "./test/fixtures/react-helmet-handler",
- content: () => {
- return {
- status: 200,
- prefetch: "test-react-helmet",
- html: ReactDOMServer.renderToString(
- React.createElement(
- "div",
- null,
- "hello",
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Helmet Title 1"),
- React.createElement("meta", { name: "description", content: "Helmet application" })
- ),
- React.createElement(
- "div",
- null,
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Nested Title"),
- React.createElement("meta", { name: "description", content: "Nested component" })
- )
- )
- )
- )
- };
- }
- });
- stdoutIntercept = xstdout.intercept(true);
- let server;
- return electrodeServer(config)
- .then(s => (server = s))
- .then(() => {
- return server
- .inject({
- method: "GET",
- url: "/"
-
- })
- .then(() => {
- stdoutIntercept.restore();
- // since there are two paths and the react-helmet-handler is only register for the
- // /react-helmet route, expect the other route's registration to cause a error message
- // to the stderr.
- expect(stdoutIntercept.stderr[0]).contains(
- "electrode-react-webapp: no handler found for token id REACT_HELMET_SCRIPTS"
- );
- });
- })
- .then(() => {
- return server
- .inject({
- method: "GET",
- url: "/react-helmet"
- })
- .then(res => {
- expect(res.result).includes(
- ` ` +
- `Nested Title `
- );
- expect(res.result)
- .includes(`window._config.ui = {"webappPrefix":""};\n
-`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- describe("with webpackDev", function () {
- it("should skip if webpack dev is not valid", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: false };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should skip if webpack compile has errors", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: true };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should select template 1 and render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(htmlFile);
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should cache template using provided cacheKey", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1&cache_key=template_cache_key_test1"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- "template_cache_key_test1"
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should cache template using provided cacheId", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1&cache_id=cache_id_test1"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- `${htmlFile}#cache_id_test1`
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should create new routeOptions from options selectTemplate returns", () => {
- let captureRequest;
- let server;
-
- return asyncVerify(
- () => electrodeServer(config),
- s => {
- server = s;
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
- },
- () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=3"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).contain(`test page title 1 `);
- expect(res.result).to.not.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- `${htmlFile}#page_title_1`
- );
- });
- },
- () => {
- return server
- .inject({
- method: "GET",
- url: "/select"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../../lib/index.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.not.contain(`test page title 1 `);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.not.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.include.all.keys(htmlFile);
- });
- },
- runFinally(() => stopServer(server))
- );
- });
-
- it("should select template 4 set context status", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=4"
- })
- .then(res => {
- expect(res.statusCode).to.equal(204);
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .finally(() => stopServer(server));
- });
- });
-
- it("should select template 2 and render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=2"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("user-handler-title ");
- expect(res.result).to.contain("DYNAMIC_INDEX_2");
- expect(res.result).to.contain("RETURN_BY_TEST_DYANMIC_2");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should use default template if selectTemplate return null", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.not.contain("DYNAMIC_INDEX");
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should refresh content module", () => {
- mainRoutePathOptions.content = {
- module: "./test/data/test-content17"
- };
-
- return electrodeServer(config).then(server => {
- let compileTime = Date.now();
-
- const testContent1 = {
- status: 200,
- html: "Test1 Electrode17
",
- prefetch: "console.log('test1');"
- };
-
- const testContent2 = {
- status: 200,
- html: "Test2 Electrode17
",
- prefetch: "console.log('test2');"
- };
-
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({
- method: "GET",
- url: "/"
- });
- };
-
- const updateTestContent = obj => {
- Fs.writeFileSync(
- Path.resolve("test/data/test-content17.js"),
- `module.exports = ${JSON.stringify(obj, null, 2)};\n`
- );
- };
-
- updateTestContent(testContent1);
-
- return xaa
- .wrap(makeRequest)
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test1 Electrode17
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- compileTime = Date.now();
- })
- .then(() => makeRequest())
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test2 Electrode17
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- })
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- })
- .finally(() => {
- updateTestContent(testContent1);
- });
- });
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/hapi17.jsx-index.spec.js b/packages/electrode-react-webapp/test/spec/hapi17.jsx-index.spec.js
deleted file mode 100644
index 8ec16ddfd..000000000
--- a/packages/electrode-react-webapp/test/spec/hapi17.jsx-index.spec.js
+++ /dev/null
@@ -1,2096 +0,0 @@
-"use strict";
-
-/* eslint-disable quotes */
-
-const Fs = require("fs");
-const assign = require("object-assign");
-const electrodeServer = require("electrode-server2");
-const Path = require("path");
-const { expect } = require("chai");
-const ReactDOMServer = require("react-dom/server");
-const React = require("react");
-const Helmet = require("react-helmet").Helmet;
-const { runFinally, asyncVerify } = require("run-verify");
-const Munchy = require("munchy");
-const xaa = require("xaa");
-
-const getConfig = () => {
- return {
- connections: {
- default: {
- port: 0
- }
- },
- plugins: {
- "react-webapp": {
- module: Path.join(__dirname, "../../lib/hapi/plugin17"),
- options: {
- templateFile: true,
- pageTitle: "Electrode App",
- paths: {
- "/test/component-redirect": {
- content: {
- module: Path.join(__dirname, "../router-engine/content.jsx")
- }
- },
- "/{args*}": {
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/select": {
- selectTemplate: (request, routeOptions) => {
- request.app.routeOptions = routeOptions;
- if (request.query.template === "1") {
- return {
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-1.html"),
- cacheKey: request.query.cache_key,
- cacheId: request.query.cache_id
- };
- } else if (request.query.template === "2") {
- return Promise.resolve({
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-2.html"),
- tokenHandlers: Path.join(__dirname, "../fixtures/token-handler")
- });
- } else if (request.query.template === "3") {
- return {
- htmlFile: Path.join(__dirname, "../fixtures/dynamic-index-1.html"),
- cacheId: "page_title_1",
- options: {
- pageTitle: "test page title 1"
- }
- };
- } else if (request.query.template === "4") {
- return {
- tokenHandlers: Path.join(__dirname, "../fixtures/token-handler")
- };
- }
- return null; // select default
- },
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/react-helmet": {},
- "/intercept": {
- templateFile: Path.join(__dirname, "../jsx-templates/index-intercept"),
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- }
- }
- }
- }
- },
- electrode: {
- logLevel: "none"
- }
- };
-};
-
-describe("hapi 17 electrode-react-webapp with jsx template", () => {
- let config;
- let configOptions;
- let mainRoutePathOptions;
- let testServer;
- let compat;
-
- let stdoutIntercept;
-
- const stopServer = server => server && server.stop();
-
- beforeEach(() => {
- delete require.cache[require.resolve("../../lib/hapi")];
- delete require.cache[require.resolve("../..")];
- compat = require("electrode-hapi-compat");
- compat._testSetHapi17(true);
-
- config = getConfig();
- configOptions = config.plugins["react-webapp"].options;
- mainRoutePathOptions = configOptions.paths["/{args*}"];
- });
-
- afterEach(() => {
- if (stdoutIntercept) {
- stdoutIntercept.restore();
- stdoutIntercept = undefined;
- }
-
- if (testServer) {
- return testServer.stop().then(() => {
- testServer = undefined;
- });
- }
-
- return Promise.resolve();
- });
-
- it("should fail if registering plugin throws", done => {
- const hapi17 = require("../../lib/hapi/plugin17");
- try {
- hapi17.register(
- {
- route: () => {
- throw Error("bad-module");
- }
- },
- {
- paths: {
- error: {
- content: { module: "bad-module" }
- }
- }
- }
- );
- } catch (err) {
- expect(err).to.be.ok;
- done();
- }
- });
-
- it("should successfully render with enterHead scripts", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-static-markup script", { src: "blah-123" }]
- };
-
- const verify = () => {
- return testServer
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain(``);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
- return electrodeServer(config).then(server => {
- testServer = server;
- return verify().then(verify);
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with insert IDs", () => {
- configOptions.insertTokenIds = true;
- return electrodeServer(config).then(server => {
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- const result = res.result;
- expect(result).to.contain("Electrode App ");
- expect(result).to.contain("Hello Electrode
");
- expect(result).to.contain("");
- expect(result).to.not.contain("Unknown marker");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains("");
- expect(result).contains(
- ""
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with content as a function", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with useStream true", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: "Hello Electrode from munchy
",
- prefetch: "console.log('Hello');",
- useStream: true
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode from munchy
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup with content html as stream", () => {
- const munchy = new Munchy(
- {},
- "Hello Electrode from munchy stream
",
- "test 2
",
- null
- );
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.resolve({
- status: 200,
- html: munchy,
- prefetch: "console.log('Hello');",
- useStream: true
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode from munchy stream
");
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully return 302 redirect", () => {
- return electrodeServer(config).then(server => {
- return server
- .inject({ method: "GET", url: "/test/component-redirect" })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect-target");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 500 if content rejects with error", () => {
- assign(mainRoutePathOptions, {
- content: () =>
- Promise.reject({
- status: 500,
- message: "Internal server error"
- })
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.statusMessage).to.equal("Internal Server Error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - foo", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/foo"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - bar", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("bar.bundle.f07a873ce87fc904a6a5.js");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("foo.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("bar.style.f07a873ce87fc904a6a5.css");
- expect(res.result).to.contain("home.bundle.f07a873ce87fc904a6a5.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev multi-chunk", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/multi-chunk"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/foo.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/bar.style.css");
- expect(res.result).to.contain("http://localhost:2992/js/home.bundle.dev.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle multiple entry points - @dev @empty", () => {
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/empty"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("http://localhost:2992/js/bundle.dev.js");
- expect(res.result).to.contain("http://localhost:2992/js/style.css");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should handle multiple entry points with a prodBundleBase", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/multi/";
- configOptions.bundleChunkSelector = "test/data/chunk-selector.js";
- configOptions.stats = "test/data/stats-test-multibundle.json";
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/bar"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain(
- `user-promise-token
\nfrom custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- expect(res.headers["x-foo-bar"]).to.equal("hello-world");
- expect(res.statusCode).to.equal(200);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- err.html = "test content throw html with status";
- err.status = 401;
- return Promise.reject(err);
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(401);
- expect(res.result).contains("test content throw html with status");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle if content function throws generic error", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("test content throw");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should reply with error stack if option is not false", () => {
- assign(mainRoutePathOptions, {
- content: () => {
- const err = new Error("test content throw");
- return Promise.reject(err);
- }
- });
-
- // configOptions.replyErrorStack = false;
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("/test/spec/hapi17.jsx-index.spec.js");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle non-render errors", () => {
- assign(mainRoutePathOptions, {
- content: () => ""
- });
-
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/non-render-error"
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("error from test/fixtures/non-render-error");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass options with mode as datass from request to content function", () => {
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.templateFile = "test/jsx-templates/index-1";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=datass"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- const result = res.result.split("\n").join("");
- expect(result).includes("no-ss");
- expect(result).includes("prefetch-mode: datass");
- expect(result).includes(`user-handler-title `);
- expect(result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should pass datass mode from routeOptions to content function", () => {
- configOptions.serverSideRendering = "datass";
- let ssrPrefetchOnly;
- assign(mainRoutePathOptions, {
- content: request => {
- ssrPrefetchOnly = request.app.ssrPrefetchOnly;
- const mode = ssrPrefetchOnly && "datass";
- return Promise.resolve({
- status: 200,
- html: "no-ss",
- prefetch: `prefetch-mode: ${mode}`
- });
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.templateFile = "test/jsx-templates/index-1";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(ssrPrefetchOnly).to.equal(true);
- expect(res.statusCode).to.equal(200);
- const result = res.result.split("\n").join("");
- expect(result).includes("no-ss");
- expect(result).includes("prefetch-mode: datass");
- expect(result).includes(`user-handler-title `);
- expect(result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle mode as noss from request", () => {
- let contentCalled = false;
- assign(mainRoutePathOptions, {
- content: () => {
- contentCalled = true;
- }
- });
-
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.templateFile = "test/jsx-templates/index-1";
- Object.assign(mainRoutePathOptions, {
- tokenHandler: "./test/fixtures/token-handler"
- });
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(contentCalled, "content should not have been called").to.equal(false);
- expect(res.statusCode).to.equal(200);
- const result = res.result.split("\n").join("");
- expect(result).includes(`user-handler-title `);
- expect(result).includes(``);
- expect(result).includes(`user-promise-token
from custom-1
user-token-1
user-token-2
` // eslint-disable-line
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should use route level templateFile", () => {
- configOptions.prodBundleBase = "http://awesome-cdn.com/myapp/";
- configOptions.stats = "test/data/stats-test-one-bundle.json";
- configOptions.htmlFile = "test/data/index-1.html";
- mainRoutePathOptions.templateFile = Path.resolve("test/jsx-templates/index-2");
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- const result = res.result.split("\n").join("");
- expect(result).to.contain(`test jsx-2
`);
- expect(result).contains(`Hello from async tag JSX-2
`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value, if configuration specifies a path and a value is present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should add a nonce value as provided by a function in the config", () => {
- configOptions.cspNonceValue = function(request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain(
- ""
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not add a nonce value, if configuration specifies a path and no value present", () => {
- configOptions.cspNonceValue = { script: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {};
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- name: "cspPlugin"
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).to.contain("");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value when provided", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = { style: "plugins.cspPlugin.nonceValue" };
- function cspRegister(server) {
- server.ext("onRequest", (request, h) => {
- request.plugins.cspPlugin = {
- nonceValue: "==ABCD"
- };
- return h.continue;
- });
- }
- const cspPlugin = {
- register: cspRegister,
- pkg: {
- name: "cspPlugin"
- }
- };
-
- return electrodeServer(config).then(server => {
- // Add a trivial csp generator for testing purposes.
- server.register(cspPlugin);
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should inject critical css with a nonce value provided by a function", () => {
- configOptions.criticalCSS = "test/data/critical.css";
- configOptions.cspNonceValue = function(request, type) {
- return `==${type}`;
- };
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain('');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 302 redirect", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 302,
- path: "/redirect2"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(302);
- expect(res.headers.location).to.equal("/redirect2");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it(`should allow content to be ""`, () => {
- assign(mainRoutePathOptions, {
- content: ""
- });
-
- return electrodeServer(config).then(server => {
- return Promise.resolve(
- server.inject({
- method: "GET",
- url: "/"
- })
- )
- .then(res => {
- const result = res.result.split("\n").join("");
- expect(result).contains(`
`);
- })
- .finally(() => {
- stopServer(server);
- });
- });
- });
-
- it("should fail if content is null", () => {
- assign(mainRoutePathOptions, {
- content: null
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(response => {
- stopServer(server);
- expect(response.result.statusCode).eq(500);
- expect(response.result.error).eq("Internal Server Error");
- });
- });
- });
-
- it("should handle unexpected errors", () => {
- const content = {
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- };
- Object.defineProperty(content, "status", {
- get: () => {
- throw new Error("unexpected error");
- }
- });
-
- assign(mainRoutePathOptions, { content: () => Promise.resolve(content) });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- stopServer(server);
- expect(res.statusCode).to.equal(500);
- expect(res.result).contains("unexpected error");
- });
- });
- });
-
- it("should handle 200 status @noss", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @no-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- message: "status 200 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result.message).to.equal("status 200 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle 200 status @noss @has-html", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "test has html"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- const result = res.result.split("\n").join("");
- expect(result).contains(``);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 200 and direct html with render false", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 200,
- html: "html
",
- render: false
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.equal("html
");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle content non 200 status noss mode", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 404,
- message: "status 404 noss"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- expect(res.result.message).to.equal("status 404 noss");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should return 404 and html, if custom html is provided", () => {
- assign(mainRoutePathOptions, {
- responseForBadStatus: null,
- content: {
- status: 404,
- html: "html content"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(404);
- const result = res.result.split("\n").join("");
- expect(result).to.contain('html content
');
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should not fail on not handled status codes", () => {
- assign(mainRoutePathOptions, {
- content: {
- status: 501,
- html: "custom 501 HTML message",
- message: "not implemented"
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should render if content has html despite non 200 status", () => {
- assign(mainRoutePathOptions, {
- options: {
- responseForBadStatus: null
- },
- content: {
- status: 501,
- html: null
- }
- });
-
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=noss"
- })
- .then(res => {
- expect(res.statusCode).to.equal(501);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle option serverSideRendering false", () => {
- configOptions.serverSideRendering = false;
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.result).includes("");
- expect(res.result).includes(`window["webappStart"]();`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should handle nojs mode", () => {
- process.env.WEBPACK_DEV = "true";
- return electrodeServer(config)
- .then(server => {
- return server
- .inject({
- method: "GET",
- url: "/?__mode=nojs"
- })
- .then(res => {
- expect(res.result).to.not.includes(
- ``
- );
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- })
- .finally(() => {
- delete process.env.WEBPACK_DEV;
- });
- });
-
- it("should handle user intercept on rendering", () => {
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/intercept"
- })
- .then(res => {
- expect(res.result).equals("context intercept handler");
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should allow support react-helmet with custom token handler", () => {
- configOptions.unbundledJS = {
- enterHead: ["test-1 script"]
- };
- configOptions.insertTokenIds = true;
-
- assign(configOptions.paths["/react-helmet"], {
- insertTokenIds: false,
- tokenHandler: "./test/fixtures/react-helmet-handler",
- content: () => {
- return {
- status: 200,
- prefetch: "test-react-helmet",
- html: ReactDOMServer.renderToString(
- React.createElement(
- "div",
- null,
- "hello",
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Helmet Title 1"),
- React.createElement("meta", { name: "description", content: "Helmet application" })
- ),
- React.createElement(
- "div",
- null,
- React.createElement(
- Helmet,
- null,
- React.createElement("title", null, "Nested Title"),
- React.createElement("meta", { name: "description", content: "Nested component" })
- )
- )
- )
- )
- };
- }
- });
- let server;
- return electrodeServer(config)
- .then(s => (server = s))
- .then(() => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- // since there are two paths and the react-helmet-handler is only register for the
- // /react-helmet route, expect the other route's result to not find handler for it
- expect(res.result).contains(
- "REACT_HELMET_SCRIPTS removed due to its handler set to null"
- );
- });
- })
- .then(() => {
- return server
- .inject({
- method: "GET",
- url: "/react-helmet"
- })
- .then(res => {
- const result = res.result.split("\n").join("");
- // expect(result).includes(
- // ` `
- // );
- expect(result).includes(`Nested Title `);
- expect(result)
- .includes(`window._config.ui = {"webappPrefix":""};\
-`);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- describe("with webpackDev", function() {
- it("should skip if webpack dev is not valid", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: false };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should skip if webpack compile has errors", () => {
- return electrodeServer(config).then(server => {
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: true };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({ method: "GET", url: "/" }).then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("");
- });
- };
-
- return makeRequest()
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should successfully render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should select template 1 and render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(htmlFile);
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should cache template using provided cacheKey", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1&cache_key=template_cache_key_test1"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- "template_cache_key_test1"
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should cache template using provided cacheId", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- let captureRequest;
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=1&cache_id=cache_id_test1"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- `${htmlFile}#cache_id_test1`
- );
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should render with selectTemplate even if htmlFile is not specified", () => {
- return electrodeServer(config).then(server => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=4"
- })
- .then(res => {
- expect(res.statusCode).equal(200);
- stopServer(server);
- })
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should create new routeOptions from options selectTemplate returns", () => {
- let captureRequest;
- let server;
-
- return asyncVerify(
- () => electrodeServer(config),
- s => {
- server = s;
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- captureRequest = request;
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
- },
- () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=3"
- })
- .then(res => {
- const htmlFile = Path.join(__dirname, "../fixtures/dynamic-index-1.html");
- expect(res.statusCode).to.equal(200);
- expect(res.result).contain(`test page title 1 `);
- expect(res.result).to.not.contain("Electrode App ");
- expect(res.result).to.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.have.keys(
- `${htmlFile}#page_title_1`
- );
- });
- },
- () => {
- return server
- .inject({
- method: "GET",
- url: "/select"
- })
- .then(res => {
- const templateFile = Path.join(__dirname, "../../template/index");
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.not.contain(`test page title 1 `);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.not.contain("DYNAMIC_INDEX_1");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- expect(captureRequest.app.routeOptions._templateCache).to.include.all.keys(
- templateFile
- );
- });
- },
- runFinally(() => stopServer(server))
- );
- });
-
- it("should select template 2 and render to static markup", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select?template=2"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("user-handler-title ");
- expect(res.result).to.contain("DYNAMIC_INDEX_2");
- expect(res.result).to.contain("RETURN_BY_TEST_DYANMIC_2");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should use default template if selectTemplate return null", () => {
- return electrodeServer(config).then(server => {
- const compileTime = Date.now();
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime };
- return h.continue;
- }
- });
-
- const makeRequest = () => {
- return server
- .inject({
- method: "GET",
- url: "/select"
- })
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.not.contain("DYNAMIC_INDEX");
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Hello Electrode
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- });
- };
-
- return makeRequest()
- .then(() => makeRequest())
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- });
- });
- });
-
- it("should refresh content module", () => {
- mainRoutePathOptions.content = {
- module: "./test/data/test-content17"
- };
-
- return electrodeServer(config).then(server => {
- let compileTime = Date.now();
-
- const testContent1 = {
- status: 200,
- html: "Test1 Electrode17
",
- prefetch: "console.log('test1');"
- };
-
- const testContent2 = {
- status: 200,
- html: "Test2 Electrode17
",
- prefetch: "console.log('test2');"
- };
-
- server.ext({
- type: "onRequest",
- method: (request, h) => {
- request.app.webpackDev = { valid: true, hasErrors: false, compileTime, blah: true };
- return h.continue;
- }
- });
- const makeRequest = () => {
- return server.inject({
- method: "GET",
- url: "/"
- });
- };
-
- const updateTestContent = obj => {
- Fs.writeFileSync(
- Path.resolve("test/data/test-content17.js"),
- `module.exports = ${JSON.stringify(obj, null, 2)};\n`
- );
- };
-
- delete require.cache[require.resolve(Path.resolve("test/data/test-content17.js"))];
-
- updateTestContent(testContent1);
-
- return xaa
- .wrap(makeRequest)
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test1 Electrode17
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- compileTime = Date.now();
- })
- .then(() => makeRequest())
- .then(res => {
- expect(res.statusCode).to.equal(200);
- expect(res.result).to.contain("Electrode App ");
- expect(res.result).to.contain("Test2 Electrode17
");
- expect(res.result).to.contain("");
- expect(res.result).to.not.contain("Unknown marker");
- updateTestContent(testContent2);
- })
- .then(() => stopServer(server))
- .catch(err => {
- stopServer(server);
- throw err;
- })
- .finally(() => {
- updateTestContent(testContent1);
- });
- });
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/jsx/jsx-renderer.spec.js b/packages/electrode-react-webapp/test/spec/jsx/jsx-renderer.spec.js
deleted file mode 100644
index c8ce65ac0..000000000
--- a/packages/electrode-react-webapp/test/spec/jsx/jsx-renderer.spec.js
+++ /dev/null
@@ -1,238 +0,0 @@
-/* @jsx createElement */
-
-/* eslint-disable no-unused-vars */
-
-"use strict";
-
-const Path = require("path");
-const Fs = require("fs");
-const { JsxRenderer, Component, IndexPage, createElement } = require("../../..").jsx;
-import Template from "../../jsx-templates/test1";
-import Template2 from "../../jsx-templates/test2";
-import Template3 from "../../jsx-templates/test3";
-
-import Template4 from "../../jsx-templates/test4";
-
-describe("Component", function() {
- it("should have isComponent and render method", () => {
- const x = new Component();
- expect(x.isComponent()).to.equal(true);
- expect(x.render()).to.equal("component");
- });
-});
-
-describe("IndexPage", function() {
- it("should have static memoize", () => {
- expect(IndexPage.memoize({})).equal(``);
- expect(IndexPage.memoize({ DOCTYPE: "blah" })).equal(``);
- });
-});
-
-describe("Jsx Renderer", function() {
- it("getTokenInst should return undefined if no token instance", () => {
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test1")),
- template: Template,
- tokenHandlers: "./test/fixtures/token-handler"
- });
- expect(renderer.getTokenInst({ props: { _id: "blah" } })).to.equal(undefined);
- });
-
- it("should have re-entrant initializeRenderer", () => {
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test1")),
- template: Template,
- tokenHandlers: "./test/fixtures/token-handler"
- });
- renderer.initializeRenderer();
- renderer.initializeRenderer(true);
- renderer.initializeRenderer();
- });
-
- it("should give top level Components depth 0", () => {
- const TestDepth = (props, context, scope) => {
- return `TestDepth: ${scope.depth}`;
- };
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test1")),
- // IndexPage doesn't nest its children so depth doesn't increase from it
- template: (
-
-
-
-
-
-
-
-
- ),
- tokenHandlers: "./test/fixtures/token-handler"
- });
- renderer.initializeRenderer();
- return renderer.render({}).then(context => {
- expect(context.output._result).contains("TestDepth: 0");
- });
- });
-
- it("should recreate nest Components and give them depth > 0", () => {
- const TestDepth2 = (props, context, scope) => {
- return `TestDepth2: ${scope.depth} elementId: ${scope.element.id}`;
- };
-
- const TestDepth1 = (props, context, scope) => {
- return (
-
- {`TestDepth1: ${scope.depth} elementId: ${scope.element.id}`}
-
- {props.children}
-
- );
- };
-
- const TestDepth0 = (props, context, scope) => {
- return (
-
- {`TestDepth0: ${scope.depth} elementId: ${scope.element.id}`}
- {props.children}
-
- );
- };
-
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test1")),
- // IndexPage doesn't nest its children so depth doesn't increase from it
- template: (
-
-
-
-
-
-
-
-
-
-
- ),
- tokenHandlers: "./test/fixtures/token-handler"
- });
-
- renderer.initializeRenderer();
- const testRender = () => renderer.render({}).then(context => context.output._result);
-
- const results = [];
- return testRender()
- .then(r => results.push(r))
- .then(testRender)
- .then(r => results.push(r))
- .then(() => {
- results.forEach(r => {
- expect(r).contains("TestDepth0: 0");
- expect(r).contains("TestDepth1: 1");
- expect(r).contains("TestDepth2: 2");
- });
- const regex = /TestDepth2: 2 elementId: ([0-9]+)\n/;
- const a = parseInt(results[0].match(regex)[1]);
- const b = parseInt(results[1].match(regex)[1]);
- expect(a).to.be.above(0);
- expect(b).to.be.above(0);
- expect(b).to.be.above(a);
- });
- });
-
- const test1ExpectedOutput = Fs.readFileSync(
- Path.join(__dirname, "test1-output.txt"),
- "utf8"
- ).trim();
-
- it("should render index page in JSX", () => {
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test1")),
- template: Template,
- tokenHandlers: "./test/fixtures/token-handler"
- });
-
- const verify = context => {
- const r = context.output._result
- .trim()
- .split("\n")
- .map(x => x.trimRight())
- .join("\n");
-
- expect(r).equal(test1ExpectedOutput);
- };
-
- renderer.initializeRenderer();
-
- const promise = renderer.render({});
- return promise.then(context => {
- verify(context);
- return renderer.render({}).then(verify);
- });
- });
-
- it("should handle failure in nesting async components", () => {
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test2")),
- template: Template2,
- tokenHandlers: "./test/fixtures/token-handler"
- });
-
- renderer.initializeRenderer();
-
- const promise = renderer.render({});
- return promise.then(context => {
- expect(context.result.message).equal("test async component fail");
- });
- });
-
- it("should have unique Token instances for multiple tokens with same _id", () => {
- const renderer = new JsxRenderer({
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test4")),
- template: Template4,
- tokenHandlers: "./test/fixtures/token-handler"
- });
-
- renderer.initializeRenderer();
-
- const promise = renderer.render({});
- return promise.then(context => {
- const r = context.output._result.split("\n").join("_");
- expect(r).contains("require1_require2_require3");
- });
- });
-
- const test3ExpectedOutput = Fs.readFileSync(
- Path.join(__dirname, "test3-output.txt"),
- "utf8"
- ).trim();
-
- it("should handle component nesting children", () => {
- const renderer = new JsxRenderer({
- insertTokenIds: true,
- templateFullPath: Path.dirname(require.resolve("../../jsx-templates/test3")),
- template: Template3,
- tokenHandlers: "./test/fixtures/token-handler"
- });
-
- renderer.initializeRenderer();
-
- const promise = renderer.render({});
- return promise.then(context => {
- const r = context.output._result
- .trim()
- .split("\n")
- .map(x => x.trimRight())
- .join("\n");
-
- expect(r).to.equal(test3ExpectedOutput);
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/jsx/test1-output.txt b/packages/electrode-react-webapp/test/spec/jsx/test1-output.txt
deleted file mode 100644
index 4e211ef73..000000000
--- a/packages/electrode-react-webapp/test/spec/jsx/test1-output.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-
-from test component1
-
-
-
-
-
-
-
-
user-handler-title
-my test
-
-
-
-
-
-user-handler-title
-
-
-token process module subapp-web/lib/init not found
-
-
-
-
-component nesting children
-=async component 1
-
async component children:
-
test nested async components 1
-
-
-
-==async component 2
-
async component children:
-
test nested async components 2
-
-
-
-
-
-
-from test component1
-hello
-
-
-
-user-token-2
-
-JavaScript is Disabled
-
-Sorry, this webpage requires JavaScript to function correctly.
-
-Please enable JavaScript in your browser and reload the page.
-
-
-
-
from custom-1
-
-
-token process module subapp-web/lib/load not found
-
-
-
-
-token process module subapp-web/lib/load not found
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/spec/jsx/test3-output.txt b/packages/electrode-react-webapp/test/spec/jsx/test3-output.txt
deleted file mode 100644
index eeac121cd..000000000
--- a/packages/electrode-react-webapp/test/spec/jsx/test3-output.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-
-nesting children
-
component1
-a
-
-
-
-
component1
-b
-
-
-
-
component1
-+a
-
-
inside component1
-
-
-
-
-
-async component
-x
- children:
-
component1
-x1
-
-
-
-
nesting children
-
component1
-m
-
-
-
-
component1
-n
-
-
-
-
component1
-+a
-
-
inside component1
-
-
-
-
-
-
component1
-x2
-
-
-
-
diff --git a/packages/electrode-react-webapp/test/spec/koa.index.spec.js b/packages/electrode-react-webapp/test/spec/koa.index.spec.js
deleted file mode 100644
index ea0a89cbf..000000000
--- a/packages/electrode-react-webapp/test/spec/koa.index.spec.js
+++ /dev/null
@@ -1,302 +0,0 @@
-"use strict";
-
-/* eslint-disable no-magic-numbers */
-
-const Path = require("path");
-const Koa = require("koa");
-const koaRouter = require("koa-router");
-const registerRoutes = require("../../lib/koa");
-const request = require("superagent");
-const expect = require("chai").expect;
-
-describe("koa electrode-react-webapp", function() {
- const webappOptions = responseForBadStatus => {
- return {
- pageTitle: "Electrode App",
- responseForBadStatus,
- paths: {
- "/": {
- content: {
- status: 200,
- html: "Hello Electrode
",
- prefetch: "console.log('Hello');"
- }
- },
- "/func": {
- content: () => {
- return Promise.resolve({
- status: 200,
- html: "Hello Electrode Function
",
- prefetch: "console.log('Hello');"
- });
- }
- },
- "/all": {
- method: "*",
- content: {
- status: 200,
- html: "Test All",
- prefetch: "console.log('Hello all');"
- }
- },
- "/fail": {
- content: req => {
- const status = req.query.status;
- const html = req.query.html;
- const x = new Error(`test fail ${status}`);
- if (status) {
- x.status = +status;
- }
- if (html) {
- x.html = html;
- }
- return Promise.reject(x);
- }
- },
- "/status": {
- content: req => {
- const html = req.query.html;
- const message = req.query.message || (html === undefined ? "no html" : undefined);
- let render;
- if (req.query.render !== undefined) {
- render = Boolean(+req.query.render);
- }
- return {
- status: +req.query.status,
- html,
- message,
- render
- };
- }
- },
- "/redirect": {
- content: {
- status: 302,
- path: "/redirect2"
- }
- },
- "/string": {
- content: "test content as a string"
- }
- }
- };
- };
-
- let koaServer;
-
- afterEach(() => {
- if (koaServer) {
- const server = koaServer;
- koaServer = undefined;
- return new Promise(resolve => server.close(resolve));
- }
- return null;
- });
-
- const startServer = options => {
- const app = new Koa();
- const router = koaRouter();
- registerRoutes(router, options);
- app.use(router.routes());
- koaServer = app.listen(0);
- return koaServer;
- };
-
- const promiseRequest = req => {
- return new Promise((resolve, reject) => {
- try {
- req.end((err, resp) => {
- if (err) reject(err);
- else resolve(resp);
- });
- } catch (err) {
- reject(err);
- }
- });
- };
-
- const promiseFailRequest = req => {
- return new Promise((resolve, reject) => {
- try {
- req.end(err => {
- if (err) resolve(err);
- else reject(new Error("expecting error from request"));
- });
- } catch (err) {
- reject(err);
- }
- });
- };
-
- it("should render to static markup", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- const makeRequest = () => {
- return promiseRequest(request(`http://localhost:${port}`)).then(resp => {
- expect(resp.text).includes("Hello Electrode
");
- expect(resp.text).includes("console.log('Hello');");
- });
- };
-
- return makeRequest().then(() => makeRequest());
- });
-
- it("should render to static markup @func_content", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(request(`http://localhost:${port}/func`)).then(resp => {
- expect(resp.text).includes("Hello Electrode Function
");
- expect(resp.text).includes("console.log('Hello');");
- });
- });
-
- it("should render to static markup @func_content @noss", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(request(`http://localhost:${port}/func?__mode=noss`)).then(resp => {
- expect(resp.text).includes(`
`);
- });
- });
-
- it("should return non 200 errors with html and stack", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
-
- return promiseFailRequest(
- request(`http://localhost:${port}/fail?status=404&html=html-foo-bar`)
- ).then(error => {
- expect(error).to.be.ok;
- expect(error.status).to.equal(404);
- expect(error.response.text).contains("test fail 404");
- expect(error.response.text).contains("html-foo-bar");
- expect(error.response.text).contains("/test/spec/koa.index.spec.js");
- });
- });
-
- it("should handle and return 500 on non-render errors", () => {
- const options = webappOptions();
- options.tokenHandlers = Path.join(__dirname, "../fixtures/non-render-error");
- const server = startServer(options);
- const port = server.address().port;
- return promiseFailRequest(request(`http://localhost:${port}/`)).then(error => {
- expect(error).to.be.ok;
- expect(error.status).to.equal(500);
- expect(error.response.text).contains("error from test/fixtures/non-render-error");
- });
- });
-
- it("should return 404 and html, if custom html is provided", () => {
- const server = startServer(webappOptions(null));
- const port = server.address().port;
- return promiseFailRequest(
- request(`http://localhost:${port}/status?status=404&html=NotFoundHTML&render=0`)
- ).then(error => {
- expect(error).to.be.ok;
- expect(error.status).to.equal(404);
- expect(error.response.text).to.equal("NotFoundHTML");
- });
- });
-
- it("should not fail on 404 if no html is provided", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseFailRequest(
- request(`http://localhost:${port}/status?status=404&data=test&render=0`)
- ).then(error => {
- expect(error).to.be.ok;
- expect(error.status).to.equal(404);
- });
- });
-
- it("should return 200 and html with render false", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(
- request(`http://localhost:${port}/status?status=200&html=HelloTestHTML&render=0`)
- ).then(resp => {
- expect(resp.status).to.equal(200);
- expect(resp.text).to.equal("HelloTestHTML");
- });
- });
-
- it("should return 500 on errors", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseFailRequest(request(`http://localhost:${port}/fail`)).then(error => {
- expect(error).to.be.ok;
- expect(error.status).to.equal(500);
- expect(error.response.text).contains("test fail undefined");
- });
- });
-
- it("should return 302 on redirect", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseFailRequest(request(`http://localhost:${port}/redirect`).redirects(0)).then(
- err => {
- expect(err.status).to.equal(302);
- expect(err.response.text).includes("/redirect2");
- }
- );
- });
-
- it("should return non 200 status", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseFailRequest(
- request(`http://localhost:${port}/status?status=401&message=HelloTest401`)
- ).then(err => {
- expect(err.status).to.equal(401);
- expect(err.response.body.message).to.equal("HelloTest401");
- });
- });
-
- it("should return 200 status with render off", () => {
- const server = startServer(webappOptions());
-
- const port = server.address().port;
- return promiseRequest(
- request(`http://localhost:${port}/status?status=200&message=HelloTest200`)
- ).then(resp => {
- expect(resp.status).to.equal(200);
- expect(resp.body.message).to.equal("HelloTest200");
- });
- });
-
- it("should handle content as a string", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(request(`http://localhost:${port}/string`)).then(resp => {
- expect(resp.text).includes("");
- expect(resp.text).includes(">test content as a string");
- });
- });
-
- it("@no-html should return JSON with 200 status with ss off", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(request(`http://localhost:${port}/status?status=200`)).then(resp => {
- expect(resp.status).to.equal(200);
- expect(resp.body.message).to.equal("no html");
- });
- });
-
- it("should setup route to all methods", () => {
- const server = startServer(webappOptions());
- const port = server.address().port;
- return promiseRequest(request.post(`http://localhost:${port}/all`).send({})).then(resp => {
- expect(resp.text).includes("Test All");
- expect(resp.text).includes("console.log('Hello all');");
- });
- });
-
- it("should handle option serverSideRendering false", () => {
- const options = webappOptions();
- options.serverSideRendering = false;
- const server = startServer(options);
- const port = server.address().port;
- return promiseRequest(request(`http://localhost:${port}`)).then(resp => {
- expect(resp.text).includes("");
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/load-handler.spec.js b/packages/electrode-react-webapp/test/spec/load-handler.spec.js
deleted file mode 100644
index 4fded60a1..000000000
--- a/packages/electrode-react-webapp/test/spec/load-handler.spec.js
+++ /dev/null
@@ -1,22 +0,0 @@
-"use strict";
-
-const loadHandler = require("../../lib/load-handler");
-const expect = require("chai").expect;
-
-describe("token module load handler", function() {
- it("should handle ES6 module default", () => {
- const x = loadHandler("../fixtures/token-mod-es6-default", __dirname);
- expect(x.toString()).contains("function es6Default");
- });
-
- it("should handle module exporting tokenHandler", () => {
- const x = loadHandler("../fixtures/token-mod-handler", __dirname);
- expect(x.toString()).contains("function asTokenHandler");
- });
-
- it("should handle module with invalid export", () => {
- expect(() => loadHandler("../fixtures/token-mod-invalid", __dirname)).throw(
- "token module invalid"
- );
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/react-webapp.spec.js b/packages/electrode-react-webapp/test/spec/react-webapp.spec.js
deleted file mode 100644
index cf14b27c7..000000000
--- a/packages/electrode-react-webapp/test/spec/react-webapp.spec.js
+++ /dev/null
@@ -1,149 +0,0 @@
-"use strict";
-
-const Path = require("path");
-const reactWebapp = require("../../lib/react-webapp");
-const expect = require("chai").expect;
-const xstdout = require("xstdout");
-
-describe("react-webapp", function() {
- describe("resolveContent", function() {
- it("should require module with relative path", () => {
- const f = "./test/data/foo.js";
- expect(reactWebapp.resolveContent({ module: f }).content).to.equal("hello");
- });
-
- it("should log error if resolving content fail", () => {
- const intercept = xstdout.intercept(true);
- const f = "./test/data/bad-content.js";
- const content = reactWebapp.resolveContent({ module: f });
- intercept.restore();
- expect(content.content).includes("test/data/bad-content.js");
- expect(intercept.stderr.join("")).includes("Error: Cannot find module 'foo-blah'");
- });
-
- it("should require module", () => {
- let mod;
- const fooRequire = x => (mod = x);
- fooRequire.resolve = x => x;
- const f = "test";
- const content = reactWebapp.resolveContent({ module: f }, fooRequire);
- expect(content.content).to.equal(f);
- expect(content.fullPath).to.equal(f);
- expect(mod).to.equal(f);
- });
- });
-
- describe("makeRouteHandler", () => {
- it("should not add default handler if it's already included in options", () => {
- const htmlFile = Path.resolve("test/fixtures/test-render-context.html");
- const defaultReactHandler = Path.join(__dirname, "../../lib/react/token-handlers");
- const intercept = xstdout.intercept(false);
- const handleRoute = reactWebapp.makeRouteHandler({
- htmlFile,
- tokenHandlers: [
- {
- name: "internal-test-handler",
- beforeRender: context => {
- expect(context.user).to.equal(false);
- context.handleError = () => {};
- },
- afterRender: context => {
- expect(context.user, "should have context.user").to.not.equal(false);
- },
- tokens: {
- "internal-test": () => "\ninternal-test",
- "test-not-found": () => "\nnot found",
- "non-func-token": ""
- }
- },
- defaultReactHandler
- ],
- __internals: { assets: {}, chunkSelector: () => ({}) }
- });
-
- const promise = handleRoute({ request: {}, content: { status: 200, html: "" } });
-
- return promise
- .then(context => {
- intercept.restore();
- const expected = `
-from wants next module
-from async ok module
-from async error module
-from string only module
-internal-test
-from async error module
-from wants next module
-not found
-from string only module
-from async ok module`;
- expect(context.result).to.equal(expected);
- })
- .catch(err => {
- intercept.restore();
- throw err;
- });
- });
-
- it("should not add default handler replaceTokenHandlers is true", () => {
- const htmlFile = Path.resolve("test/fixtures/test-render-context.html");
- const intercept = xstdout.intercept(false);
- const handleRoute = reactWebapp.makeRouteHandler({
- htmlFile,
- replaceTokenHandlers: true,
- tokenHandlers: [
- {
- name: "internal-test-handler",
- beforeRender: context => {
- expect(context.user).to.equal(false);
- context.handleError = () => {};
- },
- tokens: {
- "internal-test": () => "\ninternal-test",
- "test-not-found": () => "\nnot found",
- "non-func-token": ""
- }
- }
- ],
- __internals: { assets: {}, chunkSelector: () => ({}) }
- });
-
- const promise = handleRoute({ request: {}, content: { status: 200, html: "" } });
-
- return promise
- .then(context => {
- intercept.restore();
- const expected = `
-from wants next module
-from async ok module
-from async error module
-from string only module
-internal-test
-from async error module
-from wants next module
-not found
-from string only module
-from async ok module`;
- expect(context.result).to.equal(expected);
- })
- .catch(err => {
- intercept.restore();
- throw err;
- });
- });
- });
-
- describe("setupOptions", function() {
- it("should enable https if ENV is set", () => {
- process.env.WEBPACK_DEV_HTTPS = "true";
- const opt = reactWebapp.setupOptions({});
- expect(opt.__internals.devBundleBase).to.match(/^https:/);
- });
-
- it(`should not enable https if ENV is set to "false"`, () => {
- process.env.WEBPACK_DEV_HTTPS = "false";
- const opt = reactWebapp.setupOptions({});
- expect(opt.__internals.devBundleBase).not.to.match(/^https:/);
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/react/content.spec.js b/packages/electrode-react-webapp/test/spec/react/content.spec.js
deleted file mode 100644
index 951d18393..000000000
--- a/packages/electrode-react-webapp/test/spec/react/content.spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-"use stritct";
-
-const Path = require("path");
-const content = require("../../../lib/react/content");
-
-describe("content", function() {
- let saveEnv;
- const cwd = process.cwd();
-
- before(() => {
- saveEnv = process.env.NODE_ENV;
- });
-
- after(() => {
- if (saveEnv !== undefined) {
- process.env.NODE_ENV = saveEnv;
- } else {
- delete process.env.NODE_ENV;
- }
- });
-
- afterEach(() => {
- process.chdir(cwd);
- });
-
- describe("loadElectrodeDllAssets", function() {
- it("should return empty if unable to load asset data", () => {
- expect(content.loadElectrodeDllAssets()).to.deep.equal({});
- expect(content.loadElectrodeDllAssets({})).to.deep.equal({});
- expect(content.loadElectrodeDllAssets({ electrodeDllAssetsPath: "blahblah" })).to.deep.equal(
- {}
- );
- });
-
- it("should return load and return asset data", () => {
- expect(
- content.loadElectrodeDllAssets({ electrodeDllAssetsPath: "test/data/test-dll-assets.json" })
- ).to.deep.equal({ foo: { bar: [1] } });
- });
-
- it("should load default asset data for dev mode", () => {
- process.env.NODE_ENV = "";
- process.chdir(Path.join(__dirname, "../../data"));
- expect(content.loadElectrodeDllAssets({})).to.deep.equal({ production: false });
- });
-
- it("should load default asset data for prod mode", () => {
- process.env.NODE_ENV = "production";
- process.chdir(Path.join(__dirname, "../../data"));
- expect(content.loadElectrodeDllAssets({})).to.deep.equal({ production: true });
- });
- });
-
- describe("makeElectrodeDllScripts", function() {
- it("should return empty string for empty asset", () => {
- expect(content.makeElectrodeDllScripts({})).to.equal("");
- });
-
- it("should return scripts for DLL asset in cdnMapping", () => {
- const script = content.makeElectrodeDllScripts({
- foo: {
- cdnMapping: {
- a: "test-a.js",
- b: "test-b.js"
- }
- }
- });
-
- console.log(script);
- expect(script).to.equal(`
-`);
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/react/handlers/prefetch-bundles.spec.js b/packages/electrode-react-webapp/test/spec/react/handlers/prefetch-bundles.spec.js
deleted file mode 100644
index a5be8b32b..000000000
--- a/packages/electrode-react-webapp/test/spec/react/handlers/prefetch-bundles.spec.js
+++ /dev/null
@@ -1,23 +0,0 @@
-"use strict";
-
-const handler = require("../../../../lib/react/handlers/prefetch-bundles");
-
-describe("prefetch bundles handler", function() {
- it("should return empty string if no prefetch in content", () => {
- expect(handler({ user: { content: {} } })).to.equal("");
- });
-
- it("should return "
- );
- });
-
- it("should not return " } }
- })
- ).to.equal("");
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/render-context.spec.js b/packages/electrode-react-webapp/test/spec/render-context.spec.js
deleted file mode 100644
index 886183d1e..000000000
--- a/packages/electrode-react-webapp/test/spec/render-context.spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-"use strict";
-
-const Path = require("path");
-const AsyncTemplate = require("../../lib/async-template");
-const RenderContext = require("../../lib/render-context");
-const xaa = require("xaa");
-const xstdout = require("xstdout");
-
-const expect = require("chai").expect;
-
-describe("render-context", function() {
- it("should handle setting all stop modes", () => {
- const context = new RenderContext({}, {});
- context.stop = RenderContext.FULL_STOP;
- expect(context.isFullStop).to.equal(true);
- context.softStop();
- expect(context.isSoftStop).to.equal(true);
- context.voidStop();
- expect(context.isVoidStop).to.equal(true);
- context.fullStop();
- expect(context.isFullStop).to.equal(true);
- });
-
- it("should render template with all token types", () => {
- const htmlFile = Path.resolve("test/fixtures/test-render-context.html");
- let internalHandler = {};
- let internalTokens = {};
- let receivedResult = "";
- const send = x => {
- receivedResult += x;
- };
- const errors = [];
- const asyncTemplate = new AsyncTemplate({
- htmlFile,
- tokenHandlers: {
- name: "internal-test-handler",
- beforeRender: context => {
- context.setOutputSend(send);
- internalTokens = context.getTokens("internal-test-handler");
- context.handleError = err => errors.push(err);
- },
- afterRender: context => {
- internalHandler = context.getTokenHandler("internal-test-handler");
- },
- tokens: {
- INITIALIZE: "",
- "internal-test": () => `\nbuilt-in for internal-test`,
- "non-func-token": "\ntest non-func token"
- }
- }
- });
- asyncTemplate.initializeRenderer();
-
- const expected = `
-from wants next module
-from async ok module
-from async error module
-from string only module
-built-in for internal-test
-test non-func token
-from async error module
-from wants next module
-from string only module
-from async ok module`;
- const intercept = xstdout.intercept(false);
- return xaa
- .wrap(() => asyncTemplate.render({}))
- .then(context => {
- intercept.restore();
- expect(
- internalHandler.name,
- "lookup internal-test-handler with context.getTokenHandler failed"
- ).to.equal("internal-test-handler");
- expect(internalTokens).to.have.property("internal-test");
- expect(errors).to.deep.equal([
- "error from test/fixtures/async-error",
- "error from test/fixtures/async-error"
- ]);
- expect(context.result).to.equal("");
- expect(receivedResult).to.equal(expected);
- })
- .catch(err => {
- intercept.restore();
- throw err;
- });
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/render-output.spec.js b/packages/electrode-react-webapp/test/spec/render-output.spec.js
deleted file mode 100644
index 2fbd0a247..000000000
--- a/packages/electrode-react-webapp/test/spec/render-output.spec.js
+++ /dev/null
@@ -1,202 +0,0 @@
-"use strict";
-
-const RenderOutput = require("../../lib/render-output");
-const Munchy = require("munchy");
-const streamToArray = require("stream-to-array");
-
-const expect = require("chai").expect;
-
-describe("render-output", function() {
- it("should flush simple string", () => {
- let text;
- const context = {
- send: x => (text = x)
- };
- const ro = new RenderOutput(context);
- ro.add("hello world");
- ro.flush();
- expect(text).to.equal("hello world");
- ro.flush();
- expect(text).to.equal("hello world");
- });
-
- it("should flush multiple strings", () => {
- let text;
- const context = {
- send: x => (text = x)
- };
-
- const ro = new RenderOutput(context);
- ro.add("hello world");
- ro.add("foo bar");
- ro.flush();
- expect(text).to.equal("hello worldfoo bar");
- });
-
- const testFlushPending = (ro, context) => {
- ro.add("hello world");
- ro.add("foo bar");
- const spot = ro.reserve();
- ro.add("after pending");
- ro.add("baz");
- ro.flush();
- expect(context.text).to.equal(undefined);
- spot.add("123");
- spot.add("456");
- spot.close();
- expect(context.text).to.equal("hello worldfoo bar123456after pendingbaz");
- };
-
- it("should wait on flush when there's pending", () => {
- const context = {
- text: undefined
- };
- context.send = x => (context.text = x);
- const ro = new RenderOutput(context);
- testFlushPending(ro, context);
- });
-
- it("should continue output after flush", () => {
- const context = {
- text: undefined
- };
- context.send = x => (context.text = x);
- const ro = new RenderOutput(context);
- testFlushPending(ro, context);
- context.text = undefined;
- testFlushPending(ro, context);
- });
-
- it("should handle multiple spots", () => {
- let text = "";
- const context = {
- send: x => (text += x)
- };
- const ro = new RenderOutput(context);
- ro.add("hello world");
- ro.add("foo bar");
- const spot1 = ro.reserve();
- ro.add("after spot1");
- spot1.add("spot1 123");
- ro.add("baz1");
- ro.flush();
- expect(text).to.equal("");
- const spot2 = ro.reserve();
- spot2.add("spot2 123");
- spot2.add("456");
- spot2.close();
- expect(text).to.equal("");
- spot1.add("spot1 abc");
- spot1.add("789");
- ro.add("closing");
- spot1.close();
- ro.flush();
- expect(text).to.equal(
- "hello worldfoo barspot1 123spot1 abc789after spot1baz1spot2 123456closing"
- );
- });
-
- it("should handle multiple buffer and stream data", done => {
- const context = {
- munchy: new Munchy(),
- transform: a => a
- };
-
- streamToArray(context.munchy, (err, arr) => {
- if (err) return done(err);
- try {
- expect(arr.map(x => x.toString())).to.deep.equal([
- "hello world",
- "foo bar",
- "spot1 123",
- "spot1 abc",
- "spot1 a stream",
- "789",
- "after spot1",
- "baz1",
- "spot2 123",
- "spot2 456",
- "spot2 a buffer",
- "closing"
- ]);
- return done();
- } catch (err2) {
- return done(err2);
- }
- });
-
- const ro = new RenderOutput(context);
- ro.add("hello world");
- ro.add("foo bar");
- const spot1 = ro.reserve();
- ro.add("after spot1");
- spot1.add("spot1 123");
- ro.add("baz1");
- ro.flush();
- const spot2 = ro.reserve();
- spot2.add("spot2 123");
- spot2.add("spot2 456");
- spot2.add(Buffer.from("spot2 a buffer"));
- spot2.close();
- spot1.add("spot1 abc");
- spot1.add(new Munchy({}, "spot1 a stream", null));
- spot1.add("789");
- ro.add("closing");
- spot1.close();
- ro.close();
- });
-
- it("should delegate result to a promise w/o context and send", () => {
- const ro = new RenderOutput();
- ro.add("hello world");
- ro.add("foo bar");
- const spot1 = ro.reserve();
- ro.add("after spot1");
- spot1.add("spot1 123");
- ro.add("baz1");
- ro.flush();
- expect(ro._result).to.equal("");
- const spot2 = ro.reserve();
- spot2.add("spot2 123");
- spot2.add("456");
- spot2.close();
- expect(ro._result).to.equal("");
- spot1.add("spot1 abc");
- spot1.add("789");
- ro.add("closing");
- spot1.close();
- return ro.close().then(result => {
- expect(result).to.equal(
- "hello worldfoo barspot1 123spot1 abc789after spot1baz1spot2 123456closing"
- );
- });
- });
-
- it("should not munch if no items", done => {
- const ro = new RenderOutput();
- ro._output.sendToMunchy(null, done);
- });
-
- it("should rethrow if no _reject is available in _finish", () => {
- const ro = new RenderOutput();
- ro._reject = undefined;
- ro._resolve = () => {
- throw new Error("test error");
- };
- expect(() => ro._finish()).to.throw("test error");
- });
-
- it("should throw if can't stringify an item", () => {
- const ro = new RenderOutput();
- ro.add({});
- expect(() => ro.flush()).to.throw("unable to stringify item of type Object");
- });
-
- it("should throw if can't stringify an item without constructor", () => {
- const ro = new RenderOutput();
- const item = {};
- item.constructor = false;
- ro.add(item);
- expect(() => ro.flush()).to.throw("unable to stringify item of type object");
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/token.spec.js b/packages/electrode-react-webapp/test/spec/token.spec.js
deleted file mode 100644
index 06adb4ac6..000000000
--- a/packages/electrode-react-webapp/test/spec/token.spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-"use strict";
-
-const Token = require("../../lib/token");
-const expect = require("chai").expect;
-const xstdout = require("xstdout");
-const { TOKEN_HANDLER } = require("../../lib/symbols");
-
-describe("token", function() {
- it("should create token as internal", () => {
- const tk = new Token("test", 50);
- expect(tk.id).to.equal("test");
- expect(tk.isModule).to.equal(false);
- expect(tk.pos).to.equal(50);
- tk.load();
- expect(tk.custom).to.equal(undefined);
- });
-
- it("should invoke _call of a module", () => {
- const tk = new Token("#./test/fixtures/custom-call", 0, { _call: "setup" });
- expect(tk.id).to.equal("#./test/fixtures/custom-call");
- expect(tk.isModule).to.equal(true);
- tk.load();
- const promise = tk[TOKEN_HANDLER]();
- expect(promise).to.exist;
- return promise.then(r => {
- expect(r).to.equal("_call process from custom-call token fixture");
- });
- });
-
- it("should create token as custom and call setup only once for each token", () => {
- const tk1 = new Token("#./test/fixtures/custom-count");
- expect(tk1.id).to.equal("#./test/fixtures/custom-count");
- expect(tk1.isModule).to.equal(true);
- tk1.load();
- expect(tk1[TOKEN_HANDLER]()).to.equal("1");
- tk1.load(); // test re-entry
- expect(tk1[TOKEN_HANDLER]()).to.equal("1");
- const tk2 = new Token("#./test/fixtures/custom-count");
- expect(tk2.id).to.equal("#./test/fixtures/custom-count");
- expect(tk2.isModule).to.equal(true);
- tk2.load();
- expect(tk2[TOKEN_HANDLER]()).to.equal("2");
- });
-
- it("should handle custom module not found", () => {
- const tk = new Token("#./test/fixtures/not-found");
- expect(tk.id).to.equal("#./test/fixtures/not-found");
- expect(tk.isModule).to.equal(true);
- const intercept = xstdout.intercept(true);
- tk.load();
- intercept.restore();
- expect(tk[TOKEN_HANDLER]()).to.equal(
- "\ntoken process module ./test/fixtures/not-found not found\n"
- );
- });
-
- it("should handle custom module load failure", () => {
- const tk = new Token("#./test/fixtures/custom-fail");
- expect(tk.id).to.equal("#./test/fixtures/custom-fail");
- expect(tk.isModule).to.equal(true);
- const intercept = xstdout.intercept(true);
- tk.load();
- intercept.restore();
- expect(tk[TOKEN_HANDLER]()).to.equal(
- "\ntoken process module ./test/fixtures/custom-fail failed to load\n"
- );
- });
-
- it("should handle custom module returning null", () => {
- const tk = new Token("#./test/fixtures/custom-null");
- expect(tk.id).to.equal("#./test/fixtures/custom-null");
- expect(tk.isModule).to.equal(true);
- expect(tk.custom).to.equal(undefined);
- tk.load();
- expect(tk.custom).to.equal(null);
- });
-});
diff --git a/packages/electrode-react-webapp/test/spec/utils.spec.js b/packages/electrode-react-webapp/test/spec/utils.spec.js
deleted file mode 100644
index a98d7e3b2..000000000
--- a/packages/electrode-react-webapp/test/spec/utils.spec.js
+++ /dev/null
@@ -1,359 +0,0 @@
-"use strict";
-
-const expect = require("chai").expect;
-const Fs = require("fs");
-const utils = require("../../lib/utils");
-const Path = require("path");
-const sinon = require("sinon");
-
-describe("utils", function() {
- it("getIconStats should return stats w/o html as is", () => {
- const x = utils.getIconStats("test/data/icon-stats-empty.json");
- expect(x).to.deep.equal({ empty: true });
- });
-
- it("getStatsPath should return diff path with webpack dev", () => {
- const x = utils.getStatsPath("dist/stats.json", "build");
- expect(x).to.equal("dist/stats.json");
- process.env.WEBPACK_DEV = "true";
- const x2 = utils.getStatsPath("dist/stats.json", "build");
- expect(x2).to.equal(Path.resolve("build", "stats.json"));
- delete process.env.WEBPACK_DEV;
- });
-
- describe("htmlifyError", function() {
- let save;
- beforeEach(() => {
- if (process.env.hasOwnProperty("NODE_ENV")) {
- save = process.env.NODE_ENV;
- }
- });
-
- afterEach(() => {
- delete process.env.NODE_ENV;
- if (save !== undefined) {
- process.env.NODE_ENV = save;
- save = undefined;
- }
- });
-
- it("should return doc with err.html and err.stack", () => {
- const err = new Error("test1");
- err.html = "foo bar";
- const r = utils.htmlifyError(err);
- expect(r).contains("foo bar");
- expect(r).contains("/test/spec/utils.spec.js");
- });
-
- it("should return err.message if err.stack is not avail somehow", () => {
- const err = { message: "hello world" };
- const r = utils.htmlifyError(err);
- expect(r).contains("hello world");
- });
-
- it("should return doc w/o err.stack in production", () => {
- const err = new Error("test1");
- err.html = "foo bar";
- process.env.NODE_ENV = "production";
- const r = utils.htmlifyError(err);
- expect(r).contains("foo bar");
- expect(r).to.not.contains("/test/spec/utils.spec.js");
- });
-
- it("should return doc w/o err.stack if withStack is false", () => {
- const err = new Error("test1");
- err.html = "foo bar";
- process.env.NODE_ENV = "development";
- const r = utils.htmlifyError(err, false);
- expect(r).contains("foo bar");
- expect(r).to.not.contains("/test/spec/utils.spec.js");
- });
- });
-
- describe("getCspNonce", () => {
- it("should get no CSP nonce if option is not defined", () => {
- const nonce = utils.getCspNonce(
- {
- app: {
- scriptCsp: "csp-script",
- styleCsp: "csp-style"
- }
- },
- null
- );
- expect(nonce).to.deep.equal({
- scriptNonce: ``,
- styleNonce: ``
- });
- });
-
- it("should call function with request to get CSP nonce", () => {
- const nonce = utils.getCspNonce({}, (request, tag) => {
- if (tag === "script") return "csp-script";
- if (tag === "style") return "csp-style";
- return "";
- });
- expect(nonce).to.deep.equal({
- scriptNonce: ` nonce="csp-script"`,
- styleNonce: ` nonce="csp-style"`
- });
- });
-
- it("should get CSP nonce from request base on option path", () => {
- const nonce = utils.getCspNonce(
- {
- app: {
- scriptCsp: "csp-script",
- styleCsp: "csp-style"
- }
- },
- {
- script: "app.scriptCsp",
- style: "app.styleCsp"
- }
- );
- expect(nonce).to.deep.equal({
- scriptNonce: ` nonce="csp-script"`,
- styleNonce: ` nonce="csp-style"`
- });
- });
-
- it("should get no CSP nonce if no value can be retrieved", () => {
- const nonce = utils.getCspNonce(
- {
- app: {}
- },
- {
- script: "app.scriptCsp",
- style: "app.styleCsp"
- }
- );
- expect(nonce).to.deep.equal({
- scriptNonce: ``,
- styleNonce: ``
- });
- });
- });
-
- describe("getCriticalCSS", () => {
- it("should return empty string if loading failed", () => {
- const x = utils.getCriticalCSS("blah");
- expect(x).to.equal("");
- });
-
- it("should load CSS from a file", () => {
- const x = utils.getCriticalCSS("test/data/critical.css");
- expect(x).to.equal(`body {color: green;}
-`);
- });
- });
-
- describe("processRenderSsMode", () => {
- it("should return false for renderSs option being false", () => {
- expect(utils.processRenderSsMode({}, false, "")).to.equal(false);
- });
-
- it("should return false for renderSs mode being noss", () => {
- expect(utils.processRenderSsMode({}, true, "noss")).to.equal(false);
- });
-
- it("should return datass for renderSs and set ssrPrefetchOnly flat in request", () => {
- const request = {};
- expect(utils.processRenderSsMode(request, "datass", "")).to.equal("datass");
- expect(request.app.ssrPrefetchOnly).to.equal(true);
- });
-
- it("should return datass for mode and set ssrPrefetchOnly flat in request", () => {
- const request = {};
- expect(utils.processRenderSsMode(request, true, "datass")).to.equal("datass");
- expect(request.app.ssrPrefetchOnly).to.equal(true);
- });
- });
-
- describe("invokeTemplateProcessor", () => {
- it("should execute templateProcessor function directly", () => {
- let resA;
- let resB;
- const templateProcessor = (a, b) => {
- resA = a;
- resB = b;
- };
-
- const asyncTemplate = {};
- const options = { templateProcessor };
-
- utils.invokeTemplateProcessor(asyncTemplate, options);
- expect(resA).to.equal(asyncTemplate);
- expect(resB).to.equal(options);
- });
-
- it("should throw if templateProcessor is not a function", () => {
- const asyncTemplate = {};
- const options = { templateProcessor: true };
-
- expect(() => utils.invokeTemplateProcessor(asyncTemplate, options)).to.throw(
- "is not a function"
- );
- });
-
- it("should load function exported from module", () => {
- const asyncTemplate = {};
- const options = { templateProcessor: "./test/fixtures/template-processor-1" };
-
- expect(utils.invokeTemplateProcessor(asyncTemplate, options)).to.equal(
- "template-processor-1"
- );
- });
-
- it("should load defined function exported from module", () => {
- const asyncTemplate = {};
- const options = { templateProcessor: "./test/fixtures/template-processor-2" };
-
- expect(utils.invokeTemplateProcessor(asyncTemplate, options)).to.equal(
- "template-processor-2"
- );
- });
-
- it("should throw if module doesn't export usable function", () => {
- const asyncTemplate = {};
- const options = { templateProcessor: "./test/fixtures/template-processor-3" };
-
- expect(() => utils.invokeTemplateProcessor(asyncTemplate, options)).to.throw(
- "doesn't export a usable function"
- );
- });
- });
-
- describe("getOtherStats", () => {
- it("should require stats file if dist/server exists", () => {
- const fakeExistsSync = sinon.stub(Fs, "existsSync").callsFake(() => true);
- const fakeReaddirSync = sinon
- .stub(Fs, "readdirSync")
- .callsFake(() => [Path.resolve("es5-stats.json"), Path.resolve("es6-stats.json")]);
- const otherStats = utils.getOtherStats();
- fakeExistsSync.restore();
- fakeReaddirSync.restore();
- const keys = Object.keys(otherStats);
- expect(keys.includes("es5")).be.true;
- expect(keys.includes("es6")).be.true;
- });
- });
-
- describe("getOtherAssets", () => {
- it("should generate otherAssets if otherStats is not empty", () => {
- const otherStats = {
- es5: Path.resolve("es5-stats.json"),
- es6: Path.resolve("es6-stats.json")
- };
- const buildArtifacts = ".build";
- const pluginOptions = { otherStats, buildArtifacts };
- const otherAssets = utils.getOtherAssets(pluginOptions, utils.loadAssetsFromStats);
- const keys = Object.keys(otherAssets);
- expect(keys.includes("es5")).be.true;
- expect(keys.includes("es6")).be.true;
- });
- });
-
- describe("getBundleJsNameByQuery", () => {
- it("should get file name ends with main.bundle.js", () => {
- const data = {
- jsChunk: { name: "default.main.bundle.js" }
- };
- const otherAssets = {
- es6: { js: [{ name: "es6.main.bundle.js" }] }
- };
- const es6 = utils.getBundleJsNameByQuery(
- Object.assign(data, {
- query: { __dist: "es6" }
- }),
- otherAssets
- );
- expect(es6).to.equal(otherAssets.es6.js[0].name);
- const es5 = utils.getBundleJsNameByQuery(
- Object.assign(data, {
- query: { __dist: "es5" }
- }),
- otherAssets
- );
- expect(es5).to.equal(data.jsChunk.name);
- });
- });
-
- describe("munchyHandleStreamError", () => {
- it("should return error with stacks", () => {
- const output = utils.munchyHandleStreamError(new Error("blah blah"));
- expect(output.result).contains("Error: blah blah");
- expect(output.result).contains("test/spec/utils.spec.js:");
- expect(output.result).contains("CWD/");
- expect(output.remit).to.equal(false);
- });
-
- it("should not replace cwd shorter than 4 chars", () => {
- const save = process.cwd();
- process.chdir("/");
- const output = utils.munchyHandleStreamError(new Error("blah blah"));
- expect(output.result).contains("Error: blah blah");
- expect(output.result).contains("test/spec/utils.spec.js:");
- expect(output.result).not.contains("CWD/");
- expect(output.remit).to.equal(false);
- process.chdir(save);
- });
-
- it("should return error without stacks in production", () => {
- const save = process.env.NODE_ENV;
- process.env.NODE_ENV = "production";
- const output = utils.munchyHandleStreamError(new Error());
- expect(output.result).not.contains("test/spec/utils.spec.js:");
- expect(output.remit).to.equal(false);
- if (save) {
- process.env.NODE_ENV = save;
- }
- });
- });
-
- describe("makeDevBundleBase", () => {
- beforeEach(() => {
- delete process.env.WEBPACK_DEV_CDN_PROTOCOL;
- delete process.env.WEBPACK_DEV_CDN_HOSTNAME;
- delete process.env.WEBPACK_DEV_CDN_PORT;
- delete process.env.APP_SERVER_PORT;
- });
-
- it("should use WEBPACK_DEV_CDN_HOSTNAME env variables", () => {
- process.env.WEBPACK_DEV_CDN_HOSTNAME = "testhost";
- const baseUrl = utils.makeDevBundleBase();
- expect(baseUrl).to.equal("http://testhost/js/");
- });
-
- it("should use WEBPACK_DEV_CDN_PROTOCOL env variables", () => {
- process.env.WEBPACK_DEV_CDN_PROTOCOL = "https";
- const baseUrl = utils.makeDevBundleBase();
- expect(baseUrl).to.equal("https://localhost/js/");
- });
-
- it("should use WEBPACK_DEV_CDN_PORT env variables", () => {
- process.env.WEBPACK_DEV_CDN_PORT = "8080";
- const baseUrl = utils.makeDevBundleBase();
- expect(baseUrl).to.equal("http://localhost:8080/js/");
- });
-
- it("should ignore WEBPACK_DEV_CDN_PORT env variables if it's 80", () => {
- process.env.WEBPACK_DEV_CDN_PORT = "80";
- const baseUrl = utils.makeDevBundleBase();
- expect(baseUrl).to.equal("http://localhost/js/");
- });
-
- it("should check process.env.APP_SERVER_PORT", () => {
- process.env.APP_SERVER_PORT = "8080";
- const baseUrl = utils.makeDevBundleBase();
- expect(baseUrl).to.equal("/js/");
- });
- });
-
- describe("getProdBundles", function() {
- it("should return empty object if no route data or assets", () => {
- expect(utils.getProdBundles()).to.deep.equal({});
- expect(utils.getProdBundles("", {})).to.deep.equal({});
- });
- });
-});
diff --git a/packages/electrode-react-webapp/xclap.js b/packages/electrode-react-webapp/xclap.js
deleted file mode 100644
index ea371779c..000000000
--- a/packages/electrode-react-webapp/xclap.js
+++ /dev/null
@@ -1 +0,0 @@
-require("electrode-archetype-njs-module-dev")();