mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-03 04:29:28 +01:00
Et2Email: Some automatic tests
This commit is contained in:
parent
a62ff90018
commit
f68faa7941
@ -87,16 +87,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
// Parse string into array
|
// Parse string into array
|
||||||
if(typeof value === 'string' && value.indexOf(',') !== -1)
|
if(typeof value === 'string' && value.indexOf(',') !== -1)
|
||||||
{
|
{
|
||||||
let val = value.split(',');
|
return parseEmailsString(value, false);
|
||||||
for(let n = 0; n < val.length - 1; n++)
|
|
||||||
{
|
|
||||||
while(val[n].indexOf('@') === -1 && n < val.length - 1)
|
|
||||||
{
|
|
||||||
val[n] += ',' + val[n + 1];
|
|
||||||
val.splice(n + 1, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
@ -670,11 +661,8 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
{
|
{
|
||||||
selection.deleteFromDocument();
|
selection.deleteFromDocument();
|
||||||
}
|
}
|
||||||
|
let values = parseEmailsString(paste, this.allowPlaceholder);
|
||||||
|
|
||||||
let preg = this.allowPlaceholder ? IsEmail.EMAIL_PLACEHOLDER_PREG : IsEmail.EMAIL_PREG;
|
|
||||||
// Trim line start / end anchors off validation regex, make global
|
|
||||||
let regex = new RegExp(preg.toString().substring(2, preg.toString().length - 3), 'g');
|
|
||||||
let values = paste.match(regex);
|
|
||||||
if(values)
|
if(values)
|
||||||
{
|
{
|
||||||
values.forEach(v =>
|
values.forEach(v =>
|
||||||
@ -685,6 +673,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
|
|
||||||
// Update key to force Lit to redraw tags
|
// Update key to force Lit to redraw tags
|
||||||
this._valueUID = this.egw()?.uid() ?? new Date().toISOString();
|
this._valueUID = this.egw()?.uid() ?? new Date().toISOString();
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,6 +705,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
if(this.addAddress(this._search.value.trim()))
|
if(this.addAddress(this._search.value.trim()))
|
||||||
{
|
{
|
||||||
this._search.value = "";
|
this._search.value = "";
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
else if(this._search.value)
|
else if(this._search.value)
|
||||||
{
|
{
|
||||||
@ -773,6 +763,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
{
|
{
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this._search.value = "";
|
this._search.value = "";
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
if(event.key == "Tab")
|
if(event.key == "Tab")
|
||||||
{
|
{
|
||||||
@ -963,6 +954,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
this._search.value = "";
|
this._search.value = "";
|
||||||
this._search.focus();
|
this._search.focus();
|
||||||
this.requestUpdate("value");
|
this.requestUpdate("value");
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
if(this._close_on_select)
|
if(this._close_on_select)
|
||||||
{
|
{
|
||||||
this.open = false;
|
this.open = false;
|
||||||
@ -977,6 +969,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
let index = this.value.indexOf(event.originalValue);
|
let index = this.value.indexOf(event.originalValue);
|
||||||
this.value[index] = event.target.value;
|
this.value[index] = event.target.value;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
if(event.target.current)
|
if(event.target.current)
|
||||||
{
|
{
|
||||||
@ -990,6 +983,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
const index = this.value.indexOf(value);
|
const index = this.value.indexOf(value);
|
||||||
this.value.splice(index, 1);
|
this.value.splice(index, 1);
|
||||||
this.requestUpdate("value");
|
this.requestUpdate("value");
|
||||||
|
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
tagsTemplate()
|
tagsTemplate()
|
||||||
@ -1184,4 +1178,19 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
|
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
|
||||||
customElements.define("et2-email", Et2Email);
|
customElements.define("et2-email", Et2Email);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse string that may contain multiple comma separated email addresses into an array
|
||||||
|
*
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {string[]}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function parseEmailsString(value : string, allowPlaceholder = false) : string[]
|
||||||
|
{
|
||||||
|
let preg = allowPlaceholder ? IsEmail.EMAIL_PLACEHOLDER_PREG : IsEmail.EMAIL_PREG;
|
||||||
|
// Trim line start / end anchors off validation regex, make global
|
||||||
|
let regex = new RegExp(preg.toString().substring(2, preg.toString().length - 3), 'g');
|
||||||
|
return value.match(regex);
|
||||||
|
}
|
@ -2,6 +2,8 @@ import {assert, elementUpdated, fixture, html, oneEvent} from '@open-wc/testing'
|
|||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import {inputBasicTests} from "../../Et2InputWidget/test/InputBasicTests";
|
import {inputBasicTests} from "../../Et2InputWidget/test/InputBasicTests";
|
||||||
import {Et2Email} from "../Et2Email";
|
import {Et2Email} from "../Et2Email";
|
||||||
|
import {Et2EmailTag} from "../../Et2Select/Tag/Et2EmailTag";
|
||||||
|
import {waitForEvent} from "../../Et2Widget/event";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test file for Etemplate webComponent Select
|
* Test file for Etemplate webComponent Select
|
||||||
@ -10,11 +12,24 @@ import {Et2Email} from "../Et2Email";
|
|||||||
*/
|
*/
|
||||||
// Stub global egw for cssImage to find
|
// Stub global egw for cssImage to find
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
let uid = 0;
|
||||||
|
const testSuggestions = [
|
||||||
|
{value: "suggestion.1@example.com", label: "Suggestion 1"},
|
||||||
|
{value: "suggestion.2@example.com", label: "Suggestion 2"}
|
||||||
|
];
|
||||||
window.egw = {
|
window.egw = {
|
||||||
|
ajaxUrl: () => "",
|
||||||
|
app: () => "addressbook",
|
||||||
|
decodePath: (_path : string) => _path,
|
||||||
image: () => "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDMyIDMyIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjNjk2OTY5IiBkPSJNNi45NDMsMjguNDUzDQoJYzAuOTA2LDAuNzY1LDIuMDk3LDEuMTI3LDMuMjg2LDEuMTA5YzAuNDMsMC4wMTQsMC44NTItMC4wNjgsMS4yNjUtMC4yMDdjMC42NzktMC4xOCwxLjMyOC0wLjQ1LDEuODY2LTAuOTAyTDI5LjQwMywxNC45DQoJYzEuNzcyLTEuNDk4LDEuNzcyLTMuOTI1LDAtNS40MjJjLTEuNzcyLTEuNDk3LTQuNjQ2LTEuNDk3LTYuNDE4LDBMMTAuMTE5LDIwLjM0OWwtMi4zODktMi40MjRjLTEuNDQtMS40NTctMy43NzItMS40NTctNS4yMTIsMA0KCWMtMS40MzgsMS40Ni0xLjQzOCwzLjgyNSwwLDUuMjgxQzIuNTE4LDIzLjIwNiw1LjQ3NCwyNi45NDcsNi45NDMsMjguNDUzeiIvPg0KPC9zdmc+DQo=",
|
image: () => "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDMyIDMyIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjNjk2OTY5IiBkPSJNNi45NDMsMjguNDUzDQoJYzAuOTA2LDAuNzY1LDIuMDk3LDEuMTI3LDMuMjg2LDEuMTA5YzAuNDMsMC4wMTQsMC44NTItMC4wNjgsMS4yNjUtMC4yMDdjMC42NzktMC4xOCwxLjMyOC0wLjQ1LDEuODY2LTAuOTAyTDI5LjQwMywxNC45DQoJYzEuNzcyLTEuNDk4LDEuNzcyLTMuOTI1LDAtNS40MjJjLTEuNzcyLTEuNDk3LTQuNjQ2LTEuNDk3LTYuNDE4LDBMMTAuMTE5LDIwLjM0OWwtMi4zODktMi40MjRjLTEuNDQtMS40NTctMy43NzItMS40NTctNS4yMTIsMA0KCWMtMS40MzgsMS40Ni0xLjQzOCwzLjgyNSwwLDUuMjgxQzIuNTE4LDIzLjIwNiw1LjQ3NCwyNi45NDcsNi45NDMsMjguNDUzeiIvPg0KPC9zdmc+DQo=",
|
||||||
|
jsonq: () => Promise.resolve({}),
|
||||||
lang: i => i + "*",
|
lang: i => i + "*",
|
||||||
|
link: i => i,
|
||||||
|
preference: i => "",
|
||||||
|
request: () => Promise.resolve(testSuggestions),
|
||||||
tooltipUnbind: () => {},
|
tooltipUnbind: () => {},
|
||||||
webserverUrl: ""
|
webserverUrl: "",
|
||||||
|
uid: () => {return "" + (uid++);}
|
||||||
};
|
};
|
||||||
|
|
||||||
let element : Et2Email;
|
let element : Et2Email;
|
||||||
@ -52,7 +67,13 @@ describe("Email widget basics", () =>
|
|||||||
await elementUpdated(element);
|
await elementUpdated(element);
|
||||||
|
|
||||||
assert.equal(element.querySelector("[slot='label']").textContent, "Label set");
|
assert.equal(element.querySelector("[slot='label']").textContent, "Label set");
|
||||||
})
|
});
|
||||||
|
|
||||||
|
it("textbox gets focus when widget is focused", async() =>
|
||||||
|
{
|
||||||
|
element.focus();
|
||||||
|
assert.equal(element.shadowRoot.activeElement, element._search, "Search textbox did not get focus when widget got focus");
|
||||||
|
});
|
||||||
|
|
||||||
it("closes when losing focus", async() =>
|
it("closes when losing focus", async() =>
|
||||||
{
|
{
|
||||||
@ -67,8 +88,9 @@ describe("Email widget basics", () =>
|
|||||||
{
|
{
|
||||||
element.addEventListener("sl-hide", resolve);
|
element.addEventListener("sl-hide", resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
await elementUpdated(element);
|
await elementUpdated(element);
|
||||||
element.focus();
|
element.show();
|
||||||
|
|
||||||
await showPromise;
|
await showPromise;
|
||||||
await elementUpdated(element);
|
await elementUpdated(element);
|
||||||
@ -82,7 +104,57 @@ describe("Email widget basics", () =>
|
|||||||
|
|
||||||
// Check that it actually closed dropdown
|
// Check that it actually closed dropdown
|
||||||
assert.isFalse(element.hasAttribute("open"));
|
assert.isFalse(element.hasAttribute("open"));
|
||||||
})
|
});
|
||||||
|
|
||||||
|
it("blurring widget accepts current text", async() =>
|
||||||
|
{
|
||||||
|
const value = "valid@example.com";
|
||||||
|
element.focus();
|
||||||
|
element._search.value = value;
|
||||||
|
element.blur();
|
||||||
|
await elementUpdated(element);
|
||||||
|
|
||||||
|
assert.sameMembers(element.value, [value], "Valid email was not accepted on blur");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("Suggestions", () =>
|
||||||
|
{ // Setup run before each test
|
||||||
|
beforeEach(before);
|
||||||
|
|
||||||
|
it("clicking accepts suggestion", async() =>
|
||||||
|
{
|
||||||
|
await elementUpdated(element);
|
||||||
|
// Start the search
|
||||||
|
element.focus();
|
||||||
|
element.startSearch();
|
||||||
|
debugger;
|
||||||
|
await waitForEvent(element, "sl-after-show");
|
||||||
|
|
||||||
|
// Click the first one
|
||||||
|
element._listbox.querySelector('sl-option').dispatchEvent(new MouseEvent("mouseup", {bubbles: true}))
|
||||||
|
await elementUpdated(element);
|
||||||
|
// Check the value
|
||||||
|
assert.sameMembers(element.value, [testSuggestions[0].value]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tab accepts top suggestion", async() =>
|
||||||
|
{
|
||||||
|
element.focus();
|
||||||
|
element.startSearch();
|
||||||
|
await waitForEvent(element, "sl-after-show");
|
||||||
|
|
||||||
|
// No match between what they typed and the suggestion - no
|
||||||
|
element._search.dispatchEvent(new KeyboardEvent("keydown", {key: "Tab"}));
|
||||||
|
await elementUpdated(element);
|
||||||
|
assert.sameMembers(element.value, []);
|
||||||
|
|
||||||
|
// Partial match with current suggestion, take it
|
||||||
|
element.focus();
|
||||||
|
element._search.value = "sugg";
|
||||||
|
element._search.dispatchEvent(new KeyboardEvent("keydown", {key: "Tab"}));
|
||||||
|
await elementUpdated(element);
|
||||||
|
assert.sameMembers(element.value, [testSuggestions[0].value]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Tags", () =>
|
describe("Tags", () =>
|
||||||
@ -107,21 +179,11 @@ describe("Tags", () =>
|
|||||||
{
|
{
|
||||||
assert.equal(element._tags.length, 2, "Did not find tags");
|
assert.equal(element._tags.length, 2, "Did not find tags");
|
||||||
|
|
||||||
// Await tags to render
|
|
||||||
/* TODO
|
|
||||||
let tag_updates = []
|
|
||||||
element.select.combobox.querySelectorAll("et2-tag").forEach((t : Et2Tag) => tag_updates.push(t.updateComplete));
|
|
||||||
await Promise.all(tag_updates);
|
|
||||||
|
|
||||||
assert.equal(tags.length, 2);
|
|
||||||
assert.equal(tags[0].value, "one");
|
|
||||||
assert.equal(tags[1].value, "two");
|
|
||||||
*/
|
|
||||||
// Set up listener
|
// Set up listener
|
||||||
const listener = oneEvent(element, "change");
|
const listener = oneEvent(element, "change");
|
||||||
|
|
||||||
// Click to remove first tag
|
// Click to remove first tag
|
||||||
let removeButton = tags[0].shadowRoot.querySelector("[part='remove-button']");
|
let removeButton = element._tags[0].shadowRoot.querySelector("[part='remove-button']");
|
||||||
assert.exists(removeButton, "Could not find tag remove button");
|
assert.exists(removeButton, "Could not find tag remove button");
|
||||||
removeButton.dispatchEvent(new Event("click"));
|
removeButton.dispatchEvent(new Event("click"));
|
||||||
|
|
||||||
@ -129,14 +191,13 @@ describe("Tags", () =>
|
|||||||
|
|
||||||
// Wait for widget to update
|
// Wait for widget to update
|
||||||
await element.updateComplete;
|
await element.updateComplete;
|
||||||
tag_updates = []
|
let tag_updates = []
|
||||||
element.select.combobox.querySelectorAll('et2-tag').forEach((t : Et2Tag) => tag_updates.push(t.updateComplete));
|
element._tags.forEach((t : Et2EmailTag) => tag_updates.push(t.updateComplete));
|
||||||
await Promise.all(tag_updates);
|
await Promise.all(tag_updates);
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
assert.sameMembers(element.value, ["two"], "Removing tag did not remove value");
|
assert.sameMembers(element.value, ["two@example.com"], "Removing tag did not remove value");
|
||||||
tags = element.select.combobox.querySelectorAll('.select__tags et2-tag');
|
assert.equal(element._tags.length, 1, "Removed tag is still there");
|
||||||
assert.equal(tags.length, 1, "Removed tag is still there");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -146,4 +207,4 @@ inputBasicTests(async() =>
|
|||||||
const element = await before();
|
const element = await before();
|
||||||
element.noLang = true;
|
element.noLang = true;
|
||||||
return element
|
return element
|
||||||
}, "", "sl-select");
|
}, "", "input");
|
@ -181,7 +181,7 @@ export class Et2EmailTag extends Et2Tag
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
let extra = {
|
let extra = {
|
||||||
'presets[email]': this.value
|
'presets[email]': this.value ?? ""
|
||||||
};
|
};
|
||||||
|
|
||||||
this.egw().open('', 'addressbook', 'add', extra);
|
this.egw().open('', 'addressbook', 'add', extra);
|
||||||
|
@ -76,7 +76,8 @@ describe('Et2EmailTag', () =>
|
|||||||
assert.equal(extra['presets[email]'], 'test@example.com');
|
assert.equal(extra['presets[email]'], 'test@example.com');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
component.handleMouseDown(new MouseEvent('click'));
|
debugger;
|
||||||
|
component.shadowRoot.querySelector("et2-button-icon").dispatchEvent(new MouseEvent('click'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open addressbook CRM on avatar click', async() =>
|
it('should open addressbook CRM on avatar click', async() =>
|
||||||
|
Loading…
Reference in New Issue
Block a user