mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-23 16:33:17 +01:00
Et2Email: Some automatic tests
This commit is contained in:
parent
5e42dc34de
commit
3746e07276
@ -89,16 +89,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
// Parse string into array
|
||||
if(typeof value === 'string' && value.indexOf(',') !== -1)
|
||||
{
|
||||
let val = value.split(',');
|
||||
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 parseEmailsString(value, false);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
@ -676,6 +667,47 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
/**
|
||||
* Sometimes users paste multiple comma separated values at once. Split them then handle normally.
|
||||
* Overridden here to handle email addresses that may have commas using the regex from the validator.
|
||||
*
|
||||
* @param {ClipboardEvent} event
|
||||
* @protected
|
||||
*/
|
||||
protected handlePaste(event : ClipboardEvent)
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
let paste = event.clipboardData.getData('text');
|
||||
if(!paste)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const selection = window.getSelection();
|
||||
if(selection.rangeCount)
|
||||
{
|
||||
selection.deleteFromDocument();
|
||||
}
|
||||
let values = parseEmailsString(paste, this.allowPlaceholder);
|
||||
|
||||
if(values)
|
||||
{
|
||||
values.forEach(v =>
|
||||
{
|
||||
this.addAddress(v.trim());
|
||||
});
|
||||
this.hide();
|
||||
|
||||
// Update key to force Lit to redraw tags
|
||||
this._valueUID = this.egw()?.uid() ?? new Date().toISOString();
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> f68faa7941 (Et2Email: Some automatic tests)
|
||||
private handleSearchFocus()
|
||||
{
|
||||
this.hasFocus = true;
|
||||
@ -693,6 +725,26 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
this.hasFocus = false;
|
||||
// Should not be needed, but not firing the update
|
||||
this.requestUpdate("hasFocus");
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
// If they had something OK typed, use it, but only if focus went outside Et2Email
|
||||
// because maybe they clicked an option which took focus
|
||||
if(event.composedPath().includes(this))
|
||||
{
|
||||
if(this.addAddress(this._search.value.trim()))
|
||||
{
|
||||
this._search.value = "";
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}
|
||||
else if(this._search.value)
|
||||
{
|
||||
// Invalid input, show message. Not part of the value, so normal validation doesn't apply
|
||||
// Can't just call this.validate(), it will get cleared immediately
|
||||
this.set_validation_error(this.egw().lang("Invalid email") + ' "' + this._search.value + '"')
|
||||
}
|
||||
}
|
||||
>>>>>>> f68faa7941 (Et2Email: Some automatic tests)
|
||||
}
|
||||
|
||||
handleSearchKeyDown(event)
|
||||
@ -742,6 +794,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
{
|
||||
this.open = false;
|
||||
this._search.value = "";
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}
|
||||
if(event.key == "Tab")
|
||||
{
|
||||
@ -927,6 +980,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
this._search.value = "";
|
||||
this._search.focus();
|
||||
this.requestUpdate("value");
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
if(this._close_on_select)
|
||||
{
|
||||
this.open = false;
|
||||
@ -941,6 +995,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
let index = this.value.indexOf(event.originalValue);
|
||||
this.value[index] = event.target.value;
|
||||
this.requestUpdate();
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}
|
||||
if(event.target.current)
|
||||
{
|
||||
@ -954,6 +1009,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
const index = this.value.indexOf(value);
|
||||
this.value.splice(index, 1);
|
||||
this.requestUpdate("value");
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
}
|
||||
|
||||
tagsTemplate()
|
||||
@ -1143,6 +1199,7 @@ export class Et2Email extends Et2InputWidget(LitElement) implements SearchMixinI
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement
|
||||
customElements.define("et2-email", Et2Email);
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,8 @@ import {assert, elementUpdated, fixture, html, oneEvent} from '@open-wc/testing'
|
||||
import * as sinon from 'sinon';
|
||||
import {inputBasicTests} from "../../Et2InputWidget/test/InputBasicTests";
|
||||
import {Et2Email} from "../Et2Email";
|
||||
import {Et2EmailTag} from "../../Et2Select/Tag/Et2EmailTag";
|
||||
import {waitForEvent} from "../../Et2Widget/event";
|
||||
|
||||
/**
|
||||
* Test file for Etemplate webComponent Select
|
||||
@ -10,11 +12,24 @@ import {Et2Email} from "../Et2Email";
|
||||
*/
|
||||
// Stub global egw for cssImage to find
|
||||
// @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 = {
|
||||
ajaxUrl: () => "",
|
||||
app: () => "addressbook",
|
||||
decodePath: (_path : string) => _path,
|
||||
image: () => "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMzJweCIgaGVpZ2h0PSIzMnB4IiB2aWV3Qm94PSIwIDAgMzIgMzIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDMyIDMyIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjNjk2OTY5IiBkPSJNNi45NDMsMjguNDUzDQoJYzAuOTA2LDAuNzY1LDIuMDk3LDEuMTI3LDMuMjg2LDEuMTA5YzAuNDMsMC4wMTQsMC44NTItMC4wNjgsMS4yNjUtMC4yMDdjMC42NzktMC4xOCwxLjMyOC0wLjQ1LDEuODY2LTAuOTAyTDI5LjQwMywxNC45DQoJYzEuNzcyLTEuNDk4LDEuNzcyLTMuOTI1LDAtNS40MjJjLTEuNzcyLTEuNDk3LTQuNjQ2LTEuNDk3LTYuNDE4LDBMMTAuMTE5LDIwLjM0OWwtMi4zODktMi40MjRjLTEuNDQtMS40NTctMy43NzItMS40NTctNS4yMTIsMA0KCWMtMS40MzgsMS40Ni0xLjQzOCwzLjgyNSwwLDUuMjgxQzIuNTE4LDIzLjIwNiw1LjQ3NCwyNi45NDcsNi45NDMsMjguNDUzeiIvPg0KPC9zdmc+DQo=",
|
||||
jsonq: () => Promise.resolve({}),
|
||||
lang: i => i + "*",
|
||||
link: i => i,
|
||||
preference: i => "",
|
||||
request: () => Promise.resolve(testSuggestions),
|
||||
tooltipUnbind: () => {},
|
||||
webserverUrl: ""
|
||||
webserverUrl: "",
|
||||
uid: () => {return "" + (uid++);}
|
||||
};
|
||||
|
||||
let element : Et2Email;
|
||||
@ -52,7 +67,13 @@ describe("Email widget basics", () =>
|
||||
await elementUpdated(element);
|
||||
|
||||
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() =>
|
||||
{
|
||||
@ -67,8 +88,9 @@ describe("Email widget basics", () =>
|
||||
{
|
||||
element.addEventListener("sl-hide", resolve);
|
||||
});
|
||||
|
||||
await elementUpdated(element);
|
||||
element.focus();
|
||||
element.show();
|
||||
|
||||
await showPromise;
|
||||
await elementUpdated(element);
|
||||
@ -82,7 +104,57 @@ describe("Email widget basics", () =>
|
||||
|
||||
// Check that it actually closed dropdown
|
||||
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", () =>
|
||||
@ -107,21 +179,11 @@ describe("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
|
||||
const listener = oneEvent(element, "change");
|
||||
|
||||
// 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");
|
||||
removeButton.dispatchEvent(new Event("click"));
|
||||
|
||||
@ -129,14 +191,13 @@ describe("Tags", () =>
|
||||
|
||||
// Wait for widget to update
|
||||
await element.updateComplete;
|
||||
tag_updates = []
|
||||
element.select.combobox.querySelectorAll('et2-tag').forEach((t : Et2Tag) => tag_updates.push(t.updateComplete));
|
||||
let tag_updates = []
|
||||
element._tags.forEach((t : Et2EmailTag) => tag_updates.push(t.updateComplete));
|
||||
await Promise.all(tag_updates);
|
||||
|
||||
// Check
|
||||
assert.sameMembers(element.value, ["two"], "Removing tag did not remove value");
|
||||
tags = element.select.combobox.querySelectorAll('.select__tags et2-tag');
|
||||
assert.equal(tags.length, 1, "Removed tag is still there");
|
||||
assert.sameMembers(element.value, ["two@example.com"], "Removing tag did not remove value");
|
||||
assert.equal(element._tags.length, 1, "Removed tag is still there");
|
||||
});
|
||||
|
||||
});
|
||||
@ -146,4 +207,4 @@ inputBasicTests(async() =>
|
||||
const element = await before();
|
||||
element.noLang = true;
|
||||
return element
|
||||
}, "", "sl-select");
|
||||
}, "", "input");
|
@ -181,7 +181,7 @@ export class Et2EmailTag extends Et2Tag
|
||||
e.stopPropagation();
|
||||
|
||||
let extra = {
|
||||
'presets[email]': this.value
|
||||
'presets[email]': this.value ?? ""
|
||||
};
|
||||
|
||||
this.egw().open('', 'addressbook', 'add', extra);
|
||||
|
@ -76,7 +76,8 @@ describe('Et2EmailTag', () =>
|
||||
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() =>
|
||||
|
Loading…
Reference in New Issue
Block a user