lightview 1.4.2-b → 1.4.4-b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # lightview v1.4.2b (BETA)
1
+ # lightview v1.4.4b (BETA)
2
2
 
3
3
  Small, simple, powerful web UI and micro front end creation ...
4
4
 
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ server: {
3
+ command: 'http-server'
4
+ }
5
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "moduleFileExtensions": ["mjs", "js", "jsx", "ts", "tsx", "json", "node"],
3
+ "testMatch": [
4
+ "**/?(*.)test.?js"
5
+ ],
6
+ "verbose": true,
7
+ "transform": {},
8
+ "testEnvironment": "jest-environment-node",
9
+ "globalSetup": "jest-environment-puppeteer/setup",
10
+ "globalTeardown": "jest-environment-puppeteer/teardown",
11
+ "testEnvironment": "jest-environment-puppeteer"
12
+ }
package/lightview.js CHANGED
@@ -30,8 +30,8 @@ const {observe} = (() => {
30
30
  let CURRENTOBSERVER;
31
31
  const parser = new DOMParser();
32
32
 
33
- const addListener = (node,eventName,callback) => {
34
- node.addEventListener(eventName,callback); // just used to make code footprint smaller
33
+ const addListener = (node, eventName, callback) => {
34
+ node.addEventListener(eventName, callback); // just used to make code footprint smaller
35
35
  }
36
36
  const anchorHandler = async (event) => {
37
37
  event.preventDefault();
@@ -93,9 +93,18 @@ const {observe} = (() => {
93
93
  if (isfunction) {
94
94
  const instance = toType === Date ? new Date() : Object.create(toType.prototype);
95
95
  if (instance instanceof Array) {
96
- const parsed = JSON.parse(value.startsWith("[") ? value : `[${value}]`);
97
- if (!Array.isArray(parsed)) throw new TypeError(`Expected an Array for parsed data`)
98
- parsed.forEach((item) => instance.push(item))
96
+ let parsed = tryParse(value.startsWith("[") ? value : `[${value}]`);
97
+ if (!Array.isArray(parsed)) {
98
+ if(value.includes(",")) parsed = value.split(",");
99
+ else {
100
+ parsed = tryParse(`["${value}"]`);
101
+ if(!Array.isArray(parsed) || parsed[0]!==value && parsed.length!==1) parsed = null;
102
+ }
103
+ }
104
+ if (!Array.isArray(parsed)) {
105
+ throw new TypeError(`Expected an Array for parsed data`)
106
+ }
107
+ instance.push(...parsed);
99
108
  } else if (instance instanceof Date) {
100
109
  instance.setTime(Date.parse(value));
101
110
  } else {
@@ -118,7 +127,7 @@ const {observe} = (() => {
118
127
  }
119
128
  throw new TypeError(`Unable to coerce ${value} to ${toType}`)
120
129
  }
121
- const Reactor = (value) => {
130
+ const Reactor = (value,component) => {
122
131
  if (value && typeof (value) === "object") {
123
132
  if (value.__isReactor__) return value;
124
133
  const childReactors = [],
@@ -131,7 +140,7 @@ const {observe} = (() => {
131
140
  return [...target];
132
141
  }
133
142
  if (property === "toString") return function toString() {
134
- return JSON.stringify(target);
143
+ return JSON.stringify([...target]);
135
144
  }
136
145
  }
137
146
  let value = target[property];
@@ -146,7 +155,7 @@ const {observe} = (() => {
146
155
  return value;
147
156
  }
148
157
  if (value && type === "object") {
149
- value = Reactor(value);
158
+ value = Reactor(value,component);
150
159
  childReactors.push(value);
151
160
  }
152
161
  target[property] = value;
@@ -156,7 +165,7 @@ const {observe} = (() => {
156
165
  const type = typeof (value);
157
166
  if (target[property] !== value) {
158
167
  if (value && type === "object") {
159
- value = Reactor(value);
168
+ value = Reactor(value,component);
160
169
  childReactors.push(value);
161
170
  }
162
171
  target[property] = value;
@@ -202,7 +211,7 @@ const {observe} = (() => {
202
211
  if (newValue == null || type === "any" || newtype === type || (typetype === "function" && newValue && newtype === "object" && newValue instanceof type)) {
203
212
  if (value !== newValue) {
204
213
  event.oldValue = value;
205
- target[property].value = reactive ? Reactor(newValue) : newValue; // do first to prevent loops
214
+ target[property].value = reactive ? Reactor(newValue,component) : newValue; // do first to prevent loops
206
215
  target.postEvent.value("change", event);
207
216
  if (event.defaultPrevented) target[property].value = value;
208
217
  }
@@ -218,18 +227,18 @@ const {observe} = (() => {
218
227
  }
219
228
  });
220
229
  }
221
- const createObserver = (domNode,framed) => {
230
+ const createObserver = (domNode, framed) => {
222
231
  const observer = new MutationObserver((mutations) => {
223
232
  mutations.forEach((mutation) => {
224
233
  if (mutation.type === "attributes") {
225
- if(framed) debugger;
234
+ if (framed) debugger;
226
235
  const name = mutation.attributeName,
227
236
  target = mutation.target,
228
237
  value = target.getAttribute(name);
229
- if(framed && name==="message" && target instanceof IFrameElement) {
230
- if(value) console.log("message",value);
238
+ if (framed && name === "message" && target instanceof IFrameElement) {
239
+ if (value) console.log("message", value);
231
240
  target.removeAttribute(name);
232
- target.dispatchEvent("message",new CustomEvent("message",{detail:JSON.parse(value)}))
241
+ target.dispatchEvent(new CustomEvent("message", {detail: JSON.parse(value)}))
233
242
  }
234
243
  if (target.observedAttributes && target.observedAttributes.includes(name)) {
235
244
  if (value !== mutation.oldValue) {
@@ -270,7 +279,7 @@ const {observe} = (() => {
270
279
  nodes.push(node);
271
280
  } else if (node.nodeType === Node.ELEMENT_NODE) {
272
281
  let skip;
273
- if(node.getAttribute("type")==="radio") nodes.push(node);
282
+ if (node.getAttribute("type") === "radio") nodes.push(node);
274
283
  [...node.attributes].forEach((attr) => {
275
284
  if (attr.value.includes("${")) {
276
285
  attr.template ||= attr.value;
@@ -308,7 +317,7 @@ const {observe} = (() => {
308
317
  }
309
318
  const inputTypeToType = (inputType) => {
310
319
  if (!inputType) return "any"
311
- if (["text", "tel", "email", "url", "search", "radio","color","password"].includes(inputType)) return "string";
320
+ if (["text", "tel", "email", "url", "search", "radio", "color", "password"].includes(inputType)) return "string";
312
321
  if (["number", "range"].includes(inputType)) return "number";
313
322
  if (["datetime"].includes(inputType)) return Date;
314
323
  if (["checkbox"].includes(inputType)) return "boolean";
@@ -317,25 +326,26 @@ const {observe} = (() => {
317
326
  const _importAnchors = (node, component) => {
318
327
  [...node.querySelectorAll('a[href][target^="#"]')].forEach((node) => {
319
328
  node.removeEventListener("click", anchorHandler);
320
- addListener(node,"click", anchorHandler);
329
+ addListener(node, "click", anchorHandler);
321
330
  })
322
331
  }
323
- const bindInput = (input, name, component) => {
324
- const inputtype = input.tagName === "SELECT" ? "text" : input.getAttribute("type"),
332
+ const bindInput = (input, name, component,value) => {
333
+ const inputtype = input.tagName === "SELECT" || input.tagName === "TEXTAREA" ? "text" : input.getAttribute("type"),
325
334
  type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype),
326
- deflt = input.getAttribute("default"),
327
- value = input.getAttribute("value");
335
+ deflt = input.getAttribute("default");
336
+ value ||= input.getAttribute("value");
328
337
  let variable = component.vars[name] || {type};
329
338
  if (type !== variable.type) {
330
339
  if (variable.type === "any" || variable.type === "unknown") variable.type = type;
331
340
  else throw new TypeError(`Attempt to bind <input name="${name}" type="${type}"> to variable ${name}:${variable.type}`)
332
341
  }
333
342
  component.variables({[name]: type});
343
+ component.setValue(name,value);
334
344
  let eventname = "change";
335
- if(input.tagName!=="SELECT" && (!inputtype || ["text","number","tel","email","url","search","password"].includes(inputtype))) {
345
+ if (input.tagName !== "SELECT" && (!inputtype || input.tagName === "TEXTAREA" || ["text", "number", "tel", "email", "url", "search", "password"].includes(inputtype))) {
336
346
  eventname = "input";
337
347
  }
338
- addListener(input,eventname, (event) => {
348
+ addListener(input, eventname, (event) => {
339
349
  event.stopImmediatePropagation();
340
350
  const target = event.target;
341
351
  let value = target.value;
@@ -344,7 +354,7 @@ const {observe} = (() => {
344
354
  } else if (target.tagName === "SELECT") {
345
355
  if (target.hasAttribute("multiple")) {
346
356
  value = [...target.querySelectorAll("option")]
347
- .filter((option) => option.selected || resolveNode(option.attributes.value,component)==value || option.innerText == value)
357
+ .filter((option) => option.selected || resolveNode(option.attributes.value, component) == value || option.innerText == value)
348
358
  .map((option) => option.getAttribute("value") || option.innerText);
349
359
  }
350
360
  }
@@ -354,7 +364,7 @@ const {observe} = (() => {
354
364
  const tryParse = (value) => {
355
365
  try {
356
366
  return JSON.parse(value);
357
- } catch(e) {
367
+ } catch (e) {
358
368
  return value;
359
369
  }
360
370
  }
@@ -368,7 +378,7 @@ const {observe} = (() => {
368
378
  exported: {value: true, constant: true},
369
379
  imported: {value: true, constant: true}
370
380
  };
371
- const createClass = (domElementNode, {observer, importAnchors, framed}) => {
381
+ const createClass = (domElementNode, {observer, importAnchors, framed}) => {
372
382
  const instances = new Set(),
373
383
  dom = domElementNode.tagName === "TEMPLATE"
374
384
  ? domElementNode.content.cloneNode(true)
@@ -382,7 +392,7 @@ const {observe} = (() => {
382
392
  constructor() {
383
393
  super();
384
394
  instances.add(this);
385
- observer ||= createObserver(this,framed);
395
+ observer ||= createObserver(this, framed);
386
396
  const currentComponent = this,
387
397
  shadow = this.attachShadow({mode: "open"}),
388
398
  eventlisteners = {};
@@ -412,7 +422,7 @@ const {observe} = (() => {
412
422
  };
413
423
  this.defaultAttributes = domElementNode.tagName === "TEMPLATE" ? domElementNode.attributes : dom.attributes;
414
424
  this.varsProxy = createVarsProxy(this.vars, this, CustomElement);
415
- if(framed || CustomElement.lightviewFramed) this.variables({message:Object},{exported:true});
425
+ if (framed || CustomElement.lightviewFramed) this.variables({message: Object}, {exported: true});
416
426
  ["getElementById", "querySelector", "querySelectorAll"]
417
427
  .forEach((fname) => {
418
428
  Object.defineProperty(this, fname, {
@@ -473,50 +483,50 @@ const {observe} = (() => {
473
483
  // resolve the value before all else;
474
484
  const attr = node.attributes.value;
475
485
  let name;
476
- if(attr && attr.template) {
477
- render(!!attr.template,() => {
486
+ if (attr && attr.template) {
487
+ render(!!attr.template, () => {
478
488
  const value = resolveNode(attr, this),
479
- eltype = resolveNode(node.attributes.type,ctx);
480
- if(eltype==="checkbox") {
481
- if(coerce(value,"boolean")===true) {
482
- node.setAttribute("checked","");
489
+ eltype = resolveNode(node.attributes.type, ctx);
490
+ if (eltype === "checkbox") {
491
+ if (coerce(value, "boolean") === true) {
492
+ node.setAttribute("checked", "");
483
493
  node.checked = true;
484
494
  } else {
485
495
  node.removeAttribute("checked");
486
496
  node.checked = false;
487
497
  }
488
- const vname = resolveNode(node.attributes.name,ctx);
489
- if(vname) ctx.setValue(vname,node.checked,{coerceTo:"boolean"});
498
+ const vname = resolveNode(node.attributes.name, ctx);
499
+ if (vname) ctx.setValue(vname, node.checked, {coerceTo: "boolean"});
490
500
  }
491
- if(node.tagName==="SELECT") {
501
+ if (node.tagName === "SELECT") {
492
502
  let values = [value];
493
- if(node.hasAttribute("multiple")) values = coerce(value,Array);
503
+ if (node.hasAttribute("multiple")) values = coerce(value, Array);
494
504
  [...node.querySelectorAll("option")].forEach((option) => {
495
- if(option.hasAttribute("value")) {
505
+ if (option.hasAttribute("value")) {
496
506
  if (values.includes(resolveNode(option.attributes.value, ctx))) {
497
507
  option.setAttribute("selected", "");
498
508
  option.selected = true;
499
509
  }
500
- } else if(option.innerText.trim()===value) {
501
- option.setAttribute("selected","");
510
+ } else if (option.innerText.trim() === value) {
511
+ option.setAttribute("selected", "");
502
512
  option.selected = true;
503
513
  }
504
514
  })
505
515
  }
506
- });
507
- let name;
508
- for(const vname of this.getVariableNames()) {
509
- if("${" + vname + "}" === attr.template) {
510
- name = vname;
511
- break;
516
+ if(node.attributes.value) {
517
+ const valueattr = node.attributes.value,
518
+ template = valueattr.template || valueattr.template.value;
519
+ if(template.startsWith("${") && template.endsWith("}")) {
520
+ const name = template.substring(2,template.length-1);
521
+ if(!name.includes(" ")) bindInput(node,name,this,value);
522
+ }
512
523
  }
513
- }
514
- if(name) bindInput(node,name,ctx);
524
+ });
515
525
  }
516
526
  [...node.attributes].forEach((attr) => {
517
- if(attr.name==="value") return;
527
+ if (attr.name === "value") return;
518
528
  const {name, value} = attr;
519
- if(name==="type") {
529
+ if (name === "type") {
520
530
  if (value === "radio") {
521
531
  const name = resolveNode(node.attributes.name, ctx);
522
532
  for (const vname of this.getVariableNames()) {
@@ -524,7 +534,7 @@ const {observe} = (() => {
524
534
  render(true, () => {
525
535
  const name = resolveNode(node.attributes.name, ctx),
526
536
  varvalue = Function("context", "with(context) { return `${" + name + "}` }")(ctx.varsProxy);
527
- if (varvalue == resolveNode(node.attributes.value,ctx)) {
537
+ if (varvalue == resolveNode(node.attributes.value, ctx)) {
528
538
  node.setAttribute("checked", "");
529
539
  node.checked = true;
530
540
  } else {
@@ -543,13 +553,13 @@ const {observe} = (() => {
543
553
  if (type === "") { // name is :something
544
554
  render(!!attr.template, () => {
545
555
  const value = attr.value,
546
- elvalue = resolveNode(node.attributes.value,ctx),
547
- eltype = resolveNode(node.attributes.type,ctx),
548
- elname = resolveNode(node.attributes.name,ctx);
556
+ elvalue = resolveNode(node.attributes.value, ctx),
557
+ eltype = resolveNode(node.attributes.type, ctx),
558
+ elname = resolveNode(node.attributes.name, ctx);
549
559
  if (params[0]) {
550
560
  if (value === "true") node.setAttribute(params[0], "")
551
561
  else node.removeAttribute(params[0]);
552
- } else if (eltype=== "checkbox" || node.tagName === "OPTION") {
562
+ } else if (eltype === "checkbox" || node.tagName === "OPTION") {
553
563
  if (value === "true") node.setAttribute("checked", "")
554
564
  else node.removeAttribute("checked");
555
565
  }
@@ -560,7 +570,7 @@ const {observe} = (() => {
560
570
  const value = resolveNode(attr, this);
561
571
  if (listener) node.removeEventListener(params[0], listener);
562
572
  listener = this[value] || window[value] || Function(value);
563
- addListener(node,params[0], listener);
573
+ addListener(node, params[0], listener);
564
574
  })
565
575
  } else if (type === "l-if") {
566
576
  render(!!attr.template, () => {
@@ -634,7 +644,7 @@ const {observe} = (() => {
634
644
 
635
645
  getVariableNames() {
636
646
  return Object.keys(this.vars).filter((name) => {
637
- return !(name in reserved) && !["self","addEventListener","postEvent"].includes(name)
647
+ return !(name in reserved) && !["self", "addEventListener", "postEvent"].includes(name)
638
648
  })
639
649
  }
640
650
 
@@ -684,7 +694,7 @@ const {observe} = (() => {
684
694
  }
685
695
  if (reactive) {
686
696
  variable.reactive = true;
687
- this.vars[key] = Reactor(variable);
697
+ this.vars[key] = Reactor(variable,this);
688
698
  }
689
699
  if (shared) {
690
700
  variable.shared = true;
@@ -732,17 +742,17 @@ const {observe} = (() => {
732
742
  }
733
743
  }
734
744
  }
735
- const createComponent = (name, node, {observer, importAnchors,framed} = {}) => {
745
+ const createComponent = (name, node, {observer, importAnchors, framed} = {}) => {
736
746
  let ctor = customElements.get(name);
737
747
  if (ctor) {
738
- if(framed && !ctor.lightviewFramed) {
748
+ if (framed && !ctor.lightviewFramed) {
739
749
  ctor.lightviewFramed = true;
740
750
  } else {
741
751
  console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
742
752
  }
743
753
  return ctor;
744
754
  }
745
- ctor = createClass(node, {observer, importAnchors,framed});
755
+ ctor = createClass(node, {observer, importAnchors, framed});
746
756
  customElements.define(name, ctor);
747
757
  return ctor;
748
758
  }
@@ -771,9 +781,9 @@ const {observe} = (() => {
771
781
  }
772
782
  }
773
783
 
774
- const bodyAsComponent = ({as = "x-body", unhide, importAnchors,framed} = {}) => {
784
+ const bodyAsComponent = ({as = "x-body", unhide, importAnchors, framed} = {}) => {
775
785
  const parent = document.body.parentElement;
776
- createComponent(as, document.body, {importAnchors,framed});
786
+ createComponent(as, document.body, {importAnchors, framed});
777
787
  const component = document.createElement(as);
778
788
  parent.replaceChild(component, document.body);
779
789
  Object.defineProperty(document, "body", {
@@ -815,7 +825,7 @@ const {observe} = (() => {
815
825
 
816
826
  const url = new URL(document.currentScript.getAttribute("src"), window.location.href);
817
827
  let domContentLoadedEvent;
818
- if(!domContentLoadedEvent) addListener(window,"DOMContentLoaded", (event) => domContentLoadedEvent = event);
828
+ if (!domContentLoadedEvent) addListener(window, "DOMContentLoaded", (event) => domContentLoadedEvent = event);
819
829
  let OBSERVER;
820
830
  const loader = async (whenFramed) => {
821
831
  if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
@@ -824,10 +834,10 @@ const {observe} = (() => {
824
834
  isolated = !!document.querySelector('meta[name="l-isolate"]'),
825
835
  enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
826
836
  if (whenFramed) {
827
- whenFramed({unhide, importAnchors, isolated, enableFrames, framed:true});
837
+ whenFramed({unhide, importAnchors, isolated, enableFrames, framed: true});
828
838
  if (!isolated) {
829
839
  postMessage.enabled = true;
830
- addListener(window,"message", ({data}) => {
840
+ addListener(window, "message", ({data}) => {
831
841
  const {type, argsList} = JSON.parse(data);
832
842
  if (type === "framed") {
833
843
  const resize = () => {
@@ -863,7 +873,7 @@ const {observe} = (() => {
863
873
  }
864
874
  if (enableFrames) {
865
875
  postMessage.enabled = true;
866
- addListener(window,"message", (message) => {
876
+ addListener(window, "message", (message) => {
867
877
  const {type, iframeId, argsList, href} = JSON.parse(message.data),
868
878
  iframe = document.getElementById(iframeId);
869
879
  if (iframe) {
@@ -900,7 +910,7 @@ const {observe} = (() => {
900
910
  }
901
911
  console.warn("iframe posted a message without providing an id", message);
902
912
  });
903
- if(!OBSERVER) {
913
+ if (!OBSERVER) {
904
914
  const mutationCallback = (mutationsList) => {
905
915
  const console = document.getElementById("console");
906
916
  for (const {target, attributeName, oldValue} of mutationsList) {
@@ -914,13 +924,16 @@ const {observe} = (() => {
914
924
  }, iframe)
915
925
  }
916
926
  }
917
- if(attributeName==="message") {
918
- if(value) {
927
+ if (attributeName === "message") {
928
+ if (value) {
919
929
  target.removeAttribute("message");
920
- target.dispatchEvent(new CustomEvent("message",{target,detail:JSON.parse(value)}))
930
+ target.dispatchEvent(new CustomEvent("message", {target, detail: JSON.parse(value)}))
921
931
  }
922
932
  } else {
923
- target.dispatchEvent(new CustomEvent("attribute.changed",{target,detail:{attributeName,value,oldValue}}))
933
+ target.dispatchEvent(new CustomEvent("attribute.changed", {
934
+ target,
935
+ detail: {attributeName, value, oldValue}
936
+ }))
924
937
  }
925
938
  }
926
939
  };
@@ -932,15 +945,17 @@ const {observe} = (() => {
932
945
  }
933
946
  const whenFramed = (f, {isolated} = {}) => {
934
947
  // loads for framed content
935
- addListener(document,"DOMContentLoaded", (event) => loader(f));
948
+ addListener(document, "DOMContentLoaded", (event) => loader(f));
936
949
  }
937
950
  Lightview.whenFramed = whenFramed;
938
951
  //Object.defineProperty(Lightview, "whenFramed", {configurable: true, writable: true, value: whenFramed});
939
952
  if (window.location === window.parent.location || !(window.parent instanceof Window) || window.parent !== window) {
940
953
  // loads for unframed content
941
954
  // CodePen mucks with window.parent
942
- addListener(document,"DOMContentLoaded", () => loader())
955
+ addListener(document, "DOMContentLoaded", () => loader())
943
956
  }
944
957
 
945
958
  return {observe}
946
- })();
959
+ })();
960
+
961
+
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "lightview",
3
- "version": "1.4.2b",
3
+ "version": "1.4.4b",
4
4
  "description": "Small, simple, powerful web UI and micro front end creation ... imagine a blend of Svelte, React, Vue, Riot and more.",
5
5
  "main": "lightview.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "set NODE_OPTIONS=--experimental-vm-modules && jest ./test"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -28,5 +28,9 @@
28
28
  "bugs": {
29
29
  "url": "https://github.com/anywhichway/lightview/issues"
30
30
  },
31
- "homepage": "https://github.com/anywhichway/lightview#readme"
31
+ "homepage": "https://github.com/anywhichway/lightview#readme",
32
+ "devDependencies": {
33
+ "jest": "^27.5.1",
34
+ "jest-puppeteer": "^6.1.0"
35
+ }
32
36
  }
@@ -0,0 +1,79 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Basic</title>
6
+ <template id="x-test" name="joe" open="true" count=1 children='["mary"]' l-on:click="bump">
7
+ <span id="name">${name}</span>
8
+ <span id="open">${open}</span>
9
+ <span id="count">${count}</span>
10
+ <span id="children">${children}</span>
11
+ <span id="color">${color}</span>
12
+ <span id="checked">${checked}</span>
13
+ <span id="age">${age}</span>
14
+ <span id="hamburger">${hamburger}</span>
15
+
16
+ <input id="iuntyped" value="${iuntyped}">
17
+ <input id="itext" type="text" value="${itext}">
18
+ <input id="itel" type="tel" value="${itel}">
19
+ <input id="iemail" type="email" value="${iemail}">
20
+ <input id="iurl" type="url" value="${iurl}">
21
+ <input id="isearch" type="search" value="${isearch}">
22
+ <input id="iradio" type="radio" value="${iradio}">
23
+ <input id="icolor" type="color" value="${icolor}">
24
+ <input id="ipassword" type="password" value="${ipassword}">
25
+
26
+ <input id="inumber" type="number" value="${inumber}">
27
+ <input id="irange" type="range" value="${irange}">
28
+
29
+ <input id="idatetime" type="datetime" value="${idatetime}">
30
+
31
+ <input id="icheckbox" type="checkbox" value="${icheckbox}">
32
+
33
+ <script type="lightview/module">
34
+ debugger;
35
+ self.variables({name:string,open:boolean,count:number,children:Array},{imported,reactive});
36
+ self.variables({color:string,checked:boolean,age:number,hamburger:Array},{exported,reactive});
37
+ self.variables({counter:number},{reactive});
38
+ self.variables({myshare:number},{shared});
39
+
40
+ color = "green";
41
+ checked = true;
42
+ age = 27;
43
+ hamburger = ["lettuce"];
44
+ counter = 0;
45
+ myshare = 1;
46
+
47
+ iuntyped = "test";
48
+ itext = "test";
49
+ itel = "test";
50
+ iemail = "test";
51
+ iurl = "test";
52
+ isearch = "test";
53
+ iradio = "test";
54
+ icolor = "test";
55
+ ipassword = "test";
56
+
57
+ inumber = 1;
58
+ irange = 1;
59
+
60
+ idatetime = new Date();
61
+
62
+ icheckbox = true;
63
+
64
+ self.bump = () => {
65
+ counter++;
66
+ };
67
+ </script>
68
+ </template>
69
+ <script src="../lightview.js"></script>
70
+ <script>
71
+ Lightview.createComponent("x-test",document.getElementById("x-test"));
72
+ </script>
73
+ </head>
74
+ <body>
75
+ <p><x-test id="test"></x-test></p>
76
+
77
+ <p><x-test id="test1"></x-test></p>
78
+ </body>
79
+ </html>
@@ -0,0 +1,248 @@
1
+ import 'expect-puppeteer';
2
+
3
+ describe('Google', () => {
4
+ beforeAll(async () => {
5
+ await page.goto('https://google.com');
6
+ });
7
+
8
+ test('should be titled "Google"', async () => {
9
+ await expect(page.title()).resolves.toMatch('Google');
10
+ });
11
+ });
12
+
13
+ describe('Lightview', () => {
14
+ beforeAll(async () => {
15
+ await page.goto('http://localhost:8080/test/basic.html');
16
+ });
17
+
18
+ test('should be titled "Basic"', async () => {
19
+ await expect(page.title()).resolves.toMatch('Basic');
20
+ });
21
+
22
+ test('boolean - open should be imported', async () => {
23
+ const result = await page.evaluate(() => {
24
+ const el = document.getElementById("test");
25
+ return JSON.parse(el.getValue("open"));
26
+ });
27
+ expect(result).toBe(true);
28
+ });
29
+
30
+ test('number - count should be imported', async () => {
31
+ const result = await page.evaluate(() => {
32
+ const el = document.getElementById("test");
33
+ return JSON.parse(el.getValue("count"));
34
+ });
35
+ expect(result).toBe(1);
36
+ });
37
+
38
+ test('string - name should be imported', async () => {
39
+ const result = await page.evaluate(() => {
40
+ const el = document.getElementById("test");
41
+ return el.getValue("name");
42
+ });
43
+ expect(result).toBe("joe");
44
+ });
45
+
46
+ test('object - children should be imported', async () => {
47
+ const result = await page.evaluate(() => {
48
+ const el = document.getElementById("test");
49
+ return el.getValue("children").toJSON();
50
+ });
51
+ expect(Array.isArray(result)).toBe(true);
52
+ expect(result[0]).toBe("mary");
53
+ expect(result.length).toBe(1);
54
+ });
55
+
56
+ test('boolean - checked should be exported', async () => {
57
+ const result = await page.evaluate(() => {
58
+ const el = document.getElementById("test");
59
+ return JSON.parse(el.getAttribute("checked"));
60
+ });
61
+ expect(result).toBe(true);
62
+ });
63
+
64
+ test('number - age should be exported', async () => {
65
+ const result = await page.evaluate(() => {
66
+ const el = document.getElementById("test");
67
+ return JSON.parse(el.getAttribute("age"));
68
+ });
69
+ expect(result).toBe(27);
70
+ });
71
+
72
+ test('string - color should be exported', async () => {
73
+ const result = await page.evaluate(() => {
74
+ const el = document.getElementById("test");
75
+ return el.getAttribute("color");
76
+ });
77
+ expect(result).toBe("green");
78
+ });
79
+
80
+ test('object - hamburger should be exported', async () => {
81
+ const result = await page.evaluate(() => {
82
+ const el = document.getElementById("test");
83
+ return JSON.parse(el.getAttribute("hamburger"));
84
+ });
85
+ expect(Array.isArray(result)).toBe(true);
86
+ expect(result[0]).toBe("lettuce");
87
+ expect(result.length).toBe(1);
88
+ });
89
+
90
+ test('boolean - open should be rendered', async () => {
91
+ const result = await page.evaluate(() => {
92
+ const el = document.getElementById("test"),
93
+ result = el.getElementById("open");
94
+ return JSON.parse(result.innerText);
95
+ });
96
+ expect(result).toBe(true);
97
+ });
98
+
99
+ test('number - count should be rendered', async () => {
100
+ const result = await page.evaluate(() => {
101
+ const el = document.getElementById("test"),
102
+ result = el.getElementById("count");
103
+ return JSON.parse(result.innerText);
104
+ });
105
+ expect(result).toBe(1);
106
+ });
107
+
108
+ test('string - name should be rendered', async () => {
109
+ const result = await page.evaluate(() => {
110
+ const el = document.getElementById("test"),
111
+ result = el.getElementById("name");
112
+ return result.innerText;
113
+ });
114
+ expect(result).toBe("joe");
115
+ });
116
+
117
+ test('object - children should be rendered', async () => {
118
+ const result = await page.evaluate(() => {
119
+ const el = document.getElementById("test"),
120
+ result = el.getElementById("children");
121
+ return JSON.parse(result.innerText);
122
+ });
123
+ expect(Array.isArray(result)).toBe(true);
124
+ expect(result[0]).toBe("mary");
125
+ expect(result.length).toBe(1);
126
+ });
127
+
128
+ test('boolean - checked should be rendered', async () => {
129
+ const result = await page.evaluate(() => {
130
+ const el = document.getElementById("test"),
131
+ result = el.getElementById("checked");
132
+ return JSON.parse(result.innerText);
133
+ });
134
+ expect(result).toBe(true);
135
+ });
136
+
137
+ test('number - age should be rendered', async () => {
138
+ const result = await page.evaluate(() => {
139
+ const el = document.getElementById("test"),
140
+ result = el.getElementById("age");
141
+ return JSON.parse(result.innerText);
142
+ });
143
+ expect(result).toBe(27);
144
+ });
145
+
146
+ test('string - color should be rendered', async () => {
147
+ const result = await page.evaluate(() => {
148
+ const el = document.getElementById("test"),
149
+ result = el.getElementById("color");
150
+ return result.innerText;
151
+ });
152
+ expect(result).toBe("green");
153
+ });
154
+
155
+ test('object - hamburger should be rendered', async () => {
156
+ const result = await page.evaluate(() => {
157
+ const el = document.getElementById("test"),
158
+ result = el.getElementById("hamburger");
159
+ return JSON.parse(result.innerText);
160
+ });
161
+ expect(Array.isArray(result)).toBe(true);
162
+ expect(result[0]).toBe("lettuce");
163
+ expect(result.length).toBe(1);
164
+ });
165
+
166
+ test('shared - myshare should be same', async () => {
167
+ const result = await page.evaluate(async () => {
168
+ const el0 = document.getElementById("test"),
169
+ el1 = document.getElementById("test1")
170
+ return [el0.getValue("myshare"),el1.getValue("myshare")];
171
+ });
172
+ expect(Array.isArray(result)).toBe(true);
173
+ expect(result[0]).toBe(result[1]);
174
+ });
175
+
176
+ test('untyped input - iuntyped should be "test"', async () => {
177
+ const result = await page.evaluate(async () => {
178
+ const el = document.getElementById("test"),
179
+ result = el.getElementById("iuntyped")
180
+ return result.getAttribute("value");
181
+ });
182
+ expect(result).toBe("test");
183
+ });
184
+
185
+ // "tel", "email", "url", "search", "radio", "color", "password"
186
+ ["text","tel","email", "url", "search", "radio", "color", "password"].forEach((type) => {
187
+ const f = Function(`return async () => {
188
+ const result = await page.evaluate(async () => {
189
+ const el = document.getElementById("test"),
190
+ result = el.getElementById("i${type}");
191
+ return {value:result.getAttribute("value"),variable:el.vars["i${type}"]};
192
+ });
193
+ const {value,variable} = result;
194
+ expect(value).toBe("test");
195
+ expect(variable.name).toBe("i${type}");
196
+ expect(variable.type).toBe("string");
197
+ expect(variable.value).toBe(value);
198
+ }`)();
199
+ test(`${type} input - i${type} should be "test"`,f);
200
+ });
201
+
202
+ test('number input - inumber should be 1', async () => {
203
+ const result = await page.evaluate(async () => {
204
+ const el = document.getElementById("test"),
205
+ result = el.getElementById("inumber")
206
+ return JSON.parse(result.getAttribute("value"));
207
+ });
208
+ expect(result).toBe(1);
209
+ });
210
+
211
+ test('range input - irange should be 1', async () => {
212
+ const result = await page.evaluate(async () => {
213
+ const el = document.getElementById("test"),
214
+ result = el.getElementById("irange")
215
+ return JSON.parse(result.getAttribute("value"));
216
+ });
217
+ expect(result).toBe(1);
218
+ });
219
+
220
+ test('datetime input - idatetime should be current date', async () => {
221
+ const result = await page.evaluate(async () => {
222
+ const el = document.getElementById("test"),
223
+ result = el.getElementById("idatetime")
224
+ return result.getAttribute("value");
225
+ });
226
+ const dt = new Date(result);
227
+ expect(dt).toBeInstanceOf(Date);
228
+ expect(dt.toString()).toBe(result);
229
+ });
230
+
231
+ test('checkbox input - icheckbox should be true', async () => {
232
+ const result = await page.evaluate(async () => {
233
+ const el = document.getElementById("test"),
234
+ result = el.getElementById("icheckbox")
235
+ return JSON.parse(result.getAttribute("value"));
236
+ });
237
+ expect(result).toBe(true);
238
+ });
239
+
240
+ test('on:<handler> - count should be bumped', async () => {
241
+ await page.click("#test",{waitUntil:"load"});
242
+ const result = await page.evaluate(async () => {
243
+ const el = document.getElementById("test");
244
+ return JSON.parse(el.getValue("counter"));
245
+ });
246
+ expect(result).toBe(1);
247
+ });
248
+ });