q2-tecton-elements 1.52.2 → 1.53.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/loader.cjs.js +1 -1
- package/dist/cjs/q2-file-picker.cjs.entry.js +236 -0
- package/dist/cjs/q2-file-picker.cjs.entry.js.map +1 -0
- package/dist/cjs/q2-item_3.cjs.entry.js +250 -0
- package/dist/cjs/q2-item_3.cjs.entry.js.map +1 -0
- package/dist/cjs/q2-pill.cjs.entry.js +7 -3
- package/dist/cjs/q2-pill.cjs.entry.js.map +1 -1
- package/dist/cjs/q2-select.cjs.entry.js +3 -2
- package/dist/cjs/q2-select.cjs.entry.js.map +1 -1
- package/dist/cjs/q2-tag.cjs.entry.js +3 -1
- package/dist/cjs/q2-tag.cjs.entry.js.map +1 -1
- package/dist/cjs/q2-tecton-elements.cjs.js +1 -1
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/q2-file-picker/q2-file-picker.css +288 -0
- package/dist/collection/components/q2-file-picker/q2-file-picker.js +426 -0
- package/dist/collection/components/q2-file-picker/q2-file-picker.js.map +1 -0
- package/dist/collection/components/q2-file-picker/test/q2-file-picker-test.e2e.js +11 -0
- package/dist/collection/components/q2-file-picker/test/q2-file-picker-test.e2e.js.map +1 -0
- package/dist/collection/components/q2-file-picker/test/q2-file-picker-test.spec.js +435 -0
- package/dist/collection/components/q2-file-picker/test/q2-file-picker-test.spec.js.map +1 -0
- package/dist/collection/components/q2-item/q2-item.css +3 -0
- package/dist/collection/components/q2-list/q2-list.css +6 -0
- package/dist/collection/components/q2-pill/q2-pill.js +7 -3
- package/dist/collection/components/q2-pill/q2-pill.js.map +1 -1
- package/dist/collection/components/q2-pill/test/q2-pill-test.e2e.js +108 -0
- package/dist/collection/components/q2-pill/test/q2-pill-test.e2e.js.map +1 -1
- package/dist/collection/components/q2-select/q2-select.js +3 -2
- package/dist/collection/components/q2-select/q2-select.js.map +1 -1
- package/dist/collection/components/q2-tag/q2-tag.js +3 -1
- package/dist/collection/components/q2-tag/q2-tag.js.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/q2-file-picker.d.ts +11 -0
- package/dist/components/q2-file-picker.js +301 -0
- package/dist/components/q2-file-picker.js.map +1 -0
- package/dist/components/q2-item.js +1 -130
- package/dist/components/q2-item.js.map +1 -1
- package/dist/{esm/q2-item.entry.js → components/q2-item2.js} +29 -11
- package/dist/components/q2-item2.js.map +1 -0
- package/dist/components/q2-link.js +1 -86
- package/dist/components/q2-link.js.map +1 -1
- package/dist/{esm/q2-link.entry.js → components/q2-link2.js} +39 -9
- package/dist/components/q2-link2.js.map +1 -0
- package/dist/components/q2-list.js +1 -94
- package/dist/components/q2-list.js.map +1 -1
- package/dist/{esm/q2-list.entry.js → components/q2-list2.js} +30 -11
- package/dist/components/q2-list2.js.map +1 -0
- package/dist/components/q2-pill.js +7 -3
- package/dist/components/q2-pill.js.map +1 -1
- package/dist/components/q2-select2.js +3 -2
- package/dist/components/q2-select2.js.map +1 -1
- package/dist/components/q2-tag.js +3 -1
- package/dist/components/q2-tag.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/q2-file-picker.entry.js +232 -0
- package/dist/esm/q2-file-picker.entry.js.map +1 -0
- package/dist/esm/q2-item_3.entry.js +244 -0
- package/dist/esm/q2-item_3.entry.js.map +1 -0
- package/dist/esm/q2-pill.entry.js +7 -3
- package/dist/esm/q2-pill.entry.js.map +1 -1
- package/dist/esm/q2-select.entry.js +3 -2
- package/dist/esm/q2-select.entry.js.map +1 -1
- package/dist/esm/q2-tag.entry.js +3 -1
- package/dist/esm/q2-tag.entry.js.map +1 -1
- package/dist/esm/q2-tecton-elements.js +1 -1
- package/dist/q2-tecton-elements/q2-file-picker.entry.js +338 -0
- package/dist/q2-tecton-elements/q2-file-picker.entry.js.map +1 -0
- package/dist/q2-tecton-elements/q2-item_3.entry.js +331 -0
- package/dist/q2-tecton-elements/q2-item_3.entry.js.map +1 -0
- package/dist/q2-tecton-elements/q2-pill.entry.js +22 -18
- package/dist/q2-tecton-elements/q2-pill.entry.js.map +1 -1
- package/dist/q2-tecton-elements/q2-select.entry.js +6 -5
- package/dist/q2-tecton-elements/q2-select.entry.js.map +1 -1
- package/dist/q2-tecton-elements/q2-tag.entry.js +36 -34
- package/dist/q2-tecton-elements/q2-tag.entry.js.map +1 -1
- package/dist/q2-tecton-elements/q2-tecton-elements.esm.js +1 -1
- package/dist/q2-tecton-elements/q2-tecton-elements.esm.js.map +1 -1
- package/dist/types/components/q2-file-picker/q2-file-picker.d.ts +98 -0
- package/dist/types/components/q2-pill/q2-pill.d.ts +1 -1
- package/dist/types/components.d.ts +101 -0
- package/package.json +3 -3
- package/dist/cjs/q2-item.cjs.entry.js +0 -120
- package/dist/cjs/q2-item.cjs.entry.js.map +0 -1
- package/dist/cjs/q2-link.cjs.entry.js +0 -64
- package/dist/cjs/q2-link.cjs.entry.js.map +0 -1
- package/dist/cjs/q2-list.cjs.entry.js +0 -83
- package/dist/cjs/q2-list.cjs.entry.js.map +0 -1
- package/dist/esm/q2-item.entry.js.map +0 -1
- package/dist/esm/q2-link.entry.js.map +0 -1
- package/dist/esm/q2-list.entry.js.map +0 -1
- package/dist/q2-tecton-elements/q2-item.entry.js +0 -158
- package/dist/q2-tecton-elements/q2-item.entry.js.map +0 -1
- package/dist/q2-tecton-elements/q2-link.entry.js +0 -83
- package/dist/q2-tecton-elements/q2-link.entry.js.map +0 -1
- package/dist/q2-tecton-elements/q2-list.entry.js +0 -100
- package/dist/q2-tecton-elements/q2-list.entry.js.map +0 -1
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { Q2FilePicker } from "../q2-file-picker";
|
|
2
|
+
import { objectToHTMLAttributes, setupSpecPageWithLoc } from "../../../utils/helpers";
|
|
3
|
+
describe('q2-legend', () => {
|
|
4
|
+
const buildSlots = (slots) => {
|
|
5
|
+
return slots.reduce((acc, slot) => {
|
|
6
|
+
return `${acc}<div slot="${slot.name}">${slot.content}</div>`;
|
|
7
|
+
}, '');
|
|
8
|
+
};
|
|
9
|
+
const setupPage = async (attributes = {}, testStrings = {}, slots = []) => {
|
|
10
|
+
const attributesString = objectToHTMLAttributes(attributes);
|
|
11
|
+
const slotsString = buildSlots(slots);
|
|
12
|
+
const page = await setupSpecPageWithLoc({
|
|
13
|
+
components: [Q2FilePicker],
|
|
14
|
+
html: `<q2-file-picker ${attributesString}>${slotsString}</q2-file-picker>`,
|
|
15
|
+
}, testStrings);
|
|
16
|
+
return page;
|
|
17
|
+
};
|
|
18
|
+
const createMockFile = (props = {}) => {
|
|
19
|
+
return {
|
|
20
|
+
name: props.name || 'test-file',
|
|
21
|
+
lastModified: props.lastModified || Date.now(),
|
|
22
|
+
webkitRelativePath: props.webkitRelativePath || '',
|
|
23
|
+
size: props.size || 1234,
|
|
24
|
+
type: props.type || 'text/plain', // 'application/pdf'
|
|
25
|
+
arrayBuffer: props.arrayBuffer || jest.fn(),
|
|
26
|
+
slice: props.slice || jest.fn(),
|
|
27
|
+
stream: props.stream || jest.fn(),
|
|
28
|
+
text: props.text || jest.fn(),
|
|
29
|
+
bytes: props.bytes || jest.fn(() => Promise.resolve(new Uint8Array())),
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const createMockFileList = (files) => {
|
|
33
|
+
return Object.assign(Object.assign({}, files), { length: files.length, item: (index) => files[index] });
|
|
34
|
+
};
|
|
35
|
+
function simulateFileInputChange(page, mockFileList) {
|
|
36
|
+
const input = page.root.shadowRoot.querySelector('[test-id="file-input"]');
|
|
37
|
+
const changeCallback = jest.fn();
|
|
38
|
+
page.root.addEventListener('tctChange', changeCallback);
|
|
39
|
+
input.files = mockFileList;
|
|
40
|
+
input.dispatchEvent(new Event('change'));
|
|
41
|
+
return changeCallback;
|
|
42
|
+
}
|
|
43
|
+
describe('Props', () => {
|
|
44
|
+
describe('description', () => {
|
|
45
|
+
it('when set description rendered', async () => {
|
|
46
|
+
const descriptionText = 'Test Description';
|
|
47
|
+
const page = await setupPage({ description: descriptionText });
|
|
48
|
+
const description = page.root.shadowRoot.querySelector('[test-id="description"]');
|
|
49
|
+
expect(description).toEqualText(descriptionText);
|
|
50
|
+
});
|
|
51
|
+
it('is localizable', async () => {
|
|
52
|
+
const descriptionText = 'Test Description';
|
|
53
|
+
const page = await setupPage({ description: 'test.description' }, { 'test.description': descriptionText });
|
|
54
|
+
const description = page.root.shadowRoot.querySelector('[test-id="description"]');
|
|
55
|
+
expect(description).toEqualText(descriptionText);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('fileTypes', () => {
|
|
59
|
+
it('limits the types of files that can be selected', async () => {
|
|
60
|
+
const page = await setupPage();
|
|
61
|
+
page.root.fileTypes = ['pdf'];
|
|
62
|
+
const mockPdfFile = createMockFile({ name: 'test-file.pdf' });
|
|
63
|
+
const mockTextFile = createMockFile({ name: 'test-file.txt' });
|
|
64
|
+
const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);
|
|
65
|
+
const changeCallback = simulateFileInputChange(page, mockFileList);
|
|
66
|
+
await page.waitForChanges();
|
|
67
|
+
const value = page.root.value;
|
|
68
|
+
const expectedValue = {
|
|
69
|
+
invalidFiles: [{ file: mockTextFile, status: 'invalid-type' }],
|
|
70
|
+
validFiles: [mockPdfFile],
|
|
71
|
+
};
|
|
72
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
73
|
+
detail: expect.objectContaining(expectedValue),
|
|
74
|
+
}));
|
|
75
|
+
expect(value).toEqual(expectedValue);
|
|
76
|
+
});
|
|
77
|
+
it('allows all file types when fileTypes is not defined', async () => {
|
|
78
|
+
const page = await setupPage();
|
|
79
|
+
const mockPdfFile = createMockFile({ name: 'test-file.pdf' });
|
|
80
|
+
const mockTextFile = createMockFile({ name: 'test-file.txt' });
|
|
81
|
+
const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);
|
|
82
|
+
const changeCallback = simulateFileInputChange(page, mockFileList);
|
|
83
|
+
await page.waitForChanges();
|
|
84
|
+
const value = page.root.value;
|
|
85
|
+
const expectedValue = {
|
|
86
|
+
invalidFiles: [],
|
|
87
|
+
validFiles: [mockPdfFile, mockTextFile],
|
|
88
|
+
};
|
|
89
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
90
|
+
detail: expect.objectContaining(expectedValue),
|
|
91
|
+
}));
|
|
92
|
+
expect(value).toEqual(expectedValue);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('label', () => {
|
|
96
|
+
it('when set label rendered', async () => {
|
|
97
|
+
const labelText = 'Test Label';
|
|
98
|
+
const page = await setupPage({ label: labelText });
|
|
99
|
+
const label = page.root.shadowRoot.querySelector('[test-id="label"]');
|
|
100
|
+
expect(label).toEqualText(labelText);
|
|
101
|
+
});
|
|
102
|
+
it('is localizable', async () => {
|
|
103
|
+
const labelText = 'Test Label';
|
|
104
|
+
const page = await setupPage({ label: 'test.label' }, { 'test.label': labelText });
|
|
105
|
+
const label = page.root.shadowRoot.querySelector('[test-id="label"]');
|
|
106
|
+
expect(label).toEqualText(labelText);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('maxFiles', () => {
|
|
110
|
+
it('limits the number of files that can be selected', async () => {
|
|
111
|
+
const page = await setupPage({ 'max-files': 0 });
|
|
112
|
+
const mockPdfFile = createMockFile({ name: 'test-file.pdf', type: 'application/pdf' });
|
|
113
|
+
const mockFileList = createMockFileList([mockPdfFile]);
|
|
114
|
+
const changeCallback = simulateFileInputChange(page, mockFileList);
|
|
115
|
+
await page.waitForChanges();
|
|
116
|
+
const value = page.root.value;
|
|
117
|
+
const expectedValue = {
|
|
118
|
+
invalidFiles: [{ file: mockPdfFile, status: 'over-max-files-limit' }],
|
|
119
|
+
validFiles: [],
|
|
120
|
+
};
|
|
121
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
122
|
+
detail: expect.objectContaining(expectedValue),
|
|
123
|
+
}));
|
|
124
|
+
expect(value).toEqual(expectedValue);
|
|
125
|
+
});
|
|
126
|
+
it('allows multiple files to be selected when it is greater than 1', async () => {
|
|
127
|
+
const page = await setupPage({ maxFiles: 2 });
|
|
128
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
129
|
+
const mockFile2 = Object.assign(Object.assign({}, mockFile), { name: 'test-file-2' });
|
|
130
|
+
const mockFileListMultiple = createMockFileList([mockFile, mockFile2]);
|
|
131
|
+
const changeCallback = simulateFileInputChange(page, mockFileListMultiple);
|
|
132
|
+
await page.waitForChanges();
|
|
133
|
+
const value = page.root.value;
|
|
134
|
+
const expectedValue = {
|
|
135
|
+
invalidFiles: [],
|
|
136
|
+
validFiles: [mockFile, mockFile2],
|
|
137
|
+
};
|
|
138
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
139
|
+
detail: expect.objectContaining(expectedValue),
|
|
140
|
+
}));
|
|
141
|
+
expect(value).toEqual(expectedValue);
|
|
142
|
+
});
|
|
143
|
+
it('allows any number of files to be selected when it is not set', async () => {
|
|
144
|
+
const page = await setupPage();
|
|
145
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
146
|
+
const mockFile2 = Object.assign(Object.assign({}, mockFile), { name: 'test-file-2' });
|
|
147
|
+
const mockFile3 = Object.assign(Object.assign({}, mockFile), { name: 'test-file-3' });
|
|
148
|
+
const mockFileListMultiple = createMockFileList([mockFile, mockFile2, mockFile3]);
|
|
149
|
+
const changeCallback = simulateFileInputChange(page, mockFileListMultiple);
|
|
150
|
+
await page.waitForChanges();
|
|
151
|
+
const value = page.root.value;
|
|
152
|
+
const expectedValue = {
|
|
153
|
+
invalidFiles: [],
|
|
154
|
+
validFiles: [mockFile, mockFile2, mockFile3],
|
|
155
|
+
};
|
|
156
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
157
|
+
detail: expect.objectContaining(expectedValue),
|
|
158
|
+
}));
|
|
159
|
+
expect(value).toEqual(expectedValue);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('maxFileSize', () => {
|
|
163
|
+
it('limits the size of files that can be selected', async () => {
|
|
164
|
+
const page = await setupPage({ 'max-file-size': 2000 });
|
|
165
|
+
const mockFile = createMockFile({ name: 'test-file', size: 1000 });
|
|
166
|
+
const mockFileTooLarge = createMockFile({ name: 'test-file-2', size: 3000 });
|
|
167
|
+
const mockFileList = createMockFileList([mockFile, mockFileTooLarge]);
|
|
168
|
+
const changeCallback = simulateFileInputChange(page, mockFileList);
|
|
169
|
+
await page.waitForChanges();
|
|
170
|
+
const value = page.root.value;
|
|
171
|
+
const expectedValue = {
|
|
172
|
+
invalidFiles: [{ file: mockFileTooLarge, status: 'over-size-limit' }],
|
|
173
|
+
validFiles: [mockFile],
|
|
174
|
+
};
|
|
175
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
176
|
+
detail: expect.objectContaining(expectedValue),
|
|
177
|
+
}));
|
|
178
|
+
expect(value).toEqual(expectedValue);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('value', () => {
|
|
182
|
+
it('returns an object with empty arrays for prop values when no files have been selected', async () => {
|
|
183
|
+
const page = await setupPage();
|
|
184
|
+
const value = page.root.value;
|
|
185
|
+
const expectedValue = {
|
|
186
|
+
invalidFiles: [],
|
|
187
|
+
validFiles: [],
|
|
188
|
+
};
|
|
189
|
+
expect(value).toEqual(expectedValue);
|
|
190
|
+
});
|
|
191
|
+
it('returns an object with the selected files when files have been selected', async () => {
|
|
192
|
+
const page = await setupPage();
|
|
193
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
194
|
+
const mockFileList = createMockFileList([mockFile]);
|
|
195
|
+
simulateFileInputChange(page, mockFileList);
|
|
196
|
+
await page.waitForChanges();
|
|
197
|
+
const value = page.root.value;
|
|
198
|
+
const expectedValue = {
|
|
199
|
+
invalidFiles: [],
|
|
200
|
+
validFiles: [mockFile],
|
|
201
|
+
};
|
|
202
|
+
expect(value).toEqual(expectedValue);
|
|
203
|
+
});
|
|
204
|
+
it('returns an object with the valid and invalid files when files have been selected', async () => {
|
|
205
|
+
const page = await setupPage();
|
|
206
|
+
page.root.fileTypes = ['pdf'];
|
|
207
|
+
const mockPdfFile = createMockFile({ name: 'test-file.pdf', type: 'application/pdf' });
|
|
208
|
+
const mockTextFile = createMockFile({ name: 'test-file.txt' });
|
|
209
|
+
const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);
|
|
210
|
+
simulateFileInputChange(page, mockFileList);
|
|
211
|
+
await page.waitForChanges();
|
|
212
|
+
const value = page.root.value;
|
|
213
|
+
const expectedValue = {
|
|
214
|
+
invalidFiles: [{ file: mockTextFile, status: 'invalid-type' }],
|
|
215
|
+
validFiles: [mockPdfFile],
|
|
216
|
+
};
|
|
217
|
+
expect(value).toEqual(expectedValue);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
describe('variant', () => {
|
|
221
|
+
it('when set to "browse-drop" displays drop zone', async () => {
|
|
222
|
+
const page = await setupPage({ variant: 'browse-drop' });
|
|
223
|
+
const dropZone = page.root.shadowRoot.querySelector('[test-id="drop-zone"]');
|
|
224
|
+
const browseButton = page.root.shadowRoot.querySelector('[test-id="browse-button"]');
|
|
225
|
+
expect(dropZone).not.toBeNull();
|
|
226
|
+
expect(browseButton).toBeNull();
|
|
227
|
+
});
|
|
228
|
+
it('when set to "browse" displays only the browse button', async () => {
|
|
229
|
+
const page = await setupPage({ variant: 'browse' });
|
|
230
|
+
const dropZone = page.root.shadowRoot.querySelector('[test-id="drop-zone"]');
|
|
231
|
+
const browseButton = page.root.shadowRoot.querySelector('[test-id="browse"]');
|
|
232
|
+
expect(dropZone).toBeNull();
|
|
233
|
+
expect(browseButton).not.toBeNull();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe('Slots', () => {
|
|
238
|
+
describe('label', () => {
|
|
239
|
+
it('rendered when slot is provided', async () => {
|
|
240
|
+
const labelSlotContent = 'Test Label Slot';
|
|
241
|
+
const page = await setupPage({}, {}, [{ name: 'label', content: labelSlotContent }]);
|
|
242
|
+
const label = page.root.shadowRoot.querySelector('[test-id="label"]');
|
|
243
|
+
// check for the slot container without the slot content because
|
|
244
|
+
// newSpecPage appears to not render the slot content
|
|
245
|
+
expect(label.innerHTML).toEqualHtml('<slot name="label"></slot>');
|
|
246
|
+
});
|
|
247
|
+
it('not rendered when slot is provided and label prop set', async () => {
|
|
248
|
+
const labelText = 'Test Label';
|
|
249
|
+
const labelSlotContent = 'Test Label Slot';
|
|
250
|
+
const page = await setupPage({ label: labelText }, {}, [{ name: 'label', content: labelSlotContent }]);
|
|
251
|
+
const label = page.root.shadowRoot.querySelector('[test-id="label"]');
|
|
252
|
+
expect(label.innerHTML).toEqualHtml(labelText);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe('description', () => {
|
|
256
|
+
it('rendered when slot is provided', async () => {
|
|
257
|
+
const descriptionSlotContent = 'Test Description Slot';
|
|
258
|
+
const page = await setupPage({}, {}, [{ name: 'description', content: descriptionSlotContent }]);
|
|
259
|
+
const description = page.root.shadowRoot.querySelector('[test-id="description"]');
|
|
260
|
+
// check for the slot container without the slot content because
|
|
261
|
+
// newSpecPage appears to not render the slot content
|
|
262
|
+
expect(description.innerHTML).toEqualHtml('<slot name="description"></slot>');
|
|
263
|
+
});
|
|
264
|
+
it('not rendered when slot is provided and label prop set', async () => {
|
|
265
|
+
const descriptionText = 'Test Description';
|
|
266
|
+
const descriptionSlotContent = 'Test Description Slot';
|
|
267
|
+
const page = await setupPage({ description: descriptionText }, {}, [
|
|
268
|
+
{ name: 'description', content: descriptionSlotContent },
|
|
269
|
+
]);
|
|
270
|
+
const label = page.root.shadowRoot.querySelector('[test-id="description"]');
|
|
271
|
+
expect(label.innerHTML).toEqualHtml(descriptionText);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
describe('Events', () => {
|
|
276
|
+
describe('tctChange', () => {
|
|
277
|
+
it('emitted when a file input emits a change event', async () => {
|
|
278
|
+
const page = await setupPage();
|
|
279
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
280
|
+
const mockFileList = createMockFileList([mockFile]);
|
|
281
|
+
const changeCallback = simulateFileInputChange(page, mockFileList);
|
|
282
|
+
await page.waitForChanges();
|
|
283
|
+
const expectedValue = {
|
|
284
|
+
invalidFiles: [],
|
|
285
|
+
validFiles: [mockFile],
|
|
286
|
+
};
|
|
287
|
+
expect(changeCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
288
|
+
detail: expect.objectContaining(expectedValue),
|
|
289
|
+
}));
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
describe('Watchers', () => {
|
|
294
|
+
describe('updateFileList', () => {
|
|
295
|
+
it('sets the status of a queued file when the status prop changes', async () => {
|
|
296
|
+
const page = await setupPage();
|
|
297
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
298
|
+
page.rootInstance.queuedFiles = [mockFile];
|
|
299
|
+
page.rootInstance.updateFileList([{ name: 'test-file', status: 'uploaded' }]);
|
|
300
|
+
await page.waitForChanges();
|
|
301
|
+
expect(page.rootInstance.displayedFiles).toEqual([{ file: mockFile, status: 'uploaded' }]);
|
|
302
|
+
});
|
|
303
|
+
it('sets the status of a displayed file when the status prop changes', async () => {
|
|
304
|
+
const page = await setupPage();
|
|
305
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
306
|
+
page.rootInstance.queuedFiles = [];
|
|
307
|
+
page.rootInstance.displayedFiles = [{ file: mockFile, status: 'queued' }];
|
|
308
|
+
page.rootInstance.updateFileList([{ name: 'test-file', status: 'uploaded' }]);
|
|
309
|
+
await page.waitForChanges();
|
|
310
|
+
expect(page.rootInstance.displayedFiles).toEqual([{ file: mockFile, status: 'uploaded' }]);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
describe('Local methods', () => {
|
|
315
|
+
describe('disableLoaderIfAllFilesUploaded', () => {
|
|
316
|
+
it('sets the areFilesUploading flag to false when all files are uploaded', async () => {
|
|
317
|
+
const page = await setupPage();
|
|
318
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
319
|
+
page.rootInstance.areFilesUploading = true;
|
|
320
|
+
page.rootInstance.displayedFiles = [{ file: mockFile, status: 'uploaded' }];
|
|
321
|
+
page.rootInstance.disableLoaderIfAllFilesUploaded();
|
|
322
|
+
await page.waitForChanges();
|
|
323
|
+
expect(page.rootInstance.areFilesUploading).toBeFalsy();
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
describe('getAnimationendHandlerToRemoveFileItem', () => {
|
|
327
|
+
it('returns a function that removes a file after animation has ended', async () => {
|
|
328
|
+
const page = await setupPage();
|
|
329
|
+
const fileItem = {
|
|
330
|
+
file: createMockFile(),
|
|
331
|
+
status: 'uploaded',
|
|
332
|
+
};
|
|
333
|
+
page.rootInstance.displayedFiles = [fileItem];
|
|
334
|
+
const animationEndHandler = page.rootInstance.getAnimationendHandlerToRemoveFileItem(fileItem.file.name);
|
|
335
|
+
const mockAnimationEvent = {
|
|
336
|
+
animationName: 'shrinkToCenterFadeOut',
|
|
337
|
+
};
|
|
338
|
+
animationEndHandler(mockAnimationEvent);
|
|
339
|
+
expect(page.rootInstance.displayedFiles.length).toEqual(0);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
describe('getClickHandlerToRemoveFileItem', () => {
|
|
343
|
+
it('returns a function that flags the file as to be removed', async () => {
|
|
344
|
+
const page = await setupPage();
|
|
345
|
+
const fileItem = {
|
|
346
|
+
file: createMockFile(),
|
|
347
|
+
status: 'uploaded',
|
|
348
|
+
};
|
|
349
|
+
page.rootInstance.displayedFiles = [fileItem];
|
|
350
|
+
const clickHandler = page.rootInstance.getClickHandlerToRemoveFileItem(fileItem.file.name);
|
|
351
|
+
clickHandler();
|
|
352
|
+
expect(page.rootInstance.displayedFiles[0].toBeRemoved).toBeTruthy();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
describe('getFileItemStatusMessage', () => {
|
|
356
|
+
it('returns the correct status message', async () => {
|
|
357
|
+
const page = await setupPage();
|
|
358
|
+
const statusAndResponses = [
|
|
359
|
+
{ status: 'invalid-type', response: 'tecton.element.filePicker.unsupportedFileType' },
|
|
360
|
+
{ status: 'over-size-limit', response: 'tecton.element.filePicker.sizeExceedsLimit' },
|
|
361
|
+
{ status: 'over-max-files-limit', response: 'tecton.element.filePicker.overMaxFilesLimit' },
|
|
362
|
+
{ status: 'in-progress', response: 'tecton.element.filePicker.uploadingEllipsis' },
|
|
363
|
+
{ status: 'failed', response: 'tecton.element.filePicker.uploadFailed' },
|
|
364
|
+
{ status: 'uploaded', response: 'tecton.element.filePicker.fileSize' },
|
|
365
|
+
];
|
|
366
|
+
const size = 1234;
|
|
367
|
+
statusAndResponses.forEach(({ status, response }) => {
|
|
368
|
+
const result = page.rootInstance.getFileItemStatusMessage(status, size);
|
|
369
|
+
expect(result).toEqual(response);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
describe('grabDroppedFiles', () => {
|
|
374
|
+
it('emits an event that contains a files object', async () => {
|
|
375
|
+
const page = await setupPage();
|
|
376
|
+
const mockFile = createMockFile({ name: 'test-file' });
|
|
377
|
+
const mockFileList = createMockFileList([mockFile]);
|
|
378
|
+
const dropCallback = jest.fn();
|
|
379
|
+
page.root.addEventListener('tctChange', dropCallback);
|
|
380
|
+
const mockDragEvent = {
|
|
381
|
+
dataTransfer: {
|
|
382
|
+
files: mockFileList,
|
|
383
|
+
},
|
|
384
|
+
preventDefault: jest.fn(),
|
|
385
|
+
stopPropagation: jest.fn(),
|
|
386
|
+
};
|
|
387
|
+
page.rootInstance.grabDroppedFiles(mockDragEvent);
|
|
388
|
+
await page.waitForChanges();
|
|
389
|
+
expect(dropCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
390
|
+
detail: expect.objectContaining({
|
|
391
|
+
invalidFiles: [],
|
|
392
|
+
validFiles: [mockFile],
|
|
393
|
+
}),
|
|
394
|
+
}));
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
describe('highlightDropZone', () => {
|
|
398
|
+
it('sets the isDropZoneHighlighted flag to true', async () => {
|
|
399
|
+
const page = await setupPage({ variant: 'browse-drop' });
|
|
400
|
+
const mockDragEvent = {
|
|
401
|
+
preventDefault: jest.fn(),
|
|
402
|
+
stopPropagation: jest.fn(),
|
|
403
|
+
};
|
|
404
|
+
page.rootInstance.highlightDropZone(mockDragEvent);
|
|
405
|
+
await page.waitForChanges();
|
|
406
|
+
expect(page.rootInstance.isDropZoneHighlighted).toBeTruthy();
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
describe('launchFileBrowser', () => {
|
|
410
|
+
it('called and clicks hidden file input when browse button clicked', async () => {
|
|
411
|
+
const launchFileBrowserSpy = jest.spyOn(Q2FilePicker.prototype, 'launchFileBrowser');
|
|
412
|
+
const page = await setupPage();
|
|
413
|
+
const input = page.root.shadowRoot.querySelector('[test-id="file-input"]');
|
|
414
|
+
const browseButton = page.root.shadowRoot.querySelector('[test-id="browse-button"]');
|
|
415
|
+
const clickCallback = jest.fn();
|
|
416
|
+
input.addEventListener('click', clickCallback);
|
|
417
|
+
browseButton.dispatchEvent(new MouseEvent('click'));
|
|
418
|
+
expect(launchFileBrowserSpy).toHaveBeenCalled();
|
|
419
|
+
expect(clickCallback).toHaveBeenCalled();
|
|
420
|
+
});
|
|
421
|
+
it('called and clicks hidden file input when browse link clicked', async () => {
|
|
422
|
+
const launchFileBrowserSpy = jest.spyOn(Q2FilePicker.prototype, 'launchFileBrowser');
|
|
423
|
+
const page = await setupPage({ variant: 'browse-drop' });
|
|
424
|
+
const input = page.root.shadowRoot.querySelector('[test-id="file-input"]');
|
|
425
|
+
const browseLink = page.root.shadowRoot.querySelector('[test-id="browse-link"]');
|
|
426
|
+
const clickCallback = jest.fn();
|
|
427
|
+
input.addEventListener('click', clickCallback);
|
|
428
|
+
await browseLink.dispatchEvent(new MouseEvent('tctClick'));
|
|
429
|
+
expect(launchFileBrowserSpy).toHaveBeenCalled();
|
|
430
|
+
expect(clickCallback).toHaveBeenCalled();
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
//# sourceMappingURL=q2-file-picker-test.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"q2-file-picker-test.spec.js","sourceRoot":"","sources":["../../../../src/components/q2-file-picker/test/q2-file-picker-test.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Q2FilePicker } from '../q2-file-picker';\nimport { objectToHTMLAttributes, setupSpecPageWithLoc } from '@/utils/helpers';\n\ndescribe('q2-legend', () => {\n interface MockFileProps {\n name?: string;\n lastModified?: number;\n webkitRelativePath?: string;\n size?: number;\n type?: string;\n arrayBuffer?: () => Promise<ArrayBuffer>;\n slice?: () => Blob;\n stream?: () => ReadableStream;\n text?: () => Promise<string>;\n bytes?: () => Promise<Uint8Array>;\n }\n\n const buildSlots = (slots: Record<string, string>[]) => {\n return slots.reduce((acc, slot) => {\n return `${acc}<div slot=\"${slot.name}\">${slot.content}</div>`;\n }, '');\n };\n\n const setupPage = async (attributes = {}, testStrings = {}, slots = []) => {\n const attributesString = objectToHTMLAttributes(attributes);\n const slotsString = buildSlots(slots);\n\n const page = await setupSpecPageWithLoc(\n {\n components: [Q2FilePicker],\n html: `<q2-file-picker ${attributesString}>${slotsString}</q2-file-picker>`,\n },\n testStrings\n );\n\n return page;\n };\n\n const createMockFile = (props: MockFileProps = {}) => {\n return {\n name: props.name || 'test-file',\n lastModified: props.lastModified || Date.now(),\n webkitRelativePath: props.webkitRelativePath || '',\n size: props.size || 1234,\n type: props.type || 'text/plain', // 'application/pdf'\n arrayBuffer: props.arrayBuffer || jest.fn(),\n slice: props.slice || jest.fn(),\n stream: props.stream || jest.fn(),\n text: props.text || jest.fn(),\n bytes: props.bytes || jest.fn(() => Promise.resolve(new Uint8Array())),\n };\n };\n\n const createMockFileList = (files: File[]) => {\n return {\n ...files,\n length: files.length,\n item: (index: number) => files[index],\n };\n };\n\n function simulateFileInputChange(page, mockFileList) {\n const input = page.root.shadowRoot.querySelector('[test-id=\"file-input\"]') as HTMLInputElement;\n const changeCallback = jest.fn();\n page.root.addEventListener('tctChange', changeCallback);\n input.files = mockFileList;\n input.dispatchEvent(new Event('change'));\n\n return changeCallback;\n }\n\n describe('Props', () => {\n describe('description', () => {\n it('when set description rendered', async () => {\n const descriptionText = 'Test Description';\n const page = await setupPage({ description: descriptionText });\n const description = page.root.shadowRoot.querySelector('[test-id=\"description\"]');\n\n expect(description).toEqualText(descriptionText);\n });\n\n it('is localizable', async () => {\n const descriptionText = 'Test Description';\n const page = await setupPage(\n { description: 'test.description' },\n { 'test.description': descriptionText }\n );\n const description = page.root.shadowRoot.querySelector('[test-id=\"description\"]');\n\n expect(description).toEqualText(descriptionText);\n });\n });\n\n describe('fileTypes', () => {\n it('limits the types of files that can be selected', async () => {\n const page = await setupPage();\n page.root.fileTypes = ['pdf'];\n const mockPdfFile = createMockFile({ name: 'test-file.pdf' });\n const mockTextFile = createMockFile({ name: 'test-file.txt' });\n const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);\n const changeCallback = simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [{ file: mockTextFile, status: 'invalid-type' }],\n validFiles: [mockPdfFile],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n\n it('allows all file types when fileTypes is not defined', async () => {\n const page = await setupPage();\n const mockPdfFile = createMockFile({ name: 'test-file.pdf' });\n const mockTextFile = createMockFile({ name: 'test-file.txt' });\n const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);\n const changeCallback = simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [],\n validFiles: [mockPdfFile, mockTextFile],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n });\n\n describe('label', () => {\n it('when set label rendered', async () => {\n const labelText = 'Test Label';\n const page = await setupPage({ label: labelText });\n const label = page.root.shadowRoot.querySelector('[test-id=\"label\"]');\n\n expect(label).toEqualText(labelText);\n });\n\n it('is localizable', async () => {\n const labelText = 'Test Label';\n const page = await setupPage({ label: 'test.label' }, { 'test.label': labelText });\n const label = page.root.shadowRoot.querySelector('[test-id=\"label\"]');\n\n expect(label).toEqualText(labelText);\n });\n });\n\n describe('maxFiles', () => {\n it('limits the number of files that can be selected', async () => {\n const page = await setupPage({ 'max-files': 0 });\n const mockPdfFile = createMockFile({ name: 'test-file.pdf', type: 'application/pdf' });\n const mockFileList = createMockFileList([mockPdfFile]);\n const changeCallback = simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [{ file: mockPdfFile, status: 'over-max-files-limit' }],\n validFiles: [],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n\n it('allows multiple files to be selected when it is greater than 1', async () => {\n const page = await setupPage({ maxFiles: 2 });\n const mockFile = createMockFile({ name: 'test-file' });\n const mockFile2 = { ...mockFile, name: 'test-file-2' };\n const mockFileListMultiple = createMockFileList([mockFile, mockFile2]);\n const changeCallback = simulateFileInputChange(page, mockFileListMultiple);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [],\n validFiles: [mockFile, mockFile2],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n\n it('allows any number of files to be selected when it is not set', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n const mockFile2 = { ...mockFile, name: 'test-file-2' };\n const mockFile3 = { ...mockFile, name: 'test-file-3' };\n const mockFileListMultiple = createMockFileList([mockFile, mockFile2, mockFile3]);\n const changeCallback = simulateFileInputChange(page, mockFileListMultiple);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [],\n validFiles: [mockFile, mockFile2, mockFile3],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n });\n\n describe('maxFileSize', () => {\n it('limits the size of files that can be selected', async () => {\n const page = await setupPage({ 'max-file-size': 2000 });\n const mockFile = createMockFile({ name: 'test-file', size: 1000 });\n const mockFileTooLarge = createMockFile({ name: 'test-file-2', size: 3000 });\n const mockFileList = createMockFileList([mockFile, mockFileTooLarge]);\n const changeCallback = simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [{ file: mockFileTooLarge, status: 'over-size-limit' }],\n validFiles: [mockFile],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n expect(value).toEqual(expectedValue);\n });\n });\n\n describe('value', () => {\n it('returns an object with empty arrays for prop values when no files have been selected', async () => {\n const page = await setupPage();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [],\n validFiles: [],\n };\n\n expect(value).toEqual(expectedValue);\n });\n\n it('returns an object with the selected files when files have been selected', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n const mockFileList = createMockFileList([mockFile]);\n simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [],\n validFiles: [mockFile],\n };\n\n expect(value).toEqual(expectedValue);\n });\n\n it('returns an object with the valid and invalid files when files have been selected', async () => {\n const page = await setupPage();\n page.root.fileTypes = ['pdf'];\n const mockPdfFile = createMockFile({ name: 'test-file.pdf', type: 'application/pdf' });\n const mockTextFile = createMockFile({ name: 'test-file.txt' });\n const mockFileList = createMockFileList([mockPdfFile, mockTextFile]);\n simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const value = page.root.value;\n const expectedValue = {\n invalidFiles: [{ file: mockTextFile, status: 'invalid-type' }],\n validFiles: [mockPdfFile],\n };\n\n expect(value).toEqual(expectedValue);\n });\n });\n\n describe('variant', () => {\n it('when set to \"browse-drop\" displays drop zone', async () => {\n const page = await setupPage({ variant: 'browse-drop' });\n const dropZone = page.root.shadowRoot.querySelector('[test-id=\"drop-zone\"]');\n const browseButton = page.root.shadowRoot.querySelector('[test-id=\"browse-button\"]');\n\n expect(dropZone).not.toBeNull();\n expect(browseButton).toBeNull();\n });\n\n it('when set to \"browse\" displays only the browse button', async () => {\n const page = await setupPage({ variant: 'browse' });\n const dropZone = page.root.shadowRoot.querySelector('[test-id=\"drop-zone\"]');\n const browseButton = page.root.shadowRoot.querySelector('[test-id=\"browse\"]');\n\n expect(dropZone).toBeNull();\n expect(browseButton).not.toBeNull();\n });\n });\n });\n\n describe('Slots', () => {\n describe('label', () => {\n it('rendered when slot is provided', async () => {\n const labelSlotContent = 'Test Label Slot';\n const page = await setupPage({}, {}, [{ name: 'label', content: labelSlotContent }]);\n const label = page.root.shadowRoot.querySelector('[test-id=\"label\"]');\n\n // check for the slot container without the slot content because\n // newSpecPage appears to not render the slot content\n expect(label.innerHTML).toEqualHtml('<slot name=\"label\"></slot>');\n });\n\n it('not rendered when slot is provided and label prop set', async () => {\n const labelText = 'Test Label';\n const labelSlotContent = 'Test Label Slot';\n const page = await setupPage({ label: labelText }, {}, [{ name: 'label', content: labelSlotContent }]);\n const label = page.root.shadowRoot.querySelector('[test-id=\"label\"]');\n\n expect(label.innerHTML).toEqualHtml(labelText);\n });\n });\n\n describe('description', () => {\n it('rendered when slot is provided', async () => {\n const descriptionSlotContent = 'Test Description Slot';\n const page = await setupPage({}, {}, [{ name: 'description', content: descriptionSlotContent }]);\n const description = page.root.shadowRoot.querySelector('[test-id=\"description\"]');\n\n // check for the slot container without the slot content because\n // newSpecPage appears to not render the slot content\n expect(description.innerHTML).toEqualHtml('<slot name=\"description\"></slot>');\n });\n\n it('not rendered when slot is provided and label prop set', async () => {\n const descriptionText = 'Test Description';\n const descriptionSlotContent = 'Test Description Slot';\n const page = await setupPage({ description: descriptionText }, {}, [\n { name: 'description', content: descriptionSlotContent },\n ]);\n const label = page.root.shadowRoot.querySelector('[test-id=\"description\"]');\n\n expect(label.innerHTML).toEqualHtml(descriptionText);\n });\n });\n });\n\n describe('Events', () => {\n describe('tctChange', () => {\n it('emitted when a file input emits a change event', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n const mockFileList = createMockFileList([mockFile]);\n const changeCallback = simulateFileInputChange(page, mockFileList);\n await page.waitForChanges();\n const expectedValue = {\n invalidFiles: [],\n validFiles: [mockFile],\n };\n\n expect(changeCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining(expectedValue),\n })\n );\n });\n });\n });\n\n describe('Watchers', () => {\n describe('updateFileList', () => {\n it('sets the status of a queued file when the status prop changes', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n page.rootInstance.queuedFiles = [mockFile];\n page.rootInstance.updateFileList([{ name: 'test-file', status: 'uploaded' }]);\n await page.waitForChanges();\n\n expect(page.rootInstance.displayedFiles).toEqual([{ file: mockFile, status: 'uploaded' }]);\n });\n\n it('sets the status of a displayed file when the status prop changes', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n page.rootInstance.queuedFiles = [];\n page.rootInstance.displayedFiles = [{ file: mockFile, status: 'queued' }];\n page.rootInstance.updateFileList([{ name: 'test-file', status: 'uploaded' }]);\n await page.waitForChanges();\n\n expect(page.rootInstance.displayedFiles).toEqual([{ file: mockFile, status: 'uploaded' }]);\n });\n });\n });\n\n describe('Local methods', () => {\n describe('disableLoaderIfAllFilesUploaded', () => {\n it('sets the areFilesUploading flag to false when all files are uploaded', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n page.rootInstance.areFilesUploading = true;\n page.rootInstance.displayedFiles = [{ file: mockFile, status: 'uploaded' }];\n page.rootInstance.disableLoaderIfAllFilesUploaded();\n await page.waitForChanges();\n\n expect(page.rootInstance.areFilesUploading).toBeFalsy();\n });\n });\n\n describe('getAnimationendHandlerToRemoveFileItem', () => {\n it('returns a function that removes a file after animation has ended', async () => {\n const page = await setupPage();\n const fileItem = {\n file: createMockFile(),\n status: 'uploaded',\n };\n page.rootInstance.displayedFiles = [fileItem];\n const animationEndHandler = page.rootInstance.getAnimationendHandlerToRemoveFileItem(\n fileItem.file.name\n );\n const mockAnimationEvent = {\n animationName: 'shrinkToCenterFadeOut',\n } as AnimationEvent;\n animationEndHandler(mockAnimationEvent);\n\n expect(page.rootInstance.displayedFiles.length).toEqual(0);\n });\n });\n\n describe('getClickHandlerToRemoveFileItem', () => {\n it('returns a function that flags the file as to be removed', async () => {\n const page = await setupPage();\n const fileItem = {\n file: createMockFile(),\n status: 'uploaded',\n };\n page.rootInstance.displayedFiles = [fileItem];\n const clickHandler = page.rootInstance.getClickHandlerToRemoveFileItem(fileItem.file.name);\n clickHandler();\n\n expect(page.rootInstance.displayedFiles[0].toBeRemoved).toBeTruthy();\n });\n });\n\n describe('getFileItemStatusMessage', () => {\n it('returns the correct status message', async () => {\n const page = await setupPage();\n\n const statusAndResponses = [\n { status: 'invalid-type', response: 'tecton.element.filePicker.unsupportedFileType' },\n { status: 'over-size-limit', response: 'tecton.element.filePicker.sizeExceedsLimit' },\n { status: 'over-max-files-limit', response: 'tecton.element.filePicker.overMaxFilesLimit' },\n { status: 'in-progress', response: 'tecton.element.filePicker.uploadingEllipsis' },\n { status: 'failed', response: 'tecton.element.filePicker.uploadFailed' },\n { status: 'uploaded', response: 'tecton.element.filePicker.fileSize' },\n ];\n const size = 1234;\n\n statusAndResponses.forEach(({ status, response }) => {\n const result = page.rootInstance.getFileItemStatusMessage(status, size);\n\n expect(result).toEqual(response);\n });\n });\n });\n\n describe('grabDroppedFiles', () => {\n it('emits an event that contains a files object', async () => {\n const page = await setupPage();\n const mockFile = createMockFile({ name: 'test-file' });\n const mockFileList = createMockFileList([mockFile]);\n const dropCallback = jest.fn();\n page.root.addEventListener('tctChange', dropCallback);\n const mockDragEvent = {\n dataTransfer: {\n files: mockFileList,\n },\n preventDefault: jest.fn(),\n stopPropagation: jest.fn(),\n } as unknown as DragEvent;\n page.rootInstance.grabDroppedFiles(mockDragEvent);\n await page.waitForChanges();\n\n expect(dropCallback).toHaveBeenCalledWith(\n expect.objectContaining({\n detail: expect.objectContaining({\n invalidFiles: [],\n validFiles: [mockFile],\n }),\n })\n );\n });\n });\n\n describe('highlightDropZone', () => {\n it('sets the isDropZoneHighlighted flag to true', async () => {\n const page = await setupPage({ variant: 'browse-drop' });\n const mockDragEvent = {\n preventDefault: jest.fn(),\n stopPropagation: jest.fn(),\n } as unknown as DragEvent;\n page.rootInstance.highlightDropZone(mockDragEvent);\n await page.waitForChanges();\n\n expect(page.rootInstance.isDropZoneHighlighted).toBeTruthy();\n });\n });\n\n describe('launchFileBrowser', () => {\n it('called and clicks hidden file input when browse button clicked', async () => {\n const launchFileBrowserSpy = jest.spyOn(Q2FilePicker.prototype, 'launchFileBrowser');\n const page = await setupPage();\n const input = page.root.shadowRoot.querySelector('[test-id=\"file-input\"]');\n const browseButton = page.root.shadowRoot.querySelector('[test-id=\"browse-button\"]');\n const clickCallback = jest.fn();\n input.addEventListener('click', clickCallback);\n browseButton.dispatchEvent(new MouseEvent('click'));\n\n expect(launchFileBrowserSpy).toHaveBeenCalled();\n expect(clickCallback).toHaveBeenCalled();\n });\n\n it('called and clicks hidden file input when browse link clicked', async () => {\n const launchFileBrowserSpy = jest.spyOn(Q2FilePicker.prototype, 'launchFileBrowser');\n const page = await setupPage({ variant: 'browse-drop' });\n const input = page.root.shadowRoot.querySelector('[test-id=\"file-input\"]');\n const browseLink = page.root.shadowRoot.querySelector('[test-id=\"browse-link\"]');\n const clickCallback = jest.fn();\n input.addEventListener('click', clickCallback);\n await browseLink.dispatchEvent(new MouseEvent('tctClick'));\n\n expect(launchFileBrowserSpy).toHaveBeenCalled();\n expect(clickCallback).toHaveBeenCalled();\n });\n });\n });\n});\n"]}
|
|
@@ -167,4 +167,10 @@ button {
|
|
|
167
167
|
font-size: var(--tct-list-label-font-size, var(--app-font-size, 14px));
|
|
168
168
|
font-weight: var(--tct-list-label-font-weight, 600);
|
|
169
169
|
color: var(--tct-list-label-font-color, var(--t-text, #4d4d4d));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
slot:not([name]) {
|
|
173
|
+
display: flex;
|
|
174
|
+
flex-direction: column;
|
|
175
|
+
gap: var(--tct-list-item-gap, 0);
|
|
170
176
|
}
|
|
@@ -26,6 +26,7 @@ export class Q2Pill {
|
|
|
26
26
|
};
|
|
27
27
|
this.executeActionSheet = async (event) => {
|
|
28
28
|
const result = await showActionSheetList(this, event);
|
|
29
|
+
this.primaryBtn.focus();
|
|
29
30
|
this.handleSelectionChanges(result);
|
|
30
31
|
};
|
|
31
32
|
this.getOption = async (value) => {
|
|
@@ -37,9 +38,12 @@ export class Q2Pill {
|
|
|
37
38
|
return this.hostElement.querySelector(`q2-option[value="${value}"]`);
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
|
-
this.
|
|
41
|
+
this.handleFocusOut = async (event) => {
|
|
42
|
+
var _a;
|
|
41
43
|
const relatedTarget = event.relatedTarget;
|
|
42
|
-
if ((
|
|
44
|
+
if ((_a = this.popoverElement) === null || _a === void 0 ? void 0 : _a.contains(relatedTarget))
|
|
45
|
+
return;
|
|
46
|
+
if (this.hostElement.contains(relatedTarget))
|
|
43
47
|
return;
|
|
44
48
|
this.open = false;
|
|
45
49
|
};
|
|
@@ -337,7 +341,7 @@ export class Q2Pill {
|
|
|
337
341
|
wrapperClassNames.push('has-icon');
|
|
338
342
|
if (optionCount)
|
|
339
343
|
wrapperClassNames.push('has-options');
|
|
340
|
-
return (h("click-elsewhere", { key: '
|
|
344
|
+
return (h("click-elsewhere", { key: '65e932df96cd2135dd8340aefea2523e0ac3084c', onChange: this.onClickElsewhere }, h("div", { key: '0c4dfad1705c5f0f72ac03878776bdad4e209fa0', class: wrapperClassNames.join(' ') }, h("div", { key: 'da4d69d59bdbb4609e6638fce7b3abbf53c791e7', class: "btn-height-wrapper", ref: el => (this.primaryBtnWrapper = el), onClick: this.handleWrapperClick, tabIndex: -1 }, h("button", { key: '0d5f3a4984991bb1c47c241d9cf6676d486cd4dd', class: "btn-primary", "test-id": "btn-control", type: "button", role: (optionCount && 'combobox') || undefined, ref: el => (this.primaryBtn = el), onClick: this.handleClick, onKeyDown: this.handleKeydown, onFocusout: this.handleFocusOut, disabled: this.disabled, "aria-roledescription": !optionCount && 'filter', "aria-controls": (optionCount && 'option-list') || undefined, "aria-expanded": (optionCount && `${!!open}`) || undefined, "aria-label": this.buttonContent, "aria-describedby": (optionCount && 'option-description') || undefined }, this.truncatedButtonContent, !optionCount && active && h("span", { key: '18619ff31d265eaa351390a367ef3712dbd9547a', class: "sr" }, "(", loc('tecton.element.pill.active'), ")"))), this.renderIcon(), !!optionCount && this.renderHiddenElement()), this.optionCount > 0 && (h("q2-popover", { key: '02eb90f588ea93c7153bdbaa709eaac678359249', ref: el => (this.popoverElement = el), controlElement: this.primaryBtn, open: this.open, "max-height": this.popoverMaxHeight, minHeight: this.popoverMinHeight, direction: this.popoverDirection, align: this.popoverAlignment, onFocusout: this.handleFocusOut }, h("div", { key: 'eb74c87224cc28e45db944411cc749350c99e77b', class: "popover-content" }, h("div", { key: 'de444989719d4c154f17e484918ee6e206414642', ref: el => (this.popoverTopContainer = el), class: "popover-top-container", tabindex: "-1", hidden: !this.hasPopoverTop, onKeyDown: this.handleKeydown }, h("slot", { key: 'b58a201205c6a3980425db57d551fcd6f01583e0', name: "popover-top" })), h("q2-option-list", { key: '1eb22efce706be5803dc035cedb9232ea1bcbde8', type: "listbox", ref: el => (this.optionList = el), id: "option-list", onChange: this.handleChange, multiple: this.multiple, selectedOptions: this.selectedOptions, onReady: () => this.updateSelectedOptionElements(), label: loc('tecton.element.optionList.label', [this.optionListLabel]) }, h("slot", { key: 'de65981f3e33f12693927e4b5d9510fe751537d6' })), h("div", { key: '1c78d8873df7f63f7e7eab76c3a1a33459d3af4f', ref: el => (this.popoverBottomContainer = el), class: "popover-bottom-container", tabindex: "-1", hidden: !this.hasPopoverBottom, onKeyDown: this.handleKeydown }, h("slot", { key: '8eee76d64492fde1b01fd55f8d3e4ecb099d0b4e', name: "popover-bottom" })))))));
|
|
341
345
|
}
|
|
342
346
|
static get is() { return "q2-pill"; }
|
|
343
347
|
static get encapsulation() { return "shadow"; }
|