added DOM tests for client library

This commit is contained in:
Michael Shanks 2020-01-24 13:18:31 +00:00
parent c19b3febde
commit 994aed6f5d
6 changed files with 299 additions and 4 deletions

View File

@ -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",

View File

@ -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
}); });

View File

@ -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;
}

View File

@ -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");
});
});

View File

@ -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");
});
});

View File

@ -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);
}
});