@watermarkinsights/ripple 4.0.0-9 → 4.0.0
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/dist/cjs/{chartFunctions-33cb3097.js → chartFunctions-f5ded027.js} +1 -1
- package/dist/cjs/{functions-833ccc83.js → functions-e7db4a26.js} +67 -824
- package/dist/cjs/{global-d57c118b.js → global-b33cf49b.js} +1 -1
- package/dist/cjs/{intl-ab07bd0b.js → intl-9ef93563.js} +3 -3
- package/dist/cjs/loader.cjs.js +3 -3
- package/dist/cjs/priv-chart-popover.cjs.entry.js +1 -1
- package/dist/cjs/priv-datepicker.cjs.entry.js +1 -1
- package/dist/cjs/ripple.cjs.js +3 -3
- package/dist/cjs/wm-action-menu_2.cjs.entry.js +2 -2
- package/dist/cjs/wm-button.cjs.entry.js +1 -1
- package/dist/cjs/wm-chart.cjs.entry.js +4 -4
- package/dist/cjs/wm-datepicker.cjs.entry.js +1 -1
- package/dist/cjs/wm-file.cjs.entry.js +7 -4
- package/dist/cjs/wm-input.cjs.entry.js +4 -9
- package/dist/cjs/wm-line-chart.cjs.entry.js +3 -3
- package/dist/cjs/wm-modal-header.cjs.entry.js +2 -2
- package/dist/cjs/wm-modal.cjs.entry.js +1 -1
- package/dist/cjs/wm-navigation_3.cjs.entry.js +2 -2
- package/dist/cjs/wm-navigator.cjs.entry.js +1 -1
- package/dist/cjs/wm-option_2.cjs.entry.js +68 -119
- package/dist/cjs/wm-pagination.cjs.entry.js +1 -1
- package/dist/cjs/wm-progress-indicator_3.cjs.entry.js +4 -4
- package/dist/cjs/wm-search.cjs.entry.js +2 -2
- package/dist/cjs/wm-snackbar.cjs.entry.js +2 -2
- package/dist/cjs/wm-tab-item_3.cjs.entry.js +2 -2
- package/dist/cjs/wm-tag-input.cjs.entry.js +521 -617
- package/dist/cjs/wm-tag-option.cjs.entry.js +43 -0
- package/dist/cjs/wm-timepicker.cjs.entry.js +1 -1
- package/dist/cjs/wm-toggletip.cjs.entry.js +1 -1
- package/dist/cjs/wm-uploader.cjs.entry.js +2 -2
- package/dist/collection/collection-manifest.json +3 -3
- package/dist/collection/components/charts/wm-chart/wm-chart.css +0 -1
- package/dist/collection/components/charts/wm-progress-monitor/wm-progress-indicator.css +0 -1
- package/dist/collection/components/charts/wm-progress-monitor/wm-progress-monitor.css +9 -1
- package/dist/collection/components/wm-file/wm-file.js +23 -3
- package/dist/collection/components/wm-file/wm-file.spec.js +83 -34
- package/dist/collection/components/wm-file-list/wm-file-list.spec.js +32 -59
- package/dist/collection/components/wm-input/wm-input.js +1 -8
- package/dist/collection/components/wm-menuitem/wm-menuitem.js +1 -1
- package/dist/collection/components/wm-option/wm-option.css +6 -6
- package/dist/collection/components/wm-option/wm-option.js +47 -3
- package/dist/collection/components/wm-select/wm-select.e2e.js +60 -114
- package/dist/collection/components/wm-select/wm-select.js +80 -141
- package/dist/collection/components/wm-select/wm-select.spec.js +9 -11
- package/dist/collection/components/wm-tabs/wm-tab-list/wm-tab-list.css +0 -1
- package/dist/collection/components/wm-tag-input/wm-tag-input.css +19 -22
- package/dist/collection/components/wm-tag-input/wm-tag-input.e2e.js +3 -3
- package/dist/collection/components/wm-tag-input/wm-tag-input.js +597 -726
- package/dist/collection/components/wm-tag-input/wm-tag-option/wm-tag-option.js +241 -0
- package/dist/collection/components/wm-uploader/wm-uploader.e2e.js +26 -47
- package/dist/collection/components/wm-uploader/wm-uploader.js +3 -3
- package/dist/collection/components/wm-uploader/wm-uploader.spec.js +67 -140
- package/dist/collection/global/functions.js +22 -10
- package/dist/collection/global/intl.js +2 -2
- package/dist/collection/lang/lang.spec.js +2 -2
- package/dist/esm/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
- package/dist/esm/{functions-061ab506.js → functions-358a1a02.js} +66 -824
- package/dist/esm/{global-509460f7.js → global-ba03a879.js} +1 -1
- package/dist/esm/{intl-d698d52f.js → intl-48057c4d.js} +3 -3
- package/dist/esm/loader.js +3 -3
- package/dist/esm/polyfills/core-js.js +0 -0
- package/dist/esm/polyfills/dom.js +0 -0
- package/dist/esm/polyfills/es5-html-element.js +0 -0
- package/dist/esm/polyfills/index.js +0 -0
- package/dist/esm/polyfills/system.js +0 -0
- package/dist/esm/priv-chart-popover.entry.js +1 -1
- package/dist/esm/priv-datepicker.entry.js +1 -1
- package/dist/esm/ripple.js +3 -3
- package/dist/esm/wm-action-menu_2.entry.js +2 -2
- package/dist/esm/wm-button.entry.js +1 -1
- package/dist/esm/wm-chart.entry.js +4 -4
- package/dist/esm/wm-datepicker.entry.js +1 -1
- package/dist/esm/wm-file.entry.js +7 -4
- package/dist/esm/wm-input.entry.js +4 -9
- package/dist/esm/wm-line-chart.entry.js +3 -3
- package/dist/esm/wm-modal-header.entry.js +2 -2
- package/dist/esm/wm-modal.entry.js +1 -1
- package/dist/esm/wm-navigation_3.entry.js +2 -2
- package/dist/esm/wm-navigator.entry.js +1 -1
- package/dist/esm/wm-option_2.entry.js +68 -119
- package/dist/esm/wm-pagination.entry.js +1 -1
- package/dist/esm/wm-progress-indicator_3.entry.js +4 -4
- package/dist/esm/wm-search.entry.js +2 -2
- package/dist/esm/wm-snackbar.entry.js +2 -2
- package/dist/esm/wm-tab-item_3.entry.js +2 -2
- package/dist/esm/wm-tag-input.entry.js +522 -618
- package/dist/esm/wm-tag-option.entry.js +39 -0
- package/dist/esm/wm-timepicker.entry.js +1 -1
- package/dist/esm/wm-toggletip.entry.js +1 -1
- package/dist/esm/wm-uploader.entry.js +2 -2
- package/dist/esm-es5/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
- package/dist/esm-es5/functions-358a1a02.js +1 -0
- package/dist/esm-es5/global-ba03a879.js +1 -0
- package/dist/esm-es5/{intl-d698d52f.js → intl-48057c4d.js} +1 -1
- package/dist/esm-es5/loader.js +1 -1
- package/dist/esm-es5/priv-chart-popover.entry.js +1 -1
- package/dist/esm-es5/priv-datepicker.entry.js +1 -1
- package/dist/esm-es5/ripple.js +1 -1
- package/dist/esm-es5/wm-action-menu_2.entry.js +1 -1
- package/dist/esm-es5/wm-button.entry.js +1 -1
- package/dist/esm-es5/wm-chart.entry.js +1 -1
- package/dist/esm-es5/wm-datepicker.entry.js +1 -1
- package/dist/esm-es5/wm-file.entry.js +1 -1
- package/dist/esm-es5/wm-input.entry.js +1 -1
- package/dist/esm-es5/wm-line-chart.entry.js +1 -1
- package/dist/esm-es5/wm-modal-header.entry.js +1 -1
- package/dist/esm-es5/wm-modal.entry.js +1 -1
- package/dist/esm-es5/wm-navigation_3.entry.js +1 -1
- package/dist/esm-es5/wm-navigator.entry.js +1 -1
- package/dist/esm-es5/wm-option_2.entry.js +1 -1
- package/dist/esm-es5/wm-pagination.entry.js +1 -1
- package/dist/esm-es5/wm-progress-indicator_3.entry.js +1 -1
- package/dist/esm-es5/wm-search.entry.js +1 -1
- package/dist/esm-es5/wm-snackbar.entry.js +1 -1
- package/dist/esm-es5/wm-tab-item_3.entry.js +1 -1
- package/dist/esm-es5/wm-tag-input.entry.js +1 -1
- package/dist/esm-es5/wm-tag-option.entry.js +1 -0
- package/dist/esm-es5/wm-timepicker.entry.js +1 -1
- package/dist/esm-es5/wm-toggletip.entry.js +1 -1
- package/dist/esm-es5/wm-uploader.entry.js +1 -1
- package/dist/ripple/{p-3f159fa3.entry.js → p-05ef4092.entry.js} +1 -1
- package/dist/ripple/p-11d629cb.system.entry.js +1 -0
- package/dist/ripple/p-126fbcdb.entry.js +1 -0
- package/dist/ripple/p-12a140e0.system.entry.js +1 -0
- package/dist/ripple/{p-e61e2d7f.entry.js → p-191fafc6.entry.js} +1 -1
- package/dist/ripple/p-1ab62a21.system.entry.js +1 -0
- package/dist/ripple/{p-d8287161.entry.js → p-1e7e2ca4.entry.js} +1 -1
- package/dist/ripple/{p-fef28649.system.entry.js → p-1ee49e28.system.entry.js} +1 -1
- package/dist/ripple/{p-e82eae12.entry.js → p-299bf10c.entry.js} +1 -1
- package/dist/ripple/{p-c20c248a.entry.js → p-2d6bb6d7.entry.js} +1 -1
- package/dist/ripple/{p-a31e736a.entry.js → p-366a9608.entry.js} +1 -1
- package/dist/ripple/p-3a20b1ed.system.entry.js +1 -0
- package/dist/ripple/p-3bb79457.entry.js +1 -0
- package/dist/ripple/{p-1f7a67cc.system.js → p-426fa249.system.js} +1 -1
- package/dist/ripple/p-44d4705c.system.js +1 -0
- package/dist/ripple/p-492dd748.system.entry.js +1 -0
- package/dist/ripple/p-4aa8e2cf.entry.js +1 -0
- package/dist/ripple/{p-ff891d67.js → p-52f5ec85.js} +1 -1
- package/dist/ripple/{p-484d57e1.entry.js → p-546d5c1d.entry.js} +1 -1
- package/dist/ripple/{p-d231aed1.system.entry.js → p-585732f7.system.entry.js} +1 -1
- package/dist/ripple/p-6767b009.system.js +1 -0
- package/dist/ripple/{p-c6ba5d3d.system.entry.js → p-681c9539.system.entry.js} +1 -1
- package/dist/ripple/{p-d2c9264d.entry.js → p-68cade03.entry.js} +1 -1
- package/dist/ripple/{p-260fd686.system.entry.js → p-6c27afee.system.entry.js} +1 -1
- package/dist/ripple/{p-d108107c.entry.js → p-7740db9a.entry.js} +1 -1
- package/dist/ripple/{p-055d1c23.system.entry.js → p-7d005413.system.entry.js} +1 -1
- package/dist/ripple/{p-c9830db6.system.entry.js → p-7e2c2c46.system.entry.js} +1 -1
- package/dist/ripple/p-7fa84884.system.entry.js +1 -0
- package/dist/ripple/{p-9a3d8f0b.system.entry.js → p-8b143e9d.system.entry.js} +1 -1
- package/dist/ripple/{p-0790bfed.entry.js → p-8ea235b6.entry.js} +1 -1
- package/dist/ripple/{p-4eae76a6.entry.js → p-8fadf5dd.entry.js} +1 -1
- package/dist/ripple/{p-8df34bf3.system.entry.js → p-94c65a69.system.entry.js} +1 -1
- package/dist/ripple/{p-3bd6839a.entry.js → p-9690de6c.entry.js} +1 -1
- package/dist/ripple/p-acb0156f.system.entry.js +1 -0
- package/dist/ripple/p-ae7290c2.entry.js +1 -0
- package/dist/ripple/{p-030b527a.js → p-aea9a33a.js} +1 -1
- package/dist/ripple/p-b6e5408c.js +1 -0
- package/dist/ripple/p-b75c0973.system.js +1 -0
- package/dist/ripple/{p-21f73fee.system.entry.js → p-b858d526.system.entry.js} +1 -1
- package/dist/ripple/{p-40b5b7d1.system.entry.js → p-b92c2e16.system.entry.js} +1 -1
- package/dist/ripple/p-be79e95d.entry.js +1 -0
- package/dist/ripple/{p-b623fdc8.entry.js → p-bfff12b4.entry.js} +1 -1
- package/dist/ripple/{p-68d7cf2b.entry.js → p-c028f29c.entry.js} +1 -1
- package/dist/ripple/p-c19ed569.entry.js +1 -0
- package/dist/ripple/{p-f42031f5.system.js → p-c3da681d.system.js} +1 -1
- package/dist/ripple/{p-9b94467e.entry.js → p-c5105455.entry.js} +1 -1
- package/dist/ripple/{p-15457a4b.system.entry.js → p-c86a7f4d.system.entry.js} +1 -1
- package/dist/ripple/{p-b9283910.entry.js → p-db58d96b.entry.js} +1 -1
- package/dist/ripple/p-dd92850a.js +1 -0
- package/dist/ripple/p-e39e6c2b.entry.js +1 -0
- package/dist/ripple/{p-a8ea87d1.system.entry.js → p-ec831e59.system.entry.js} +1 -1
- package/dist/ripple/{p-f1029090.system.entry.js → p-ee51efe0.system.entry.js} +1 -1
- package/dist/ripple/{p-777ced5b.entry.js → p-eec01bbe.entry.js} +1 -1
- package/dist/ripple/{p-5ed1b0a2.system.entry.js → p-f339d590.system.entry.js} +1 -1
- package/dist/ripple/{p-5b593411.system.entry.js → p-f3407959.system.entry.js} +1 -1
- package/dist/ripple/{p-da727af8.system.entry.js → p-f3a374ff.system.entry.js} +1 -1
- package/dist/ripple/{p-867b20a9.system.entry.js → p-f43fda55.system.entry.js} +1 -1
- package/dist/ripple/ripple.esm.js +1 -1
- package/dist/ripple/ripple.js +1 -1
- package/dist/types/components/wm-file/wm-file.d.ts +1 -1
- package/dist/types/components/wm-input/wm-input.d.ts +0 -1
- package/dist/types/components/wm-option/wm-option.d.ts +2 -0
- package/dist/types/components/wm-select/wm-select.d.ts +7 -7
- package/dist/types/components/wm-tag-input/wm-tag-input.d.ts +65 -85
- package/dist/types/components/wm-tag-input/wm-tag-option/wm-tag-option.d.ts +18 -0
- package/dist/types/components/wm-uploader/wm-uploader.d.ts +1 -1
- package/dist/types/components.d.ts +30 -27
- package/dist/types/global/functions.d.ts +2 -1
- package/dist/types/global/intl.d.ts +2 -2
- package/package.json +1 -1
- package/dist/cjs/wm-tag-input-row.cjs.entry.js +0 -23
- package/dist/collection/components/wm-tag-input/wm-tag-input-row/wm-tag-input-row.js +0 -122
- package/dist/collection/components/wm-tag-input/wm-tag-input.spec.js +0 -1039
- package/dist/esm/wm-tag-input-row.entry.js +0 -19
- package/dist/esm-es5/functions-061ab506.js +0 -1
- package/dist/esm-es5/global-509460f7.js +0 -1
- package/dist/esm-es5/wm-tag-input-row.entry.js +0 -1
- package/dist/ripple/p-1c3ba701.system.entry.js +0 -1
- package/dist/ripple/p-4a8c95b9.system.entry.js +0 -1
- package/dist/ripple/p-5f2c09f6.entry.js +0 -1
- package/dist/ripple/p-647a4a4a.system.entry.js +0 -1
- package/dist/ripple/p-7011accc.entry.js +0 -1
- package/dist/ripple/p-707383d5.system.js +0 -1
- package/dist/ripple/p-7c2e47bc.system.entry.js +0 -1
- package/dist/ripple/p-839d7e0f.system.js +0 -1
- package/dist/ripple/p-928cc755.system.entry.js +0 -1
- package/dist/ripple/p-9888c825.js +0 -1
- package/dist/ripple/p-a5308115.js +0 -1
- package/dist/ripple/p-b45a2fc3.entry.js +0 -1
- package/dist/ripple/p-b4b57baf.system.entry.js +0 -1
- package/dist/ripple/p-c15f29e5.system.js +0 -1
- package/dist/ripple/p-d38882eb.entry.js +0 -1
- package/dist/ripple/p-d601c5a1.entry.js +0 -1
- package/dist/ripple/p-d68678d2.entry.js +0 -1
- package/dist/ripple/p-e703d9cd.entry.js +0 -1
- package/dist/ripple/p-eb0d569a.system.entry.js +0 -1
- package/dist/types/components/wm-tag-input/wm-tag-input-row/wm-tag-input-row.d.ts +0 -11
|
@@ -1,1039 +0,0 @@
|
|
|
1
|
-
import { newSpecPage } from "@stencil/core/testing";
|
|
2
|
-
import { TagInput } from "./wm-tag-input";
|
|
3
|
-
import * as globalFunctions from "../../global/functions";
|
|
4
|
-
// mock ResizeObserver
|
|
5
|
-
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
|
6
|
-
observe: jest.fn(),
|
|
7
|
-
unobserve: jest.fn(),
|
|
8
|
-
disconnect: jest.fn(),
|
|
9
|
-
}));
|
|
10
|
-
// mockComputedStyle, component measures the placeholder on render to properly position the input
|
|
11
|
-
global.getComputedStyle = jest
|
|
12
|
-
.fn()
|
|
13
|
-
.mockImplementation(() => ({ paddingLeft: "0px", paddingRight: "0px", marginLeft: "0px", marginRight: "0px" }));
|
|
14
|
-
describe("taginput", () => {
|
|
15
|
-
let page;
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
page = await newSpecPage({
|
|
18
|
-
components: [TagInput],
|
|
19
|
-
html: `<wm-tag-input id="input" label="label" options="one,two,three,four"></wm-tag-input>`,
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
it("builds", async () => {
|
|
23
|
-
expect(page.root).toMatchSnapshot();
|
|
24
|
-
});
|
|
25
|
-
it("has right aria roles", async () => {
|
|
26
|
-
page = await newSpecPage({
|
|
27
|
-
components: [TagInput],
|
|
28
|
-
html: `<wm-tag-input label="label" options="one,two,three,four" selected-tags="one,three" info="info text"></wm-tag-input>`,
|
|
29
|
-
});
|
|
30
|
-
const label = await page.root.shadowRoot.querySelector("label");
|
|
31
|
-
expect(label.textContent).toBe("label");
|
|
32
|
-
const input = await page.root.shadowRoot.querySelector("input");
|
|
33
|
-
expect(input).toEqualAttribute("role", "combobox");
|
|
34
|
-
expect(input).toEqualAttribute("aria-label", "label 50 characters allowed.");
|
|
35
|
-
const helpText = await page.root.shadowRoot.querySelector(".help-text");
|
|
36
|
-
expect(input).toEqualAttribute("aria-describedby", helpText.id);
|
|
37
|
-
const dropdown = await page.root.shadowRoot.querySelector(".dropdown");
|
|
38
|
-
expect(dropdown).toEqualAttribute("role", "listbox");
|
|
39
|
-
expect(dropdown).toHaveAttribute("aria-multiselectable");
|
|
40
|
-
const options = await page.root.shadowRoot.querySelectorAll(".option");
|
|
41
|
-
options.forEach((option) => {
|
|
42
|
-
expect(option).toEqualAttribute("role", "option");
|
|
43
|
-
});
|
|
44
|
-
const tagArea = await page.root.shadowRoot.querySelector(".tag-area");
|
|
45
|
-
expect(tagArea).toEqualAttribute("role", "listbox");
|
|
46
|
-
expect(tagArea).toEqualAttribute("aria-label", "label tag selection. Press Backspace or Delete to remove a tag.");
|
|
47
|
-
expect(tagArea).toEqualAttribute("aria-describedby", "info max-tags");
|
|
48
|
-
expect(tagArea).toEqualAttribute("aria-orientation", "horizontal");
|
|
49
|
-
const tags = await page.root.shadowRoot.querySelectorAll(".tag");
|
|
50
|
-
tags.forEach((tag) => {
|
|
51
|
-
expect(tag).toEqualAttribute("role", "option");
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
it("changes help text when options are not provided", async () => {
|
|
55
|
-
// not editable with options
|
|
56
|
-
page = await newSpecPage({
|
|
57
|
-
components: [TagInput],
|
|
58
|
-
html: `<wm-tag-input label="label" add-new="false" options="one,two,three"></wm-tag-input>`,
|
|
59
|
-
});
|
|
60
|
-
let helpText = await page.root.shadowRoot.querySelector(".help-text");
|
|
61
|
-
expect(helpText.textContent).toBe("Search and select a tag.");
|
|
62
|
-
// editable with options
|
|
63
|
-
page = await newSpecPage({
|
|
64
|
-
components: [TagInput],
|
|
65
|
-
html: `<wm-tag-input label="label" options="one,two,three"></wm-tag-input>`,
|
|
66
|
-
});
|
|
67
|
-
helpText = await page.root.shadowRoot.querySelector(".help-text");
|
|
68
|
-
expect(helpText.textContent).toBe("Search and select a tag. Press the Enter or Comma key to add a new tag.");
|
|
69
|
-
// editable without options
|
|
70
|
-
page = await newSpecPage({
|
|
71
|
-
components: [TagInput],
|
|
72
|
-
html: `<wm-tag-input label="label"></wm-tag-input>`,
|
|
73
|
-
});
|
|
74
|
-
helpText = await page.root.shadowRoot.querySelector(".help-text");
|
|
75
|
-
expect(helpText.textContent).toBe(" Press the Enter or Comma key to add a new tag.");
|
|
76
|
-
});
|
|
77
|
-
it("shows the appropriate default placeholder text", async () => {
|
|
78
|
-
// editable with options
|
|
79
|
-
await page.setContent(`<wm-tag-input label="label" options="one,two"></wm-tag-input>`);
|
|
80
|
-
let input = await page.root.shadowRoot.querySelector("input");
|
|
81
|
-
expect(input).toEqualAttribute("placeholder", "Add or search for a tag");
|
|
82
|
-
// editable without options
|
|
83
|
-
page = await newSpecPage({
|
|
84
|
-
components: [TagInput],
|
|
85
|
-
html: `<wm-tag-input label="label"></wm-tag-input>`,
|
|
86
|
-
});
|
|
87
|
-
input = await page.root.shadowRoot.querySelector("input");
|
|
88
|
-
expect(input).toEqualAttribute("placeholder", "Add a new tag");
|
|
89
|
-
// not editable
|
|
90
|
-
page = await newSpecPage({
|
|
91
|
-
components: [TagInput],
|
|
92
|
-
html: `<wm-tag-input label="label" add-new="false" options="one,two,three"></wm-tag-input>`,
|
|
93
|
-
});
|
|
94
|
-
input = await page.root.shadowRoot.querySelector("input");
|
|
95
|
-
expect(input).toEqualAttribute("placeholder", "Search and select a tag");
|
|
96
|
-
});
|
|
97
|
-
it("shows options in original case", async () => {
|
|
98
|
-
await page.setContent('<wm-tag-input label="label" options="one two, Three four, five Six, sEVen, eight nine ten" selected-tags="one two, Three four, five Six, sEVen,eight nine ten"></wm-tag-input>');
|
|
99
|
-
const tags = page.root.shadowRoot.querySelectorAll(".tag");
|
|
100
|
-
expect(tags[0].dataset.tag).toBe("one two");
|
|
101
|
-
expect(tags[1].dataset.tag).toBe("Three four");
|
|
102
|
-
expect(tags[2].dataset.tag).toBe("five Six");
|
|
103
|
-
expect(tags[3].dataset.tag).toBe("sEVen");
|
|
104
|
-
expect(tags[4].dataset.tag).toBe("eight nine ten");
|
|
105
|
-
});
|
|
106
|
-
it("alphabetizes list items", async () => {
|
|
107
|
-
await page.setContent('<wm-tag-input label="label" options="C, B, E, D, F, A"></wm-tag-input>');
|
|
108
|
-
// List items appear in alphabetical orderconst listItems = page.root!.shadowRoot!.querySelectorAll(".option");
|
|
109
|
-
const listItems = page.root.shadowRoot.querySelectorAll(".option");
|
|
110
|
-
expect(listItems[0].textContent).toBe("A");
|
|
111
|
-
expect(listItems[1].textContent).toBe("B");
|
|
112
|
-
expect(listItems[2].textContent).toBe("C");
|
|
113
|
-
expect(listItems[3].textContent).toBe("D");
|
|
114
|
-
expect(listItems[4].textContent).toBe("E");
|
|
115
|
-
expect(listItems[5].textContent).toBe("F");
|
|
116
|
-
});
|
|
117
|
-
it("handles different casing of identical options", async () => {
|
|
118
|
-
await page.setContent(`<wm-tag-input label="label" options="one,two,three" selected-tags="oNE,tWO,thREe"></wm-tag-input>`);
|
|
119
|
-
const listItems = page.root.shadowRoot.querySelectorAll(".option");
|
|
120
|
-
const tags = page.root.shadowRoot.querySelectorAll(".tag");
|
|
121
|
-
expect(listItems.length).toBe(3);
|
|
122
|
-
expect(tags.length).toBe(3);
|
|
123
|
-
});
|
|
124
|
-
it("consolidates pre-selected tags into the options", async () => {
|
|
125
|
-
await page.setContent(`<wm-tag-input label="label" selected-tags="a,b,c"></wm-tag-input>`);
|
|
126
|
-
const listItems = page.root.shadowRoot.querySelectorAll(".option");
|
|
127
|
-
expect(listItems.length).toBe(3);
|
|
128
|
-
expect(page.root.options).toBe("a,b,c");
|
|
129
|
-
expect(listItems[0].textContent).toBe("a");
|
|
130
|
-
expect(listItems[1].textContent).toBe("b");
|
|
131
|
-
expect(listItems[2].textContent).toBe("c");
|
|
132
|
-
});
|
|
133
|
-
it("reflects selected tags", async () => {
|
|
134
|
-
const component = new TagInput();
|
|
135
|
-
const mockListToCSV = (component.listToCSV = jest.fn());
|
|
136
|
-
const mockWmTagInputChanged = (component.wmTagInputChanged.emit = jest.fn());
|
|
137
|
-
const tagsList = ["one", "two", "three"];
|
|
138
|
-
component.tagsList = tagsList;
|
|
139
|
-
component.reflectSelectedTags(tagsList, ["one", "two"]);
|
|
140
|
-
expect(mockListToCSV).toHaveBeenCalledTimes(1);
|
|
141
|
-
expect(mockListToCSV).toHaveBeenLastCalledWith(tagsList);
|
|
142
|
-
expect(mockWmTagInputChanged).toHaveBeenCalledTimes(1);
|
|
143
|
-
expect(mockWmTagInputChanged).toHaveBeenLastCalledWith({
|
|
144
|
-
value: tagsList,
|
|
145
|
-
tagChanged: "three",
|
|
146
|
-
});
|
|
147
|
-
jest.restoreAllMocks();
|
|
148
|
-
});
|
|
149
|
-
it("checks case insensitive list inclusion", async () => {
|
|
150
|
-
// includesCaseInsensitive
|
|
151
|
-
const component = new TagInput();
|
|
152
|
-
const testArray = ["One", "TWO", "three", "fOUr and FIve", "s I x"];
|
|
153
|
-
expect(component.includesCaseInsensitive(testArray, "one")).toBe(true);
|
|
154
|
-
expect(component.includesCaseInsensitive(testArray, "oNe")).toBe(true);
|
|
155
|
-
expect(component.includesCaseInsensitive(testArray, "seven")).toBe(false);
|
|
156
|
-
});
|
|
157
|
-
it("filters case insensitive strings from arrays", async () => {
|
|
158
|
-
// filterCaseInsensitive
|
|
159
|
-
const component = new TagInput();
|
|
160
|
-
const testArray = ["One", "TWO", "three", "fOUr and FIve", "s I x"];
|
|
161
|
-
const answers = [
|
|
162
|
-
["TWO", "three", "fOUr and FIve", "s I x"],
|
|
163
|
-
["One", "three", "fOUr and FIve", "s I x"],
|
|
164
|
-
["One", "TWO", "fOUr and FIve", "s I x"],
|
|
165
|
-
["One", "TWO", "three", "s I x"],
|
|
166
|
-
["One", "TWO", "three", "fOUr and FIve"],
|
|
167
|
-
];
|
|
168
|
-
testArray.forEach((str, idx) => {
|
|
169
|
-
const lowercaseWord = str.toLowerCase();
|
|
170
|
-
expect(component.filterCaseInsensitive(testArray, lowercaseWord)).toStrictEqual(answers[idx]);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
it("throws error if no label prop is passed", async () => {
|
|
174
|
-
const mockConsoleError = (console.error = jest.fn());
|
|
175
|
-
await page.setContent(`<wm-tag-input></wm-tag-input>`);
|
|
176
|
-
expect(mockConsoleError).toHaveBeenCalledWith("wm-tag-input must have a label property");
|
|
177
|
-
jest.restoreAllMocks();
|
|
178
|
-
});
|
|
179
|
-
describe("handles user keys", () => {
|
|
180
|
-
describe("handles input keys", () => {
|
|
181
|
-
afterEach(() => {
|
|
182
|
-
jest.restoreAllMocks();
|
|
183
|
-
});
|
|
184
|
-
it("handles input key down", async () => {
|
|
185
|
-
// handleInputKeyDown
|
|
186
|
-
const component = new TagInput();
|
|
187
|
-
const mockPreventDefault = jest.fn();
|
|
188
|
-
const mockStopPropagation = jest.fn();
|
|
189
|
-
const event = {
|
|
190
|
-
key: "",
|
|
191
|
-
preventDefault: mockPreventDefault,
|
|
192
|
-
stopPropagation: mockStopPropagation,
|
|
193
|
-
};
|
|
194
|
-
//@ts-ignore
|
|
195
|
-
component.inputEl = { value: "new tag" };
|
|
196
|
-
// Enter
|
|
197
|
-
const mockHandleInputSubmit = (component.submitInput = jest.fn());
|
|
198
|
-
event.key = "Enter";
|
|
199
|
-
component.handleInputKeyDown(event);
|
|
200
|
-
expect(mockStopPropagation).toHaveBeenCalledTimes(1);
|
|
201
|
-
expect(mockHandleInputSubmit).toHaveBeenCalledTimes(1);
|
|
202
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
203
|
-
jest.clearAllMocks();
|
|
204
|
-
// mock listItemEls getter
|
|
205
|
-
jest.spyOn(component, "listItemEls", "get").mockReturnValue([{}]);
|
|
206
|
-
// ArrowDown
|
|
207
|
-
const mockHandleInputArrowDown = (component.handleInputArrowDown = jest.fn());
|
|
208
|
-
event.key = "ArrowDown";
|
|
209
|
-
component.handleInputKeyDown(event);
|
|
210
|
-
expect(mockHandleInputArrowDown).toHaveBeenCalledTimes(1);
|
|
211
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
212
|
-
jest.clearAllMocks();
|
|
213
|
-
// ArrowUp
|
|
214
|
-
const mockHandleInputArrowUp = (component.handleInputArrowUp = jest.fn());
|
|
215
|
-
event.key = "ArrowUp";
|
|
216
|
-
component.handleInputKeyDown(event);
|
|
217
|
-
expect(mockHandleInputArrowUp).toHaveBeenCalledTimes(1);
|
|
218
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
219
|
-
jest.clearAllMocks();
|
|
220
|
-
// Escape
|
|
221
|
-
const spyCloseDropdown = jest.spyOn(component, "closeDropdown");
|
|
222
|
-
jest.spyOn(component, "clearListItemFocus").mockImplementation(() => { });
|
|
223
|
-
event.key = "Escape";
|
|
224
|
-
component.isExpanded = true;
|
|
225
|
-
component.handleInputKeyDown(event);
|
|
226
|
-
expect(spyCloseDropdown).toHaveBeenCalledTimes(1);
|
|
227
|
-
jest.clearAllMocks();
|
|
228
|
-
// Backspace
|
|
229
|
-
const mockHandleInputBackspace = (component.handleInputBackspace = jest.fn());
|
|
230
|
-
event.key = "Backspace";
|
|
231
|
-
component.handleInputKeyDown(event);
|
|
232
|
-
expect(mockHandleInputBackspace).toHaveBeenCalledTimes(1);
|
|
233
|
-
jest.restoreAllMocks();
|
|
234
|
-
});
|
|
235
|
-
it("handles input change", async () => {
|
|
236
|
-
// handleInputChanged
|
|
237
|
-
const component = new TagInput();
|
|
238
|
-
const mockClearListItemFocus = (component.clearListItemFocus = jest.fn());
|
|
239
|
-
const mockGenerateCharacterLimitWarning = (component.generateCharacterLimitWarning = jest.fn());
|
|
240
|
-
component.announce = jest.fn();
|
|
241
|
-
const mockAnnounceExistingOptions = (component.announceExistingOptions = jest.fn());
|
|
242
|
-
const mockOpenDropdown = (component.openDropdown = jest.fn());
|
|
243
|
-
component.handleInputChanged("word");
|
|
244
|
-
expect(component.charCount).toBe("word".length);
|
|
245
|
-
expect(mockClearListItemFocus).toHaveBeenCalledTimes(1);
|
|
246
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(1);
|
|
247
|
-
expect(mockAnnounceExistingOptions).toHaveBeenCalledTimes(1);
|
|
248
|
-
expect(mockGenerateCharacterLimitWarning).toHaveBeenCalledTimes(0);
|
|
249
|
-
jest.clearAllMocks();
|
|
250
|
-
component.characterLimit = 3;
|
|
251
|
-
component.isExpanded = true;
|
|
252
|
-
component.handleInputChanged("more than 3 characters");
|
|
253
|
-
expect(mockClearListItemFocus).toHaveBeenCalledTimes(1);
|
|
254
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(0);
|
|
255
|
-
expect(mockAnnounceExistingOptions).toHaveBeenCalledTimes(1);
|
|
256
|
-
expect(mockGenerateCharacterLimitWarning).toHaveBeenCalledTimes(1);
|
|
257
|
-
jest.restoreAllMocks();
|
|
258
|
-
});
|
|
259
|
-
it("handles input arrow down", async () => {
|
|
260
|
-
// handleInputArrowDown
|
|
261
|
-
const component = new TagInput();
|
|
262
|
-
const mockOpenDropdown = (component.openDropdown = jest.fn());
|
|
263
|
-
const mockMoveDownListItem = (component.moveDownListItem = jest.fn());
|
|
264
|
-
component.isExpanded = false;
|
|
265
|
-
component.handleInputArrowDown();
|
|
266
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(1);
|
|
267
|
-
expect(mockMoveDownListItem).toHaveBeenCalledTimes(0);
|
|
268
|
-
jest.clearAllMocks();
|
|
269
|
-
component.isExpanded = true;
|
|
270
|
-
component.handleInputArrowDown();
|
|
271
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(0);
|
|
272
|
-
expect(mockMoveDownListItem).toHaveBeenCalledTimes(1);
|
|
273
|
-
jest.restoreAllMocks();
|
|
274
|
-
});
|
|
275
|
-
it("handles input arrow up", async () => {
|
|
276
|
-
// handleInputArrowUp
|
|
277
|
-
const component = new TagInput();
|
|
278
|
-
const mockOpenDropdown = (component.openDropdown = jest.fn());
|
|
279
|
-
const mockMoveUpListItem = (component.moveUpListItem = jest.fn());
|
|
280
|
-
component.isExpanded = false;
|
|
281
|
-
component.handleInputArrowUp();
|
|
282
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(1);
|
|
283
|
-
expect(mockMoveUpListItem).toHaveBeenCalledTimes(0);
|
|
284
|
-
jest.clearAllMocks();
|
|
285
|
-
component.isExpanded = true;
|
|
286
|
-
component.handleInputArrowUp();
|
|
287
|
-
expect(mockOpenDropdown).toHaveBeenCalledTimes(0);
|
|
288
|
-
expect(mockMoveUpListItem).toHaveBeenCalledTimes(1);
|
|
289
|
-
jest.restoreAllMocks();
|
|
290
|
-
});
|
|
291
|
-
it("handles input submit", async () => {
|
|
292
|
-
// submitInput
|
|
293
|
-
const component = new TagInput();
|
|
294
|
-
const mockAddTag = (component.addTag = jest.fn(() => ["first", "second"]));
|
|
295
|
-
const mockAddOption = (component.addOption = jest.fn());
|
|
296
|
-
const mockResetInput = (component.resetInput = jest.fn());
|
|
297
|
-
let canAddNew = true;
|
|
298
|
-
component.submitInput(canAddNew, "new tag");
|
|
299
|
-
expect(mockAddTag).toHaveBeenCalledTimes(1);
|
|
300
|
-
expect(mockAddOption).toHaveBeenCalledTimes(1);
|
|
301
|
-
expect(mockResetInput).toHaveBeenCalledTimes(1);
|
|
302
|
-
expect((component.charCount = 0));
|
|
303
|
-
jest.clearAllMocks();
|
|
304
|
-
component.submitInput(canAddNew, "");
|
|
305
|
-
expect(mockAddTag).toHaveBeenCalledTimes(0);
|
|
306
|
-
expect(mockAddOption).toHaveBeenCalledTimes(0);
|
|
307
|
-
expect(mockResetInput).toHaveBeenCalledTimes(0);
|
|
308
|
-
jest.clearAllMocks();
|
|
309
|
-
component.maxTags = 3;
|
|
310
|
-
component.submitInput(canAddNew, "new tag");
|
|
311
|
-
expect(mockAddTag).toHaveBeenCalledTimes(1);
|
|
312
|
-
expect(mockAddOption).toHaveBeenCalledTimes(1);
|
|
313
|
-
expect(mockResetInput).toHaveBeenCalledTimes(1);
|
|
314
|
-
jest.clearAllMocks();
|
|
315
|
-
component.maxTags = 2;
|
|
316
|
-
component.submitInput(canAddNew, "new tag");
|
|
317
|
-
expect(mockAddTag).toHaveBeenCalledTimes(1);
|
|
318
|
-
expect(mockAddOption).toHaveBeenCalledTimes(1);
|
|
319
|
-
expect(mockResetInput).toHaveBeenCalledTimes(1);
|
|
320
|
-
jest.clearAllMocks();
|
|
321
|
-
canAddNew = false;
|
|
322
|
-
component.submitInput(canAddNew, "new tag");
|
|
323
|
-
expect(mockAddTag).toHaveBeenCalledTimes(0);
|
|
324
|
-
expect(mockAddOption).toHaveBeenCalledTimes(0);
|
|
325
|
-
expect(mockResetInput).toHaveBeenCalledTimes(0);
|
|
326
|
-
jest.restoreAllMocks();
|
|
327
|
-
});
|
|
328
|
-
it("handles input backspace", async () => {
|
|
329
|
-
// handleInputBackspace
|
|
330
|
-
const component = new TagInput();
|
|
331
|
-
const mockFocus = jest.fn();
|
|
332
|
-
const tagAreaEl = { focus: mockFocus };
|
|
333
|
-
jest.spyOn(component, "focusTag").mockImplementation(() => { });
|
|
334
|
-
const mockRequestAnimationFrame = jest
|
|
335
|
-
.spyOn(window, "requestAnimationFrame")
|
|
336
|
-
//@ts-ignore
|
|
337
|
-
.mockImplementation((cb) => cb());
|
|
338
|
-
jest.spyOn(component, "tagEls", "get").mockReturnValue([{}]);
|
|
339
|
-
//@ts-ignore
|
|
340
|
-
component.tagAreaEl = tagAreaEl;
|
|
341
|
-
//@ts-ignore
|
|
342
|
-
component.inputEl = { value: "new tag" };
|
|
343
|
-
component.tagsList = ["one", "two"];
|
|
344
|
-
component.handleInputBackspace();
|
|
345
|
-
expect(mockRequestAnimationFrame).toHaveBeenCalledTimes(0);
|
|
346
|
-
expect(mockFocus).toHaveBeenCalledTimes(0);
|
|
347
|
-
//@ts-ignore
|
|
348
|
-
component.inputEl = { value: "" };
|
|
349
|
-
component.handleInputBackspace();
|
|
350
|
-
expect(mockRequestAnimationFrame).toHaveBeenCalledTimes(1);
|
|
351
|
-
expect(mockFocus).toHaveBeenCalledTimes(1);
|
|
352
|
-
jest.restoreAllMocks();
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
describe("handles list item keys", () => {
|
|
356
|
-
afterEach(() => {
|
|
357
|
-
jest.restoreAllMocks();
|
|
358
|
-
});
|
|
359
|
-
it("handles list item click", async () => {
|
|
360
|
-
// handleListItemClick
|
|
361
|
-
const component = new TagInput();
|
|
362
|
-
let fooEl = document.createElement("li");
|
|
363
|
-
fooEl.dataset.option = "two";
|
|
364
|
-
//@ts-ignore
|
|
365
|
-
const event = { target: fooEl };
|
|
366
|
-
const mockAnnounce = (component.announce = jest.fn());
|
|
367
|
-
const mockResetInput = (component.resetInput = jest.fn());
|
|
368
|
-
const mockAddTag = (component.addTag = jest.fn());
|
|
369
|
-
const mockAddOption = (component.addOption = jest.fn());
|
|
370
|
-
component.tagsList = ["one", "two"];
|
|
371
|
-
component.handleListItemClick(event.target);
|
|
372
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
373
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("two has already been added.");
|
|
374
|
-
expect(mockResetInput).toHaveBeenCalledTimes(0);
|
|
375
|
-
expect(mockAddTag).toHaveBeenCalledTimes(0);
|
|
376
|
-
expect(mockAddOption).toHaveBeenCalledTimes(0);
|
|
377
|
-
jest.clearAllMocks();
|
|
378
|
-
component.tagsList = ["one"];
|
|
379
|
-
component.handleListItemClick(event.target);
|
|
380
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(0);
|
|
381
|
-
expect(mockResetInput).toHaveBeenCalledTimes(1);
|
|
382
|
-
expect(mockAddTag).toHaveBeenCalledTimes(1);
|
|
383
|
-
expect(mockAddOption).toHaveBeenCalledTimes(1);
|
|
384
|
-
expect(component.focusedElement).toBeUndefined();
|
|
385
|
-
jest.restoreAllMocks();
|
|
386
|
-
});
|
|
387
|
-
it("handles list item key down", async () => {
|
|
388
|
-
// handleListItemKeyDown
|
|
389
|
-
const component = new TagInput();
|
|
390
|
-
const mockTargetClick = jest.fn();
|
|
391
|
-
const evTarget = { click: mockTargetClick };
|
|
392
|
-
const mockMoveDownListItem = (component.moveDownListItem = jest.fn());
|
|
393
|
-
const mockMoveUpListItem = (component.moveUpListItem = jest.fn());
|
|
394
|
-
const mockFocus = jest.fn();
|
|
395
|
-
//@ts-ignore
|
|
396
|
-
const inputEl = { focus: () => { } };
|
|
397
|
-
// @ts-ignore
|
|
398
|
-
component.inputEl = inputEl;
|
|
399
|
-
const mockCloseDropdown = (component.closeDropdown = jest.fn());
|
|
400
|
-
const mockPreventDefault = jest.fn();
|
|
401
|
-
let event = {
|
|
402
|
-
key: "",
|
|
403
|
-
target: evTarget,
|
|
404
|
-
preventDefault: mockPreventDefault,
|
|
405
|
-
};
|
|
406
|
-
// Enter
|
|
407
|
-
event.key = "Enter";
|
|
408
|
-
// @ts-ignore
|
|
409
|
-
component.handleListItemKeyDown(event);
|
|
410
|
-
expect(mockTargetClick).toHaveBeenCalledTimes(1);
|
|
411
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
412
|
-
jest.clearAllMocks();
|
|
413
|
-
// Space
|
|
414
|
-
event.key = " ";
|
|
415
|
-
// @ts-ignore
|
|
416
|
-
component.handleListItemKeyDown(event);
|
|
417
|
-
expect(mockTargetClick).toHaveBeenCalledTimes(1);
|
|
418
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
419
|
-
jest.clearAllMocks();
|
|
420
|
-
// ArrowDown
|
|
421
|
-
event.key = "ArrowDown";
|
|
422
|
-
// @ts-ignore
|
|
423
|
-
component.handleListItemKeyDown(event);
|
|
424
|
-
expect(mockMoveDownListItem).toHaveBeenCalledTimes(1);
|
|
425
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
426
|
-
jest.clearAllMocks();
|
|
427
|
-
// ArrowUp
|
|
428
|
-
event.key = "ArrowUp";
|
|
429
|
-
// @ts-ignore
|
|
430
|
-
component.handleListItemKeyDown(event);
|
|
431
|
-
expect(mockMoveUpListItem).toHaveBeenCalledTimes(1);
|
|
432
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
433
|
-
jest.clearAllMocks();
|
|
434
|
-
// Escape
|
|
435
|
-
event.key = "Escape";
|
|
436
|
-
// @ts-ignore
|
|
437
|
-
component.inputEl = { focus: mockFocus };
|
|
438
|
-
// @ts-ignore
|
|
439
|
-
component.handleListItemKeyDown(event);
|
|
440
|
-
expect(mockFocus).toHaveBeenCalledTimes(1);
|
|
441
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(0);
|
|
442
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(0);
|
|
443
|
-
jest.clearAllMocks();
|
|
444
|
-
// @ts-ignore
|
|
445
|
-
component.inputEl = inputEl;
|
|
446
|
-
jest.spyOn(component, "focusedElement", "get").mockReturnValue(inputEl);
|
|
447
|
-
// @ts-ignore
|
|
448
|
-
component.handleListItemKeyDown(event);
|
|
449
|
-
expect(mockFocus).toHaveBeenCalledTimes(0);
|
|
450
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
|
451
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(0);
|
|
452
|
-
jest.restoreAllMocks();
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
describe("handles tag area keys", () => {
|
|
456
|
-
afterEach(() => {
|
|
457
|
-
jest.restoreAllMocks();
|
|
458
|
-
});
|
|
459
|
-
it("handles tag area key down", async () => {
|
|
460
|
-
// handleTagAreaKeyDown
|
|
461
|
-
const component = new TagInput();
|
|
462
|
-
const mockMoveLeftTag = (component.moveLeftTag = jest.fn());
|
|
463
|
-
const mockMoveRightTag = (component.moveRightTag = jest.fn());
|
|
464
|
-
const mockHandleTagAreaDelete = (component.handleTagAreaDelete = jest.fn());
|
|
465
|
-
const mockPreventDefault = jest.fn();
|
|
466
|
-
let event = { key: "", preventDefault: mockPreventDefault };
|
|
467
|
-
// ArrowLeft
|
|
468
|
-
event.key = "ArrowLeft";
|
|
469
|
-
//@ts-ignore
|
|
470
|
-
component.handleTagAreaKeyDown(event);
|
|
471
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(1);
|
|
472
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(0);
|
|
473
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(0);
|
|
474
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
475
|
-
jest.clearAllMocks();
|
|
476
|
-
// ArrowUp
|
|
477
|
-
event.key = "ArrowUp";
|
|
478
|
-
//@ts-ignore
|
|
479
|
-
component.handleTagAreaKeyDown(event);
|
|
480
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(1);
|
|
481
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(0);
|
|
482
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(0);
|
|
483
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
484
|
-
jest.clearAllMocks();
|
|
485
|
-
// ArrowRight
|
|
486
|
-
event.key = "ArrowRight";
|
|
487
|
-
//@ts-ignore
|
|
488
|
-
component.handleTagAreaKeyDown(event);
|
|
489
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(0);
|
|
490
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(1);
|
|
491
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(0);
|
|
492
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
493
|
-
jest.clearAllMocks();
|
|
494
|
-
// ArrowDown
|
|
495
|
-
event.key = "ArrowDown";
|
|
496
|
-
//@ts-ignore
|
|
497
|
-
component.handleTagAreaKeyDown(event);
|
|
498
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(0);
|
|
499
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(1);
|
|
500
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(0);
|
|
501
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(1);
|
|
502
|
-
jest.clearAllMocks();
|
|
503
|
-
// Backspace
|
|
504
|
-
event.key = "Backspace";
|
|
505
|
-
//@ts-ignore
|
|
506
|
-
component.handleTagAreaKeyDown(event);
|
|
507
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(0);
|
|
508
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(0);
|
|
509
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(1);
|
|
510
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(0);
|
|
511
|
-
jest.clearAllMocks();
|
|
512
|
-
// Delete
|
|
513
|
-
event.key = "Delete";
|
|
514
|
-
//@ts-ignore
|
|
515
|
-
component.handleTagAreaKeyDown(event);
|
|
516
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(0);
|
|
517
|
-
expect(mockMoveRightTag).toHaveBeenCalledTimes(0);
|
|
518
|
-
expect(mockHandleTagAreaDelete).toHaveBeenCalledTimes(1);
|
|
519
|
-
expect(mockPreventDefault).toHaveBeenCalledTimes(0);
|
|
520
|
-
jest.clearAllMocks();
|
|
521
|
-
jest.restoreAllMocks();
|
|
522
|
-
});
|
|
523
|
-
it("handles tag area delete", async () => {
|
|
524
|
-
// handleTagAreaDelete
|
|
525
|
-
const component = new TagInput();
|
|
526
|
-
const mockRemoveTag = (component.removeTag = jest.fn());
|
|
527
|
-
let element1 = document.createElement("li");
|
|
528
|
-
element1.dataset.tag = "one";
|
|
529
|
-
let element2 = document.createElement("li");
|
|
530
|
-
element2.dataset.tag = "two";
|
|
531
|
-
jest.spyOn(component, "tagEls", "get").mockReturnValue([element1, element2]);
|
|
532
|
-
component.tagsList = ["one", "two"];
|
|
533
|
-
const mockInputFocus = jest.fn();
|
|
534
|
-
const mockFocusTag = (component.focusTag = jest.fn());
|
|
535
|
-
// @ts-ignore
|
|
536
|
-
component.inputEl = { focus: mockInputFocus };
|
|
537
|
-
component.focusedTag = element1;
|
|
538
|
-
component.handleTagAreaDelete();
|
|
539
|
-
expect(mockRemoveTag).toHaveBeenCalledTimes(1);
|
|
540
|
-
expect(component.focusedTag).toBe(element1);
|
|
541
|
-
expect(mockInputFocus).toHaveBeenCalledTimes(0);
|
|
542
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(1);
|
|
543
|
-
jest.clearAllMocks();
|
|
544
|
-
component.focusedTag = element2;
|
|
545
|
-
component.tagsList = [];
|
|
546
|
-
component.handleTagAreaDelete();
|
|
547
|
-
expect(mockRemoveTag).toHaveBeenCalledTimes(1);
|
|
548
|
-
expect(mockInputFocus).toHaveBeenCalledTimes(1);
|
|
549
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(0);
|
|
550
|
-
jest.clearAllMocks();
|
|
551
|
-
component.focusedTag = element2;
|
|
552
|
-
component.tagsList = ["one", "two"];
|
|
553
|
-
component.handleTagAreaDelete();
|
|
554
|
-
expect(mockRemoveTag).toHaveBeenCalledTimes(1);
|
|
555
|
-
expect(mockInputFocus).toHaveBeenCalledTimes(0);
|
|
556
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(1);
|
|
557
|
-
expect(component.focusedTag).toBe(element1);
|
|
558
|
-
jest.clearAllMocks();
|
|
559
|
-
component.focusedTag = null;
|
|
560
|
-
component.handleTagAreaDelete();
|
|
561
|
-
expect(mockRemoveTag).toHaveBeenCalledTimes(0);
|
|
562
|
-
expect(mockInputFocus).toHaveBeenCalledTimes(0);
|
|
563
|
-
expect(component.focusedTag).toBe(null);
|
|
564
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(0);
|
|
565
|
-
jest.clearAllMocks();
|
|
566
|
-
jest.restoreAllMocks();
|
|
567
|
-
});
|
|
568
|
-
});
|
|
569
|
-
});
|
|
570
|
-
describe("manages focus", () => {
|
|
571
|
-
it("handles blur of focusable elements", () => {
|
|
572
|
-
// handleBlur
|
|
573
|
-
const component = new TagInput();
|
|
574
|
-
const element1 = {};
|
|
575
|
-
const element2 = {};
|
|
576
|
-
const event = { relatedTarget: element1 };
|
|
577
|
-
const mockDismissTooltip = (component.dismissTooltip = jest.fn());
|
|
578
|
-
const mockClearCellFocus = (component.clearCellFocus = jest.fn());
|
|
579
|
-
const mockCloseDropdown = (component.closeDropdown = jest.fn());
|
|
580
|
-
const div = document.createElement("div");
|
|
581
|
-
div.classList.add("focused");
|
|
582
|
-
// @ts-ignore
|
|
583
|
-
component.fieldWrapperEl = div;
|
|
584
|
-
component.handleBlur(event, element1);
|
|
585
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(0);
|
|
586
|
-
expect(mockDismissTooltip).toHaveBeenCalledTimes(1);
|
|
587
|
-
expect(mockClearCellFocus).toHaveBeenCalledTimes(1);
|
|
588
|
-
// @ts-ignore
|
|
589
|
-
expect(component.fieldWrapperEl).toHaveClass("focused");
|
|
590
|
-
component.handleBlur(event, element2);
|
|
591
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
|
592
|
-
expect(mockDismissTooltip).toHaveBeenCalledTimes(2);
|
|
593
|
-
expect(mockClearCellFocus).toHaveBeenCalledTimes(2);
|
|
594
|
-
// @ts-ignore
|
|
595
|
-
expect(component.fieldWrapperEl).not.toHaveClass("focused");
|
|
596
|
-
jest.restoreAllMocks();
|
|
597
|
-
});
|
|
598
|
-
it("handles focus of tag area", async () => {
|
|
599
|
-
// handleTagAreaFocus
|
|
600
|
-
const component = new TagInput();
|
|
601
|
-
const mockCloseDropdown = (component.closeDropdown = jest.fn());
|
|
602
|
-
const mockFocusTag = (component.focusTag = jest.fn());
|
|
603
|
-
const liElement1 = {};
|
|
604
|
-
const liElement2 = {};
|
|
605
|
-
jest.spyOn(component, "tagEls", "get").mockReturnValue([liElement1]);
|
|
606
|
-
jest.spyOn(component, "nonLockedTagEls", "get").mockReturnValue([liElement1]);
|
|
607
|
-
component.focusedTag = null;
|
|
608
|
-
component.handleTagAreaFocus();
|
|
609
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
|
610
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(1);
|
|
611
|
-
expect(mockFocusTag).toHaveBeenLastCalledWith(liElement1);
|
|
612
|
-
mockCloseDropdown.mockClear();
|
|
613
|
-
mockFocusTag.mockClear();
|
|
614
|
-
component.focusedTag = liElement2;
|
|
615
|
-
component.handleTagAreaFocus();
|
|
616
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
|
617
|
-
expect(mockFocusTag).toHaveBeenCalledTimes(1);
|
|
618
|
-
expect(mockFocusTag).toHaveBeenLastCalledWith(liElement2);
|
|
619
|
-
jest.restoreAllMocks();
|
|
620
|
-
});
|
|
621
|
-
it("focuses list items", async () => {
|
|
622
|
-
// focusListItem
|
|
623
|
-
const component = new TagInput();
|
|
624
|
-
const mockScrollIntoView = jest.fn();
|
|
625
|
-
const newInput = document.createElement("input");
|
|
626
|
-
newInput.setAttribute("aria-activedescendant", "");
|
|
627
|
-
// @ts-ignore
|
|
628
|
-
component.inputEl = newInput;
|
|
629
|
-
const element = document.createElement("li");
|
|
630
|
-
element.id = "fake-id";
|
|
631
|
-
element.scrollIntoView = mockScrollIntoView;
|
|
632
|
-
component.focusListItem(element);
|
|
633
|
-
expect(component.focusedListItem).toBe(element);
|
|
634
|
-
// @ts-ignore
|
|
635
|
-
expect(component.inputEl).toEqualAttribute("aria-activedescendant", "fake-id");
|
|
636
|
-
expect(mockScrollIntoView).toHaveBeenCalledTimes(1);
|
|
637
|
-
jest.restoreAllMocks();
|
|
638
|
-
});
|
|
639
|
-
it("focuses tags", async () => {
|
|
640
|
-
jest.spyOn(globalFunctions, "hideTooltip").mockImplementation(() => { });
|
|
641
|
-
// focusTag
|
|
642
|
-
const component = new TagInput();
|
|
643
|
-
const element = document.createElement("li");
|
|
644
|
-
element.id = "fakeID";
|
|
645
|
-
//@ts-ignore
|
|
646
|
-
component.tagAreaEl = document.createElement("ul");
|
|
647
|
-
component.focusTag(element);
|
|
648
|
-
expect(component.focusedTag).toBe(element);
|
|
649
|
-
//@ts-ignore
|
|
650
|
-
expect(component.tagAreaEl).toEqualAttribute("aria-activedescendant", "fakeID");
|
|
651
|
-
jest.restoreAllMocks();
|
|
652
|
-
});
|
|
653
|
-
it("clears tag focus", async () => {
|
|
654
|
-
// clearTagFocus
|
|
655
|
-
const component = new TagInput();
|
|
656
|
-
const tagArea = document.createElement("ul");
|
|
657
|
-
tagArea.setAttribute("aria-activedescendant", "fakeID");
|
|
658
|
-
component.focusedListItem = {};
|
|
659
|
-
//@ts-ignore
|
|
660
|
-
component.tagAreaEl = tagArea;
|
|
661
|
-
//@ts-ignore
|
|
662
|
-
expect(component.tagAreaEl).toEqualAttribute("aria-activedescendant", "fakeID");
|
|
663
|
-
component.clearTagFocus();
|
|
664
|
-
//@ts-ignore
|
|
665
|
-
expect(component.tagAreaEl).toEqualAttribute("aria-activedescendant", "");
|
|
666
|
-
expect(component.focusedTag).toBeNull();
|
|
667
|
-
});
|
|
668
|
-
it("clears list item focus", async () => {
|
|
669
|
-
// clearListItemFocus
|
|
670
|
-
const component = new TagInput();
|
|
671
|
-
const element1 = document.createElement("li");
|
|
672
|
-
const element2 = document.createElement("li");
|
|
673
|
-
const element3 = document.createElement("li");
|
|
674
|
-
element1.classList.add("focused");
|
|
675
|
-
element2.classList.add("focused");
|
|
676
|
-
element3.classList.add("focused");
|
|
677
|
-
jest.spyOn(component, "listItemEls", "get").mockReturnValue([element1, element2, element3]);
|
|
678
|
-
const newInput = document.createElement("input");
|
|
679
|
-
newInput.setAttribute("aria-activedescendant", "fake-id");
|
|
680
|
-
// @ts-ignore
|
|
681
|
-
component.inputEl = newInput;
|
|
682
|
-
component.clearListItemFocus();
|
|
683
|
-
expect(component.focusedListItem).toBeNull();
|
|
684
|
-
component.listItemEls.forEach((el) => {
|
|
685
|
-
expect(el.tabIndex).toBe(-1);
|
|
686
|
-
expect(el).not.toHaveClass("focused");
|
|
687
|
-
});
|
|
688
|
-
// @ts-ignore
|
|
689
|
-
expect(component.inputEl).toEqualAttribute("aria-activedescendant", "");
|
|
690
|
-
component.focusedListItem = {};
|
|
691
|
-
jest.spyOn(component, "listItemEls", "get").mockReturnValue([]);
|
|
692
|
-
component.clearListItemFocus();
|
|
693
|
-
expect(component.focusedListItem).toBeNull();
|
|
694
|
-
});
|
|
695
|
-
});
|
|
696
|
-
it("moves down list items", async () => {
|
|
697
|
-
// moveDownListItem
|
|
698
|
-
const component = new TagInput();
|
|
699
|
-
const element1 = {};
|
|
700
|
-
const element2 = {};
|
|
701
|
-
const element3 = {};
|
|
702
|
-
// @ts-ignore
|
|
703
|
-
element1.nextElementSibling = element2;
|
|
704
|
-
// @ts-ignore
|
|
705
|
-
element2.nextElementSibling = element3;
|
|
706
|
-
const spyListItemEls = jest
|
|
707
|
-
.spyOn(component, "listItemEls", "get")
|
|
708
|
-
.mockReturnValue([element1, element2, element3]);
|
|
709
|
-
const mockFocusListItem = (component.focusListItem = jest.fn());
|
|
710
|
-
component.focusedListItem = null;
|
|
711
|
-
component.moveDownListItem();
|
|
712
|
-
expect(mockFocusListItem).toHaveBeenCalledTimes(1);
|
|
713
|
-
expect(mockFocusListItem).toHaveBeenLastCalledWith(element1);
|
|
714
|
-
mockFocusListItem.mockClear();
|
|
715
|
-
component.focusedListItem = element1;
|
|
716
|
-
component.moveDownListItem();
|
|
717
|
-
expect(mockFocusListItem).toHaveBeenCalledTimes(1);
|
|
718
|
-
expect(mockFocusListItem).toHaveBeenLastCalledWith(element2);
|
|
719
|
-
mockFocusListItem.mockClear();
|
|
720
|
-
component.focusedListItem = element2;
|
|
721
|
-
component.moveDownListItem();
|
|
722
|
-
expect(mockFocusListItem).toHaveBeenCalledTimes(1);
|
|
723
|
-
expect(mockFocusListItem).toHaveBeenLastCalledWith(element3);
|
|
724
|
-
mockFocusListItem.mockClear();
|
|
725
|
-
component.focusedListItem = element3;
|
|
726
|
-
component.moveDownListItem();
|
|
727
|
-
expect(mockFocusListItem).toHaveBeenCalledTimes(1);
|
|
728
|
-
expect(mockFocusListItem).toHaveBeenLastCalledWith(element1);
|
|
729
|
-
mockFocusListItem.mockClear();
|
|
730
|
-
spyListItemEls.mockReturnValue([]);
|
|
731
|
-
component.moveDownListItem();
|
|
732
|
-
expect(mockFocusListItem).toHaveBeenCalledTimes(0);
|
|
733
|
-
mockFocusListItem.mockClear();
|
|
734
|
-
jest.restoreAllMocks();
|
|
735
|
-
});
|
|
736
|
-
it("adds and removes options", async () => {
|
|
737
|
-
// addOption, removeOption
|
|
738
|
-
const component = new TagInput();
|
|
739
|
-
const spyFilterCaseInsensitive = jest.spyOn(component, "filterCaseInsensitive");
|
|
740
|
-
const optionsList = ["one", "tWo", "THREE"];
|
|
741
|
-
const removedThree = ["one", "tWo"];
|
|
742
|
-
// adding
|
|
743
|
-
component.optionsList = optionsList;
|
|
744
|
-
expect(component.addOption("WORD")).toStrictEqual([...optionsList, "WORD"]);
|
|
745
|
-
// removing
|
|
746
|
-
component.removeOption("three");
|
|
747
|
-
expect(spyFilterCaseInsensitive).toHaveBeenCalledTimes(1);
|
|
748
|
-
expect(component.optionsList).toStrictEqual(removedThree);
|
|
749
|
-
jest.restoreAllMocks();
|
|
750
|
-
});
|
|
751
|
-
it("adds and removes tags", async () => {
|
|
752
|
-
// addTag, removeTag
|
|
753
|
-
const component = new TagInput();
|
|
754
|
-
const spyFilterCaseInsensitive = jest.spyOn(component, "filterCaseInsensitive");
|
|
755
|
-
const mockAnnounce = (component.announce = jest.fn());
|
|
756
|
-
const mockRemoveOption = (component.removeOption = jest.fn());
|
|
757
|
-
component.tagsList = ["one", "two", "three"];
|
|
758
|
-
// adding
|
|
759
|
-
component.addTag("three");
|
|
760
|
-
expect(component.tagsList).toStrictEqual(["one", "two", "three"]);
|
|
761
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(0);
|
|
762
|
-
component.addTag("four");
|
|
763
|
-
expect(component.tagsList).toStrictEqual(["one", "two", "three", "four"]);
|
|
764
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
765
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("four added.");
|
|
766
|
-
mockAnnounce.mockClear();
|
|
767
|
-
// removing
|
|
768
|
-
component.options = "one,two,three";
|
|
769
|
-
component.tagsList = ["one", "two", "three"];
|
|
770
|
-
component.removeTag("two");
|
|
771
|
-
expect(spyFilterCaseInsensitive).toHaveBeenCalledTimes(1);
|
|
772
|
-
expect(spyFilterCaseInsensitive).toHaveBeenLastCalledWith(["one", "two", "three"], "two");
|
|
773
|
-
expect(component.tagsList).toStrictEqual(["one", "three"]);
|
|
774
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
775
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("two removed");
|
|
776
|
-
expect(mockRemoveOption).toHaveBeenCalledTimes(0);
|
|
777
|
-
spyFilterCaseInsensitive.mockClear();
|
|
778
|
-
mockAnnounce.mockClear();
|
|
779
|
-
mockRemoveOption.mockClear();
|
|
780
|
-
component.options = "one,two";
|
|
781
|
-
component.tagsList = ["one", "two", "three"];
|
|
782
|
-
component.optionsList = ["one", "two", "three"];
|
|
783
|
-
await component.removeTag("three");
|
|
784
|
-
expect(spyFilterCaseInsensitive).toHaveBeenCalledTimes(1);
|
|
785
|
-
expect(spyFilterCaseInsensitive).toHaveBeenLastCalledWith(["one", "two", "three"], "three");
|
|
786
|
-
expect(component.tagsList).toStrictEqual(["one", "two"]);
|
|
787
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
788
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("three removed");
|
|
789
|
-
expect(mockRemoveOption).toHaveBeenCalledTimes(1);
|
|
790
|
-
spyFilterCaseInsensitive.mockClear();
|
|
791
|
-
mockAnnounce.mockClear();
|
|
792
|
-
mockRemoveOption.mockClear();
|
|
793
|
-
jest.restoreAllMocks();
|
|
794
|
-
});
|
|
795
|
-
it("removes tag on remove button click", async () => {
|
|
796
|
-
const component = new TagInput();
|
|
797
|
-
const mockMoveLeftTag = (component.moveLeftTag = jest.fn());
|
|
798
|
-
const mockRemoveTag = (component.removeTag = jest.fn());
|
|
799
|
-
component.handleRemoveButtonClick("word");
|
|
800
|
-
expect(mockMoveLeftTag).toHaveBeenCalledTimes(1);
|
|
801
|
-
expect(mockRemoveTag).toHaveBeenCalledTimes(1);
|
|
802
|
-
expect(mockRemoveTag).toHaveBeenLastCalledWith("word");
|
|
803
|
-
});
|
|
804
|
-
it("resets the input field", async () => {
|
|
805
|
-
// resetInput
|
|
806
|
-
const component = new TagInput();
|
|
807
|
-
const input = { value: "word" };
|
|
808
|
-
// @ts-ignore
|
|
809
|
-
component.inputEl = input;
|
|
810
|
-
component.charCount = 20;
|
|
811
|
-
component.resetInput();
|
|
812
|
-
expect(component.charCount).toBe(0);
|
|
813
|
-
// @ts-ignore
|
|
814
|
-
expect(component.inputEl.value).toBe("");
|
|
815
|
-
});
|
|
816
|
-
it("closes dropdown if not target or child", async () => {
|
|
817
|
-
// closeIfNotElOrChild
|
|
818
|
-
const component = new TagInput();
|
|
819
|
-
const element1 = {};
|
|
820
|
-
const event = { target: element1 };
|
|
821
|
-
const mockCloseDropdown = (component.closeDropdown = jest.fn());
|
|
822
|
-
component.isExpanded = false;
|
|
823
|
-
component.closeIfNotElOrChild(event);
|
|
824
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(0);
|
|
825
|
-
jest.clearAllMocks();
|
|
826
|
-
component.isExpanded = true;
|
|
827
|
-
component.closeIfNotElOrChild(event);
|
|
828
|
-
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
|
829
|
-
jest.restoreAllMocks();
|
|
830
|
-
});
|
|
831
|
-
it("sorts case insensitively", () => {
|
|
832
|
-
const component = new TagInput();
|
|
833
|
-
const list = ["canteloupe", "Apple", "Banana", "Cranberry", "blueberry", "apricot", "double word", "extra"];
|
|
834
|
-
const answer = ["Apple", "apricot", "Banana", "blueberry", "canteloupe", "Cranberry", "double word", "extra"];
|
|
835
|
-
expect(component.sortCaseInsensitive(list)).toStrictEqual(answer);
|
|
836
|
-
});
|
|
837
|
-
it("debounces handling resize", () => {
|
|
838
|
-
const component = new TagInput();
|
|
839
|
-
const mockDebouncedUpdate = (component.debouncedUpdate = jest.fn());
|
|
840
|
-
component.debouncedUpdate();
|
|
841
|
-
expect(mockDebouncedUpdate).toHaveBeenCalledTimes(1);
|
|
842
|
-
jest.restoreAllMocks();
|
|
843
|
-
//
|
|
844
|
-
});
|
|
845
|
-
it("postions the input element properly", () => {
|
|
846
|
-
const component = new TagInput();
|
|
847
|
-
// @ts-ignore
|
|
848
|
-
component.inputEl = document.createElement("input");
|
|
849
|
-
// @ts-ignore
|
|
850
|
-
component.tagAreaEl = document.createElement("ul");
|
|
851
|
-
// @ts-ignore
|
|
852
|
-
component.tagAreaEl.getBoundingClientRect = () => {
|
|
853
|
-
return { right: 200 };
|
|
854
|
-
};
|
|
855
|
-
const element1 = {
|
|
856
|
-
dataset: { tag: "one" },
|
|
857
|
-
};
|
|
858
|
-
const element2 = {
|
|
859
|
-
dataset: { tag: "two" },
|
|
860
|
-
};
|
|
861
|
-
jest.spyOn(component, "tagEls", "get").mockReturnValue([element1, element2]);
|
|
862
|
-
// last tag exists and spaceAvailable
|
|
863
|
-
element2.getBoundingClientRect = () => {
|
|
864
|
-
return { right: 0 };
|
|
865
|
-
};
|
|
866
|
-
// @ts-ignore
|
|
867
|
-
element2.offsetTop = 10;
|
|
868
|
-
component.positionInput();
|
|
869
|
-
// @ts-ignore
|
|
870
|
-
expect(component.inputEl.style.position).toBe("absolute");
|
|
871
|
-
// @ts-ignore
|
|
872
|
-
expect(component.inputEl.style.top).toBe("10px");
|
|
873
|
-
// @ts-ignore
|
|
874
|
-
// 200 - 0 - 8
|
|
875
|
-
expect(component.inputEl.style.width).toBe("192px");
|
|
876
|
-
// last tag exists and no spaceAvailable
|
|
877
|
-
element2.getBoundingClientRect = () => {
|
|
878
|
-
return { right: 180 };
|
|
879
|
-
};
|
|
880
|
-
// @ts-ignore
|
|
881
|
-
element2.offsetTop = 10;
|
|
882
|
-
component.positionInput();
|
|
883
|
-
// @ts-ignore
|
|
884
|
-
expect(component.inputEl.style.position).toBe("static");
|
|
885
|
-
// @ts-ignore
|
|
886
|
-
expect(component.inputEl.style.width).toBe("100%");
|
|
887
|
-
// no tags exist
|
|
888
|
-
jest.spyOn(component, "tagEls", "get").mockReturnValue([]);
|
|
889
|
-
component.positionInput();
|
|
890
|
-
// @ts-ignore
|
|
891
|
-
expect(component.inputEl.style.position).toBe("static");
|
|
892
|
-
// @ts-ignore
|
|
893
|
-
expect(component.inputEl.style.width).toBe("100%");
|
|
894
|
-
});
|
|
895
|
-
it("creates CSV from list", () => {
|
|
896
|
-
const component = new TagInput();
|
|
897
|
-
const list1 = ["one", "two", "and three"];
|
|
898
|
-
expect(component.listToCSV(list1)).toBe("one,two,and three");
|
|
899
|
-
expect(component.listToCSV([])).toBe("");
|
|
900
|
-
});
|
|
901
|
-
describe("handles announcements", () => {
|
|
902
|
-
it("announces live region notifications", async () => {
|
|
903
|
-
// announce
|
|
904
|
-
const component = new TagInput();
|
|
905
|
-
const div = document.createElement("div");
|
|
906
|
-
div.textContent = "";
|
|
907
|
-
//@ts-ignore
|
|
908
|
-
component.liveRegionEl = div;
|
|
909
|
-
component.announce("Message");
|
|
910
|
-
expect(component.liveRegionMessage).toBe("Message");
|
|
911
|
-
});
|
|
912
|
-
it("announces existing options", async () => {
|
|
913
|
-
// announceExistingOptions
|
|
914
|
-
const component = new TagInput();
|
|
915
|
-
const element1 = {};
|
|
916
|
-
const element2 = {};
|
|
917
|
-
const mockAnnounce = (component.announce = jest.fn());
|
|
918
|
-
jest.spyOn(component, "optionEls", "get").mockReturnValue([element1, element2]);
|
|
919
|
-
const spyRequestAnimationFrame = jest
|
|
920
|
-
.spyOn(window, "requestAnimationFrame")
|
|
921
|
-
//@ts-ignore
|
|
922
|
-
.mockImplementation((cb) => cb());
|
|
923
|
-
component.announceExistingOptions();
|
|
924
|
-
expect(spyRequestAnimationFrame).toHaveBeenCalledTimes(1);
|
|
925
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
926
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("2 existing options.");
|
|
927
|
-
jest.clearAllMocks();
|
|
928
|
-
jest.spyOn(component, "optionEls", "get").mockReturnValue([element1]);
|
|
929
|
-
component.announceExistingOptions();
|
|
930
|
-
expect(spyRequestAnimationFrame).toHaveBeenCalledTimes(1);
|
|
931
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
932
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("1 existing option.");
|
|
933
|
-
jest.clearAllMocks();
|
|
934
|
-
jest.spyOn(component, "optionEls", "get").mockReturnValue([]);
|
|
935
|
-
component.announceExistingOptions();
|
|
936
|
-
expect(spyRequestAnimationFrame).toHaveBeenCalledTimes(1);
|
|
937
|
-
expect(mockAnnounce).toHaveBeenCalledTimes(1);
|
|
938
|
-
expect(mockAnnounce).toHaveBeenLastCalledWith("0 existing options.");
|
|
939
|
-
jest.restoreAllMocks();
|
|
940
|
-
});
|
|
941
|
-
it("announces character limits warnings", async () => {
|
|
942
|
-
const component = new TagInput();
|
|
943
|
-
let message = component.generateCharacterLimitWarning(0, 50);
|
|
944
|
-
expect(message).toBe("0 of 50 characters entered.");
|
|
945
|
-
message = component.generateCharacterLimitWarning(30, 50);
|
|
946
|
-
expect(message).toBe("30 of 50 characters entered.");
|
|
947
|
-
message = component.generateCharacterLimitWarning(50, 50);
|
|
948
|
-
expect(message).toBe("50 of 50 characters entered. No additional characters will be entered.");
|
|
949
|
-
message = component.generateCharacterLimitWarning(75, 50);
|
|
950
|
-
expect(message).toBe("75 of 50 characters entered. No additional characters will be entered.");
|
|
951
|
-
});
|
|
952
|
-
});
|
|
953
|
-
describe("generates intl messages", () => {
|
|
954
|
-
it("generates the added tag message", () => {
|
|
955
|
-
const component = new TagInput();
|
|
956
|
-
expect(component.generateTagAddedMessage("word")).toBe("word added.");
|
|
957
|
-
});
|
|
958
|
-
it("generates the already added tag message", () => {
|
|
959
|
-
const component = new TagInput();
|
|
960
|
-
expect(component.generateTagAlreadyAddedMessage("word")).toBe("word has already been added.");
|
|
961
|
-
});
|
|
962
|
-
it("configures messages", () => {
|
|
963
|
-
const component = new TagInput();
|
|
964
|
-
// defaults are in place
|
|
965
|
-
expect(component.componentMessages.addNewHelpText).toBe("Press the Enter or Comma key to add a new tag.");
|
|
966
|
-
expect(component.componentMessages.selectionHelpText).toBe("Search and select a tag.");
|
|
967
|
-
expect(component.componentMessages.maxTagsReached).toBe("No more tags can be added because the limit has been reached.");
|
|
968
|
-
expect(component.componentMessages.tagAreaInstructions).toBe("tag selection. Press Backspace or Delete to remove a tag.");
|
|
969
|
-
expect(component.componentMessages.tagsAdded).toBe("Tags added");
|
|
970
|
-
// handles partial replacement
|
|
971
|
-
component.messageConfig =
|
|
972
|
-
'{"tagAreaInstructions": "tagAreaInstructions replacement", "tagsAdded": "tagsAdded replacement"}';
|
|
973
|
-
expect(component.componentMessages.addNewHelpText).toBe("Press the Enter or Comma key to add a new tag.");
|
|
974
|
-
expect(component.componentMessages.selectionHelpText).toBe("Search and select a tag.");
|
|
975
|
-
expect(component.componentMessages.maxTagsReached).toBe("No more tags can be added because the limit has been reached.");
|
|
976
|
-
expect(component.componentMessages.tagAreaInstructions).toBe("tagAreaInstructions replacement");
|
|
977
|
-
expect(component.componentMessages.tagsAdded).toBe("tagsAdded replacement");
|
|
978
|
-
// handles full replacement
|
|
979
|
-
component.messageConfig =
|
|
980
|
-
'{"addNewHelpText": "addNewHelpText replacement", "selectionHelpText": "selectionHelpText replacement", "maxTagsReached": "maxTagsReached replacement", "tagAreaInstructions": "tagAreaInstructions replacement", "tagsAdded": "tagsAdded replacement"}';
|
|
981
|
-
expect(component.componentMessages.addNewHelpText).toBe("addNewHelpText replacement");
|
|
982
|
-
expect(component.componentMessages.selectionHelpText).toBe("selectionHelpText replacement");
|
|
983
|
-
expect(component.componentMessages.maxTagsReached).toBe("maxTagsReached replacement");
|
|
984
|
-
expect(component.componentMessages.tagAreaInstructions).toBe("tagAreaInstructions replacement");
|
|
985
|
-
expect(component.componentMessages.tagsAdded).toBe("tagsAdded replacement");
|
|
986
|
-
});
|
|
987
|
-
});
|
|
988
|
-
});
|
|
989
|
-
//type table acceptance criteria
|
|
990
|
-
//x table is rendered under input segment
|
|
991
|
-
//x magnifying glass icon is added for both types
|
|
992
|
-
//x styling of the tag-limit area is updated
|
|
993
|
-
//x add new max-tags limit reached message
|
|
994
|
-
//x table rows are zebra-striped
|
|
995
|
-
//x hover state is darker
|
|
996
|
-
//x selected options have new selected style (blueish with saturated border)
|
|
997
|
-
//x -> selected rows styling is overidden by hover styling
|
|
998
|
-
//x locked rows have the lock icon to the left of the first column text
|
|
999
|
-
//x selected locked tags are darker than the rest, and have lock icon instead of delete x
|
|
1000
|
-
//x identical names have identical looking tags
|
|
1001
|
-
//x table content scrolls while the input segment stays in place
|
|
1002
|
-
//x entering text filters across all columns
|
|
1003
|
-
//x when no options pass filter, message is shown
|
|
1004
|
-
//x user can select or deselect tags by activating the row (Enter & click)
|
|
1005
|
-
//x the text in col1 is what is displayed in the tag
|
|
1006
|
-
//x component allows for 2-4 columns
|
|
1007
|
-
//x component has no character count
|
|
1008
|
-
//// Properties of wm-tag-input
|
|
1009
|
-
//x selected-tags: in table variant, list of id of the table rows that are selected
|
|
1010
|
-
//x tag-input-type: defaults to "dropdown", used "table" for table variant
|
|
1011
|
-
//x col-headers: comma separated list of column headers. Required
|
|
1012
|
-
//x col-widths: comma separated list of css width values. If a value is blank, it fills rest of available space
|
|
1013
|
-
//x -> (defaults to a table cell with no width e.g. "50%,134px,,10%")
|
|
1014
|
-
//x col-wrap: comma separated list of values either trunc or wrap. defaults to wrap for all columns, or wrap for all unspecified columns.
|
|
1015
|
-
//x -> e.g. if a table has 4 columns, "trunc" is treated as "trunc,wrap,wrap,wrap"
|
|
1016
|
-
//// Properties of wm-tag-input-row
|
|
1017
|
-
//x id: used to link the row to the tag. the id is what is added to the selected-tags property
|
|
1018
|
-
//x col1, col2, col3, col4: the values for each column of the row
|
|
1019
|
-
//x locked: whether or not the row can be activated. selected and unselected rows can be locked
|
|
1020
|
-
//x -> aria-describedby or similar indicates locked status
|
|
1021
|
-
//x input field has combobox role
|
|
1022
|
-
//x table has grid role
|
|
1023
|
-
//x table has aria-multiselectable
|
|
1024
|
-
//x rows have role row
|
|
1025
|
-
//x cells have role gridcell
|
|
1026
|
-
//x header cells have role columnheader
|
|
1027
|
-
//x aria-expanded will NOT be used
|
|
1028
|
-
//x table does not have a tab-stop
|
|
1029
|
-
//x up, down, left and right arrows navigate the table cells
|
|
1030
|
-
//x navigation is handled with aria-activedescendant, true focus remains on the input field
|
|
1031
|
-
//x down arrow from the input field navigates to the first row, up arrow goes to the last row
|
|
1032
|
-
//x while a cell is "focused" or hovered, a tooltip appears if the text is truncated
|
|
1033
|
-
//x cell "focus" is indicated by an inwards purple shadow, like the navigation component
|
|
1034
|
-
//x on load, pre-selected tags are handled
|
|
1035
|
-
//x while typing, faux focus is cleared
|
|
1036
|
-
//x if max-tags reached, make sure focus goes to list instead of input
|
|
1037
|
-
//x tooltip disappears on scroll
|
|
1038
|
-
// should activating a locked element sr-alert the user?
|
|
1039
|
-
// should typing that returns no results sr-alert the user?
|