added DOM tests for client library
This commit is contained in:
parent
c19b3febde
commit
994aed6f5d
|
@ -48,6 +48,7 @@
|
||||||
"babel-jest": "^24.8.0",
|
"babel-jest": "^24.8.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"jest": "^24.8.0",
|
"jest": "^24.8.0",
|
||||||
|
"jsdom": "^16.0.1",
|
||||||
"rollup": "^1.12.0",
|
"rollup": "^1.12.0",
|
||||||
"rollup-plugin-commonjs": "^10.0.0",
|
"rollup-plugin-commonjs": "^10.0.0",
|
||||||
"rollup-plugin-node-builtins": "^2.1.2",
|
"rollup-plugin-node-builtins": "^2.1.2",
|
||||||
|
|
|
@ -19,6 +19,12 @@ export const createApp = (componentLibraries, appDefinition, user) => {
|
||||||
|
|
||||||
const childComponents = [];
|
const childComponents = [];
|
||||||
|
|
||||||
|
if(hydrate) {
|
||||||
|
while (htmlElement.firstChild) {
|
||||||
|
htmlElement.removeChild(htmlElement.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(let childProps of childrenProps) {
|
for(let childProps of childrenProps) {
|
||||||
const {componentName, libName} = splitName(childProps._component);
|
const {componentName, libName} = splitName(childProps._component);
|
||||||
|
|
||||||
|
@ -37,7 +43,7 @@ export const createApp = (componentLibraries, appDefinition, user) => {
|
||||||
const component = new (componentLibraries[libName][componentName])({
|
const component = new (componentLibraries[libName][componentName])({
|
||||||
target: htmlElement,
|
target: htmlElement,
|
||||||
props: componentProps,
|
props: componentProps,
|
||||||
hydrate,
|
hydrate:false,
|
||||||
anchor
|
anchor
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createApp } from "./createApp";
|
import { createApp } from "./createApp";
|
||||||
import { trimSlash } from "./common/trimSlash";
|
import { trimSlash } from "./common/trimSlash";
|
||||||
|
|
||||||
export const loadBudibase = async (componentLibraries, props) => {
|
export const loadBudibase = async ({componentLibraries, props, window, localStorage}) => {
|
||||||
|
|
||||||
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
|
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
|
||||||
|
|
||||||
|
@ -36,8 +36,11 @@ export const loadBudibase = async (componentLibraries, props) => {
|
||||||
const _app = createApp(componentLibraries, appDefinition, user);
|
const _app = createApp(componentLibraries, appDefinition, user);
|
||||||
_app.hydrateChildren(
|
_app.hydrateChildren(
|
||||||
[props],
|
[props],
|
||||||
document.body);
|
window.document.body);
|
||||||
|
|
||||||
|
return _app;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.loadBudibase = loadBudibase;
|
if(window) {
|
||||||
|
window.loadBudibase = loadBudibase;
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
import { load } from "./testAppDef";
|
||||||
|
|
||||||
|
describe("initialiseApp", () => {
|
||||||
|
|
||||||
|
it("should populate root element prop from store value", async () => {
|
||||||
|
|
||||||
|
const {dom} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
className: {
|
||||||
|
"##bbstate": "divClassName",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"default"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
expect(rootDiv.className).toBe("default");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should update root element from store", async () => {
|
||||||
|
|
||||||
|
const {dom, app} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
className: {
|
||||||
|
"##bbstate": "divClassName",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"default"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.store.update(s => {
|
||||||
|
s.divClassName = "newvalue";
|
||||||
|
return s;
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
expect(rootDiv.className).toBe("newvalue");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should populate child component with store value", async () => {
|
||||||
|
const {dom} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: {
|
||||||
|
"##bbstate": "headerOneText",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"header one"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: {
|
||||||
|
"##bbstate": "headerTwoText",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"header two"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
|
||||||
|
expect(rootDiv.children.length).toBe(2);
|
||||||
|
expect(rootDiv.children[0].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[0].innerText).toBe("header one");
|
||||||
|
expect(rootDiv.children[1].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[1].innerText).toBe("header two");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should populate child component with store value", async () => {
|
||||||
|
const {dom, app} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: {
|
||||||
|
"##bbstate": "headerOneText",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"header one"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: {
|
||||||
|
"##bbstate": "headerTwoText",
|
||||||
|
"##bbsource": "store",
|
||||||
|
"##bbstatefallback":"header two"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
app.store.update(s => {
|
||||||
|
s.headerOneText = "header 1 - new val";
|
||||||
|
s.headerTwoText = "header 2 - new val";
|
||||||
|
return s;
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
|
||||||
|
expect(rootDiv.children.length).toBe(2);
|
||||||
|
expect(rootDiv.children[0].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[0].innerText).toBe("header 1 - new val");
|
||||||
|
expect(rootDiv.children[1].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[1].innerText).toBe("header 2 - new val");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { load } from "./testAppDef";
|
||||||
|
|
||||||
|
describe("initialiseApp", () => {
|
||||||
|
|
||||||
|
it("should populate simple div with initial props", async () => {
|
||||||
|
|
||||||
|
const {dom} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
className: "my-test-class"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(dom.window.document.body.children.length).toBe(1);
|
||||||
|
const child = dom.window.document.body.children[0];
|
||||||
|
expect(child.className).toBe("my-test-class");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should populate child component with props", async () => {
|
||||||
|
const {dom} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: "header one"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: "header two"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
|
||||||
|
expect(rootDiv.children.length).toBe(2);
|
||||||
|
expect(rootDiv.children[0].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[0].innerText).toBe("header one");
|
||||||
|
expect(rootDiv.children[1].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[1].innerText).toBe("header two");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should append children when told to do so", async () => {
|
||||||
|
const {dom} = await load({
|
||||||
|
_component: "testlib/div",
|
||||||
|
_children: [
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: "header one"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_component: "testlib/h1",
|
||||||
|
text: "header two"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
append: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const rootDiv = dom.window.document.body.children[0];
|
||||||
|
|
||||||
|
expect(rootDiv.children.length).toBe(3);
|
||||||
|
expect(rootDiv.children[0].tagName).toBe("DIV");
|
||||||
|
expect(rootDiv.children[0].className).toBe("default-child");
|
||||||
|
expect(rootDiv.children[1].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[1].innerText).toBe("header one");
|
||||||
|
expect(rootDiv.children[2].tagName).toBe("H1");
|
||||||
|
expect(rootDiv.children[2].innerText).toBe("header two");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { JSDOM } from "jsdom";
|
||||||
|
import { loadBudibase } from "../src/index";
|
||||||
|
|
||||||
|
export const load = async (props) => {
|
||||||
|
const dom = new JSDOM(`<!DOCTYPE html><html><body></body><html>`);
|
||||||
|
setAppDef(dom.window, props);
|
||||||
|
const app = await loadBudibase({
|
||||||
|
componentLibraries: allLibs(dom.window),
|
||||||
|
window: dom.window,
|
||||||
|
localStorage: createLocalStorage(),
|
||||||
|
props
|
||||||
|
});
|
||||||
|
return {dom, app};
|
||||||
|
}
|
||||||
|
|
||||||
|
const setAppDef = (window, props) => {
|
||||||
|
window["##BUDIBASE_APPDEFINITION##"] = ({
|
||||||
|
componentLibraries: [],
|
||||||
|
props,
|
||||||
|
hierarchy: {},
|
||||||
|
appRootPath: ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const allLibs = (window) => ({
|
||||||
|
testlib: maketestlib(window)
|
||||||
|
});
|
||||||
|
|
||||||
|
const createLocalStorage = () => {
|
||||||
|
const data = {};
|
||||||
|
return ({
|
||||||
|
getItem: key => data[key],
|
||||||
|
setItem: (key, value) => data[key] = value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const maketestlib = (window) => ({
|
||||||
|
div: function(opts) {
|
||||||
|
|
||||||
|
const node = window.document.createElement("DIV");
|
||||||
|
const defaultChild = window.document.createElement("DIV");
|
||||||
|
defaultChild.className = "default-child";
|
||||||
|
node.appendChild(defaultChild);
|
||||||
|
|
||||||
|
let currentProps = {...opts.props};
|
||||||
|
let childNodes = [];
|
||||||
|
|
||||||
|
const set = (props) => {
|
||||||
|
currentProps = Object.assign(currentProps, props);
|
||||||
|
node.className = currentProps.className || "";
|
||||||
|
if(currentProps._children && currentProps._children.length > 0) {
|
||||||
|
if(currentProps.append) {
|
||||||
|
for(let c of childNodes) {
|
||||||
|
node.removeChild(c);
|
||||||
|
}
|
||||||
|
const components = currentProps._bb.appendChildren(currentProps._children, node);
|
||||||
|
childNodes = components.map(c => c._element);
|
||||||
|
} else {
|
||||||
|
currentProps._bb.hydrateChildren(currentProps._children, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$set = set;
|
||||||
|
this._element = node;
|
||||||
|
set(opts.props);
|
||||||
|
opts.target.appendChild(node);
|
||||||
|
},
|
||||||
|
|
||||||
|
h1: function(opts) {
|
||||||
|
|
||||||
|
const node = window.document.createElement("H1");
|
||||||
|
|
||||||
|
let currentProps = {...opts.props};
|
||||||
|
|
||||||
|
const set = (props) => {
|
||||||
|
currentProps = Object.assign(currentProps, props);
|
||||||
|
if(currentProps.text) {
|
||||||
|
node.innerText = currentProps.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$set = set;
|
||||||
|
this._element = node;
|
||||||
|
set(opts.props);
|
||||||
|
opts.target.appendChild(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue