Skip to content

Commit

Permalink
add tests for subapp-react (#1486)
Browse files Browse the repository at this point in the history
* 1

* 2

* 3

* 4

* 5
  • Loading branch information
jchip authored Jan 5, 2020
1 parent 2553c95 commit 6aac430
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 7 deletions.
3 changes: 2 additions & 1 deletion packages/subapp-react/lib/framework-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ class FrameworkLib {
assert(Provider, "subapp-web: react-redux Provider not available");
// finally render the element with Redux Provider and the store created
return await this.renderTo(
React.createElement(Provider, { store: this.store }, this.createTopComponent())
React.createElement(Provider, { store: this.store }, this.createTopComponent()),
options
);
}
return "";
Expand Down
12 changes: 7 additions & 5 deletions packages/subapp-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@
"@babel/register": "^7.7.7",
"babel-preset-minify": "^0.5.1",
"electrode-archetype-njs-module-dev": "^3.0.0",
"jsdom": "^15.2.1",
"react": "^16.8.3",
"react-async-ssr": "^0.6.0",
"react-dom": "^16.8.3",
"react-redux": "^6.0.1",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"redux": "^4.0.1"
"redux": "^4.0.1",
"run-verify": "^1.2.2"
},
"peerDependencies": {
"react": "*",
Expand Down Expand Up @@ -78,10 +80,10 @@
"**/.babelrc.js"
],
"check-coverage": true,
"statements": 0,
"branches": 0,
"functions": 0,
"lines": 0,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100,
"cache": true
}
}
1 change: 0 additions & 1 deletion packages/subapp-react/src/fe-framework-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class FrameworkLib {

const props = { ...options._prepared, ...options.props };
const Component = subApp.info.StartComponent || subApp.info.Component;

if (element) {
if (options.serverSideRendering) {
hydrate(<Component {...props} />, element);
Expand Down
2 changes: 2 additions & 0 deletions packages/subapp-react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export * from "subapp-web";
export { default as React } from "react";

export { default as AppContext } from "./app-context";

export { FrameworkLib };
62 changes: 62 additions & 0 deletions packages/subapp-react/test/spec/fe-framework.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use strict";

const React = require("react"); // eslint-disable-line
const feLib = require("../../src");
const { JSDOM } = require("jsdom");

describe("FE React framework", function() {
//
it("should setup FrameworkLib", () => {
expect(feLib.React).to.be.ok;
expect(feLib.AppContext).to.be.ok;
expect(feLib.loadSubApp).to.be.a("function");
expect(feLib.FrameworkLib).to.be.ok;
});

it("should render component into DOM element", () => {
const dom = new JSDOM(`<div id="test"></div>`);
global.window = dom.window;
const element = dom.window.document.getElementById("test");
const framework = new feLib.FrameworkLib({
subApp: {
info: {
Component: props => <p>hello {props.foo}</p>
}
},
element,
options: { props: { foo: "bar" } }
});
framework.renderStart();
expect(element.innerHTML).equals(`<p>hello bar</p>`);
});

it("should hydrate render component into DOM element", () => {
const dom = new JSDOM(`<div id="test"><p>hello <!-- -->bar</p></div>`);
global.window = dom.window;
const element = dom.window.document.getElementById("test");
const framework = new feLib.FrameworkLib({
subApp: {
info: {
Component: props => <p>hello {props.foo}</p>
}
},
element,
options: { props: { foo: "bar" }, serverSideRendering: true }
});
framework.renderStart();
expect(element.innerHTML).equals(`<p>hello <!-- -->bar</p>`);
});

it("should just return the component without DOM element", () => {
const Component = props => <p>hello {props.foo}</p>;

const framework = new feLib.FrameworkLib({
subApp: {
info: { Component }
},
options: { props: { foo: "bar" }, serverSideRendering: true }
});
const c = framework.renderStart();
expect(c.type).equals(Component);
});
});
198 changes: 198 additions & 0 deletions packages/subapp-react/test/spec/ssr-framework.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const React = require("react"); // eslint-disable-line
const lib = require("../../lib");
const { withRouter } = require("react-router");
const { Route, Switch } = require("react-router-dom"); // eslint-disable-line
const { asyncVerify } = require("run-verify");
const Redux = require("redux");
const { connect } = require("react-redux");

describe("SSR React framework", function() {
it("should setup React framework", () => {
Expand All @@ -24,6 +27,16 @@ describe("SSR React framework", function() {
expect(res).contains("has no StartComponent");
});

it("should not do SSR if serverSideRendering is not true", async () => {
const framework = new lib.FrameworkLib({
subApp: { Component: () => {} },
subAppServer: {},
options: { serverSideRendering: false }
});
const res = await framework.handleSSR();
expect(res).equals("");
});

it("should render subapp with w/o initial props if no prepare provided", async () => {
const framework = new lib.FrameworkLib({
subApp: {
Expand Down Expand Up @@ -59,6 +72,84 @@ describe("SSR React framework", function() {
expect(res).contains("Hello foo bar");
});

it("should render Component with streaming if enabled", () => {
const framework = new lib.FrameworkLib({
subApp: {
prepare: () => ({ test: "foo bar" }),
Component: props => {
return <div>Hello {props.test}</div>;
}
},
subAppServer: {},
options: { serverSideRendering: true, streaming: true },
context: {
user: {}
}
});
return asyncVerify(
() => framework.handleSSR(),
(stream, next) => {
let res = "";
stream.on("data", data => (res += data.toString()));
stream.on("end", () => next(null, res));
stream.on("error", next);
},
res => expect(res).contains("Hello foo bar")
);
});

it("should hydrate render Component with streaming if enabled", () => {
const framework = new lib.FrameworkLib({
subApp: {
prepare: () => ({ test: "foo bar" }),
Component: props => {
return <div>Hello {props.test}</div>;
}
},
subAppServer: {},
options: { serverSideRendering: true, streaming: true, hydrateServerData: true },
context: {
user: {}
}
});
return asyncVerify(
() => framework.handleSSR(),
(stream, next) => {
let res = "";
stream.on("data", data => (res += data.toString()));
stream.on("end", () => next(null, res));
stream.on("error", next);
},
res => expect(res).contains(`<div>Hello <!-- -->foo bar</div>`)
);
});

it("should render Component from subapp with hydration info", async () => {
const framework = new lib.FrameworkLib({
subApp: {
prepare: () => ({
test: "foo bar"
}),
Component: props => {
return <div>Hello {props.test}</div>;
}
},
subAppServer: {},
options: {
serverSideRendering: true,
hydrateServerData: true
},
context: {
user: {}
}
});
// data-reactroot isn't getting created due to Context.Provider
// see https://github.com/facebook/react/issues/15012
const res = await framework.handleSSR();
// but the non-static renderToString adds a <!-- --> for some reason
expect(res).contains("Hello <!-- -->foo bar");
});

it("should render Component from subapp with initial props from server's prepare", async () => {
const framework = new lib.FrameworkLib({
subApp: {
Expand All @@ -78,6 +169,113 @@ describe("SSR React framework", function() {
expect(res).contains("Hello foo bar");
});

it("should init redux store and render Component", async () => {
const Component = connect(x => x)(props => <div>Hello {props.test}</div>);

const framework = new lib.FrameworkLib({
subApp: {
__redux: true,
Component,
reduxCreateStore: initState => Redux.createStore(x => x, initState),
prepare: () => ({ test: "foo bar" })
},
subAppServer: {},
options: { serverSideRendering: true },
context: {
user: {}
}
});
const res = await framework.handleSSR();
expect(res).contains("Hello foo bar");
expect(framework.initialStateStr).equals(`{"test":"foo bar"}`);
});

it("should init redux store and render Component but doesn't attach initial state", async () => {
const Component = connect(x => x)(props => <div>Hello {props.test}</div>);

const framework = new lib.FrameworkLib({
subApp: {
__redux: true,
Component,
reduxCreateStore: initState => Redux.createStore(x => x, initState),
prepare: () => ({ test: "foo bar" })
},
subAppServer: { attachInitialState: false },
options: { serverSideRendering: true },
context: {
user: {}
}
});
const res = await framework.handleSSR();
expect(res).contains("Hello foo bar");
expect(framework.initialStateStr).equals(undefined);
});

it("should init redux store but doesn't render Component if serverSideRendering is not true", async () => {
const Component = connect(x => x)(props => <div>Hello {props.test}</div>);

const framework = new lib.FrameworkLib({
subApp: {
__redux: true,
Component,
reduxCreateStore: initState => Redux.createStore(x => x, initState),
prepare: () => ({ test: "foo bar" })
},
subAppServer: { attachInitialState: false },
options: { serverSideRendering: false },
context: {
user: {}
}
});
const res = await framework.handleSSR();
expect(res).equals("");
expect(framework.initialStateStr).equals(undefined);
});

it("should init redux store with empty state without prepare and render Component", async () => {
const Component = connect(x => x)(props => <div>Hello {props.test}</div>);

const framework = new lib.FrameworkLib({
subApp: {
__redux: true,
Component,
reduxCreateStore: initState => Redux.createStore(x => x, initState)
},
subAppServer: {},
options: { serverSideRendering: true },
context: {
user: {}
}
});
const res = await framework.handleSSR();
expect(res).contains("Hello <");
expect(framework.initialStateStr).equals(`{}`);
});

it("should hydrate render Component with suspense using react-async-ssr", async () => {
const framework = new lib.FrameworkLib({
subApp: {
Component: props => {
return (
<React.Suspense fallback={<h1>Loading...</h1>}>
<div>Hello {props.test}</div>
</React.Suspense>
);
}
},
subAppServer: {
prepare: () => ({ test: "foo bar" })
},
options: { serverSideRendering: true, suspenseSsr: true, hydrateServerData: true },
context: {
user: {}
}
});
const res = await framework.handleSSR();
// react-async-ssr includes data-reactroot
expect(res).contains(`<div data-reactroot="">Hello <!-- -->foo bar</div>`);
});

it("should render Component with suspense using react-async-ssr", async () => {
const framework = new lib.FrameworkLib({
subApp: {
Expand Down

0 comments on commit 6aac430

Please sign in to comment.