diff --git a/api/js/etemplate/Et2Email/Et2Email.ts b/api/js/etemplate/Et2Email/Et2Email.ts
index 1a0d50bc58..eea6fe699e 100644
--- a/api/js/etemplate/Et2Email/Et2Email.ts
+++ b/api/js/etemplate/Et2Email/Et2Email.ts
@@ -1351,7 +1351,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
?active=${this.open}
>
const element = await before();
element.noLang = true;
return element
-}, "", "input");
\ No newline at end of file
+}, "fake@example.com", "input");
\ No newline at end of file
diff --git a/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts b/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts
index 4440b57c6a..79c81189d5 100644
--- a/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts
+++ b/api/js/etemplate/Et2InputWidget/Et2InputWidget.ts
@@ -189,6 +189,7 @@ const Et2InputWidgetMixin =
>(superclass : T)
this._messagesHeldWhileFocused = [];
this.readonly = false;
+ this.required = false;
this._oldValue = this.getValue();
this.isSlComponent = typeof (this).handleChange === 'function';
@@ -224,7 +225,7 @@ const Et2InputWidgetMixin = >(superclass : T)
* A property has changed, and we want to make adjustments to other things
* based on that
*
- * @param {import('@lion/core').PropertyValues } changedProperties
+ * @param changedProperties
*/
updated(changedProperties : PropertyValues)
{
diff --git a/api/js/etemplate/Et2InputWidget/test/InputBasicTests.ts b/api/js/etemplate/Et2InputWidget/test/InputBasicTests.ts
index 75c34a5174..314cabd7a5 100644
--- a/api/js/etemplate/Et2InputWidget/test/InputBasicTests.ts
+++ b/api/js/etemplate/Et2InputWidget/test/InputBasicTests.ts
@@ -118,11 +118,16 @@ export function inputBasicTests(before : Function, test_value : string, value_se
{
beforeEach(async() =>
{
+ assert.isNotEmpty(test_value, "test_value needs to be a value");
+
element = await before();
+ await elementUpdated(element);
+ element.required = true;
+ await elementUpdated(element);
});
// This is just visually comparing for a difference, no deep inspection
- it("looks different when required")
+ //it("looks different when required")
/*
Not yet working attempt to have playwright compare visually
@@ -142,5 +147,35 @@ export function inputBasicTests(before : Function, test_value : string, value_se
*/
+ it("is invalid without a value", async() =>
+ {
+ element.set_value("");
+
+ // wait for asychronous changes to the DOM
+ await elementUpdated(element);
+
+ // widget returns what we gave it
+ assert.equal(element.get_value(), "");
+ assert.equal(element.required, true, "required not set");
+
+ // widget fails validation
+ let messages = [];
+ assert.isFalse(element.isValid(messages), `Required has no value (${element.getValue()}), but is considered valid`);
+ });
+ it("is valid with a value", async() =>
+ {
+ element.set_value(test_value);
+
+ // wait for asychronous changes to the DOM
+ await elementUpdated(element);
+
+ // widget returns what we gave it
+ assert.equal(element.get_value(), test_value);
+ assert.equal(element.required, true, "required not set");
+
+ // widget fails validation
+ let messages = [];
+ assert.isTrue(element.isValid(messages), `Required has a value (${element.getValue()}), but is not considered valid. ` + messages.join("\n"));
+ });
});
}
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts
index ad827b7bee..3629052458 100644
--- a/api/js/etemplate/Et2Select/Et2Select.ts
+++ b/api/js/etemplate/Et2Select/Et2Select.ts
@@ -293,9 +293,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
/** The select's help text. If you need to display HTML, use the `help-text` slot instead. */
@property({attribute: 'help-text'}) helpText = '';
- /** The select's required attribute. */
- @property({type: Boolean, reflect: true}) required = false;
-
/** If the select is limited to 1 row, we show the number of tags not visible */
@state()
protected _tagsHidden = 0;
@@ -817,9 +814,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
return this.select?.open ?? false;
}
- protected _renderOptions()
- {return Promise.resolve();}
-
protected get select() : SlSelect
{
return this.shadowRoot?.querySelector("sl-select");
@@ -1034,7 +1028,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
return html`
${this._styleTemplate()}
>(supe
}
- willUpdate(changedProperties : PropertyValues)
- {
- // Add in actual option tags to the DOM based on the new select_options
- if(changedProperties.has('select_options') || changedProperties.has("emptyLabel"))
- {
- // Add in options as children to the target node
- const optionPromise = this._renderOptions();
-
- // This is needed to display initial load value in some cases, like infolog nm header filters
- if(typeof this.selectionChanged !== "undefined")
- {
- optionPromise.then(async() =>
- {
- await this.updateComplete;
- this.selectionChanged();
- });
- }
- }
- }
-
public getValueAsArray()
{
if(Array.isArray(this.value))
@@ -200,48 +180,6 @@ export const Et2WidgetWithSelectMixin = >(supe
return result;
}
- /**
- * Render select_options as child DOM Nodes
- * @protected
- */
- protected _renderOptions()
- {
- return Promise.resolve();
- // Add in options as children to the target node
- if(!this._optionTargetNode)
- {
- return Promise.resolve();
- }
- /**
- * Doing all this garbage to get the options to always show up.
- * If we just do `render(options, target)`, they only show up in the DOM the first time. If the
- * same option comes back in a subsequent search, map() does not put it into the DOM.
- * If we render into a new target, the options get rendered, but we have to wait for them to be
- * rendered before we can do anything else with them.
- */
- let temp_target = document.createElement("div");
-
- let options = html`${this._emptyLabelTemplate()}${this.select_options
- // Filter out empty values if we have empty label to avoid duplicates
- .filter(o => this.emptyLabel ? o.value !== '' : o)
- .map(this._groupTemplate.bind(this))}`;
-
- render(options, temp_target);
- this._optionRenderPromise = Promise.all(([...temp_target.querySelectorAll(":scope > *")].map(item => item.render)))
- .then(() =>
- {
- this._optionTargetNode.replaceChildren(
- ...Array.from(temp_target.querySelectorAll(":scope > *")),
- ...Array.from(this._optionTargetNode.querySelectorAll(":scope > [slot]"))
- );
- if(typeof this.handleMenuSlotChange == "function")
- {
- this.handleMenuSlotChange();
- }
- });
- return this._optionRenderPromise;
- }
-
/**
* Set the select options
*
diff --git a/api/js/etemplate/Et2Select/test/Et2SelectBasic.test.ts b/api/js/etemplate/Et2Select/test/Et2SelectBasic.test.ts
index c9bd9c4987..956e20729b 100644
--- a/api/js/etemplate/Et2Select/test/Et2SelectBasic.test.ts
+++ b/api/js/etemplate/Et2Select/test/Et2SelectBasic.test.ts
@@ -157,6 +157,6 @@ inputBasicTests(async() =>
{
const element = await before();
element.noLang = true;
- element.select_options = [{value: "", label: ""}];
+ element.select_options = [{value: "", label: ""}, {value: "one", label: "one"}];
return element
-}, "", "sl-select");
\ No newline at end of file
+}, "one", "sl-select");
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Textbox/test/Et2Textbox.test.ts b/api/js/etemplate/Et2Textbox/test/Et2Textbox.test.ts
index 9091883da4..4445a758de 100644
--- a/api/js/etemplate/Et2Textbox/test/Et2Textbox.test.ts
+++ b/api/js/etemplate/Et2Textbox/test/Et2Textbox.test.ts
@@ -1,10 +1,17 @@
/**
* Test file for Etemplate webComponent Textbox
*/
-import {assert, fixture, html} from '@open-wc/testing';
+import {assert, elementUpdated, fixture, html} from '@open-wc/testing';
import {Et2Textbox} from "../Et2Textbox";
import {inputBasicTests} from "../../Et2InputWidget/test/InputBasicTests";
+import * as sinon from "sinon";
+// Stub global egw for cssImage to find
+// @ts-ignore
+window.egw = {
+ lang: i => i + "*",
+ tooltipUnbind: () => {}
+};
// Reference to component under test
let element : Et2Textbox;
@@ -14,6 +21,11 @@ async function before()
element = await fixture(html`
`);
+
+ // Stub egw()
+ sinon.stub(element, "egw").returns(window.egw);
+ await elementUpdated(element);
+
return element;
}