@descope-ui/descope-address-field 0.0.1
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/CHANGELOG.md +13 -0
- package/e2e/descope-address-field-connector-google.spec.ts +190 -0
- package/e2e/descope-address-field-connector-radar.spec.ts +167 -0
- package/e2e/descope-address-field.spec.ts +464 -0
- package/e2e/mocks.ts +41 -0
- package/package.json +33 -0
- package/project.json +17 -0
- package/src/component/AddressFieldClass.js +135 -0
- package/src/component/descope-address-field-internal/AddressFieldInternal.js +139 -0
- package/src/component/descope-address-field-internal/index.js +3 -0
- package/src/component/index.js +9 -0
- package/src/connectors/google.js +119 -0
- package/src/connectors/googleScriptInit.js +12 -0
- package/src/connectors/index.js +2 -0
- package/src/connectors/radar.js +100 -0
- package/src/theme.js +16 -0
- package/stories/descope-address-field.stories.js +166 -0
- package/stories/mockConnector.js +82 -0
- package/testDriver/addressFieldTestDriver.ts +49 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { test, expect, Page } from '@playwright/test';
|
|
2
|
+
import { getStoryUrl, loopConfig, loopPresets } from 'e2e-utils';
|
|
3
|
+
import createAddressFieldTestDriver from '../testDriver/addressFieldTestDriver';
|
|
4
|
+
|
|
5
|
+
const storyName = 'descope-address-field';
|
|
6
|
+
const componentName = 'descope-address-field';
|
|
7
|
+
|
|
8
|
+
const BooleanValues = ['true', 'false'];
|
|
9
|
+
|
|
10
|
+
const componentAttributes = {
|
|
11
|
+
label: 'address label',
|
|
12
|
+
placeholder: 'Test placeholder',
|
|
13
|
+
size: ['xs', 'sm', 'md', 'lg'],
|
|
14
|
+
bordered: BooleanValues,
|
|
15
|
+
readonly: BooleanValues,
|
|
16
|
+
required: BooleanValues,
|
|
17
|
+
'full-width': BooleanValues,
|
|
18
|
+
disabled: 'true',
|
|
19
|
+
'default-value': 'test value',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
test.describe('theme', () => {
|
|
23
|
+
const { placeholder, ...restConfig } = componentAttributes;
|
|
24
|
+
|
|
25
|
+
loopPresets(
|
|
26
|
+
{
|
|
27
|
+
'with placeholder': { placeholder },
|
|
28
|
+
'with default-value and allow-custom-value': {
|
|
29
|
+
'default-value': 'default value',
|
|
30
|
+
'allow-custom-value': 'true',
|
|
31
|
+
},
|
|
32
|
+
'with default-value and not allow-custom-value': {
|
|
33
|
+
'default-value': 'default value',
|
|
34
|
+
'allow-custom-value': 'false',
|
|
35
|
+
},
|
|
36
|
+
'rtl with default-value': {
|
|
37
|
+
'default-value': '-default value',
|
|
38
|
+
direction: 'rtl',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
(preset, name) => {
|
|
42
|
+
test.describe(name, () => {
|
|
43
|
+
test.beforeEach(async ({ page }) => {
|
|
44
|
+
await page.goto(getStoryUrl(storyName, preset));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('hover', async ({ page }) => {
|
|
48
|
+
const component = createAddressFieldTestDriver(
|
|
49
|
+
page.locator(componentName),
|
|
50
|
+
);
|
|
51
|
+
await component.hover();
|
|
52
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('focus', async ({ page }) => {
|
|
56
|
+
const component = createAddressFieldTestDriver(
|
|
57
|
+
page.locator(componentName),
|
|
58
|
+
);
|
|
59
|
+
await component.focus();
|
|
60
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
loopPresets(
|
|
67
|
+
{
|
|
68
|
+
'with label and required': {
|
|
69
|
+
label: '-Label',
|
|
70
|
+
placeholder: '-Placeholder',
|
|
71
|
+
required: 'true',
|
|
72
|
+
},
|
|
73
|
+
'with floating label and required': {
|
|
74
|
+
label: '-Label',
|
|
75
|
+
placeholder: '-Placeholder',
|
|
76
|
+
required: 'true',
|
|
77
|
+
'label-type': 'floating',
|
|
78
|
+
},
|
|
79
|
+
'with label and not required': {
|
|
80
|
+
label: '-Label',
|
|
81
|
+
placeholder: '-Placeholder',
|
|
82
|
+
required: 'false',
|
|
83
|
+
},
|
|
84
|
+
'with floating label and not required': {
|
|
85
|
+
label: '-Label',
|
|
86
|
+
placeholder: '-Placeholder',
|
|
87
|
+
required: 'false',
|
|
88
|
+
'label-type': 'floating',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
(preset, name) => {
|
|
92
|
+
test(name, async ({ page }) => {
|
|
93
|
+
await page.goto(getStoryUrl(storyName, preset));
|
|
94
|
+
const component = createAddressFieldTestDriver(
|
|
95
|
+
page.locator(componentName),
|
|
96
|
+
);
|
|
97
|
+
expect(
|
|
98
|
+
await component.screenshot({ animations: 'disabled' }),
|
|
99
|
+
).toMatchSnapshot();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test(`rtl ${name}`, async ({ page }) => {
|
|
103
|
+
await page.goto(
|
|
104
|
+
getStoryUrl(storyName, { ...preset, direction: 'rtl' }),
|
|
105
|
+
);
|
|
106
|
+
const component = createAddressFieldTestDriver(
|
|
107
|
+
page.locator(componentName),
|
|
108
|
+
);
|
|
109
|
+
expect(
|
|
110
|
+
await component.screenshot({ animations: 'disabled' }),
|
|
111
|
+
).toMatchSnapshot();
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
['', 'rtl'].forEach((direction) => {
|
|
117
|
+
test(`${!!direction ? 'rtl ' : ''}default error message`, async ({
|
|
118
|
+
page,
|
|
119
|
+
}) => {
|
|
120
|
+
await page.goto(
|
|
121
|
+
getStoryUrl(storyName, {
|
|
122
|
+
label: '-Label',
|
|
123
|
+
placeholder: '-Placeholder',
|
|
124
|
+
required: 'true',
|
|
125
|
+
direction,
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
const component = createAddressFieldTestDriver(
|
|
129
|
+
page.locator(componentName),
|
|
130
|
+
);
|
|
131
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
132
|
+
expect(
|
|
133
|
+
await component.screenshot({ timeout: 1000, animations: 'disabled' }),
|
|
134
|
+
).toMatchSnapshot();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
['', 'rtl'].forEach((direction) => {
|
|
139
|
+
test(`${!!direction ? 'rtl ' : ''}custom error message`, async ({
|
|
140
|
+
page,
|
|
141
|
+
}) => {
|
|
142
|
+
await page.goto(
|
|
143
|
+
getStoryUrl(storyName, {
|
|
144
|
+
label: '-Label',
|
|
145
|
+
placeholder: '-Placeholder',
|
|
146
|
+
required: 'true',
|
|
147
|
+
'data-errormessage-value-missing': '-please fill it',
|
|
148
|
+
direction,
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
const component = createAddressFieldTestDriver(
|
|
152
|
+
page.locator(componentName),
|
|
153
|
+
);
|
|
154
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
155
|
+
expect(
|
|
156
|
+
await component.screenshot({ timeout: 1000, animations: 'disabled' }),
|
|
157
|
+
).toMatchSnapshot();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test.describe('with value', () => {
|
|
162
|
+
loopConfig(restConfig, (attr, value) => {
|
|
163
|
+
test.describe(`${attr}: ${value}`, () => {
|
|
164
|
+
test.beforeEach(async ({ page }) => {
|
|
165
|
+
await page.goto(getStoryUrl(storyName, { [attr]: value }));
|
|
166
|
+
const component = createAddressFieldTestDriver(
|
|
167
|
+
page.locator(componentName),
|
|
168
|
+
);
|
|
169
|
+
await component.setValue('autovalue');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('hover', async ({ page }) => {
|
|
173
|
+
const component = createAddressFieldTestDriver(
|
|
174
|
+
page.locator(componentName),
|
|
175
|
+
);
|
|
176
|
+
await component.hover();
|
|
177
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('focus', async ({ page }) => {
|
|
181
|
+
const component = createAddressFieldTestDriver(
|
|
182
|
+
page.locator(componentName),
|
|
183
|
+
);
|
|
184
|
+
await component.focus();
|
|
185
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test.describe('dropdown', () => {
|
|
192
|
+
loopPresets(
|
|
193
|
+
{
|
|
194
|
+
'size: xs': { size: 'xs' },
|
|
195
|
+
'size: sm': { size: 'sm' },
|
|
196
|
+
'size: md': { size: 'md' },
|
|
197
|
+
'size: lg': { size: 'lg' },
|
|
198
|
+
'full-width: true': { 'full-width': 'true' },
|
|
199
|
+
'full-width: false': { 'full-width': 'false' },
|
|
200
|
+
rtl: { direction: 'rtl', 'full-width': 'true' },
|
|
201
|
+
},
|
|
202
|
+
(preset, name) => {
|
|
203
|
+
test(name, async ({ page }) => {
|
|
204
|
+
await page.goto(getStoryUrl(storyName, preset));
|
|
205
|
+
const component = createAddressFieldTestDriver(
|
|
206
|
+
page.locator(componentName),
|
|
207
|
+
);
|
|
208
|
+
await component.insertValue('fastmock');
|
|
209
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
210
|
+
hasText: 'fastmock Custom Road, Sample City,',
|
|
211
|
+
});
|
|
212
|
+
await resultsLoaded.waitFor();
|
|
213
|
+
expect(await component.dropDown.screenshot()).toMatchSnapshot();
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('loading', async ({ page }) => {
|
|
220
|
+
await page.goto(getStoryUrl(storyName, {}));
|
|
221
|
+
const component = createAddressFieldTestDriver(page.locator(componentName));
|
|
222
|
+
await component.insertValue('loadin');
|
|
223
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
224
|
+
hasText: 'Custom Road',
|
|
225
|
+
});
|
|
226
|
+
await resultsLoaded.waitFor();
|
|
227
|
+
await component.insertValue('g');
|
|
228
|
+
await page.waitForTimeout(300);
|
|
229
|
+
expect(
|
|
230
|
+
await component.dropDown.screenshot({ animations: 'disabled' }),
|
|
231
|
+
).toMatchSnapshot();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('error message with icon', async ({ page }) => {
|
|
235
|
+
await page.goto(
|
|
236
|
+
getStoryUrl(storyName, { required: true, errorMsgIcon: true }),
|
|
237
|
+
);
|
|
238
|
+
const component = createAddressFieldTestDriver(page.locator(componentName));
|
|
239
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
240
|
+
await component.blur();
|
|
241
|
+
expect(
|
|
242
|
+
await component.screenshot({
|
|
243
|
+
animations: 'disabled',
|
|
244
|
+
caret: 'hide',
|
|
245
|
+
timeout: 3000,
|
|
246
|
+
}),
|
|
247
|
+
).toMatchSnapshot();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test.describe('logic', () => {
|
|
252
|
+
test.describe('min search length', () => {
|
|
253
|
+
test('default', async ({ page }) => {
|
|
254
|
+
await page.goto(getStoryUrl(storyName));
|
|
255
|
+
const component = createAddressFieldTestDriver(
|
|
256
|
+
page.locator(componentName),
|
|
257
|
+
);
|
|
258
|
+
await component.insertValue('moc');
|
|
259
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
260
|
+
hasText: ' Custom Road, Sample City,',
|
|
261
|
+
});
|
|
262
|
+
await resultsLoaded.waitFor();
|
|
263
|
+
const items = await component.getItems();
|
|
264
|
+
expect(items.length).toBeGreaterThan(0);
|
|
265
|
+
await expect(component.dropDown).toBeVisible();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('custom', async ({ page }) => {
|
|
269
|
+
await page.goto(getStoryUrl(storyName, { 'min-search-length': '4' }));
|
|
270
|
+
const component = createAddressFieldTestDriver(
|
|
271
|
+
page.locator(componentName),
|
|
272
|
+
);
|
|
273
|
+
await component.insertValue('fas');
|
|
274
|
+
// Need to have the timeout to wait for the results to load (or not)
|
|
275
|
+
await page.waitForTimeout(1000);
|
|
276
|
+
let items = await component.getItems();
|
|
277
|
+
expect(items.length).toBe(0);
|
|
278
|
+
await expect(component.dropDown).not.toBeVisible();
|
|
279
|
+
await component.insertValue('t');
|
|
280
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
281
|
+
hasText: ' Custom Road, Sample City,',
|
|
282
|
+
});
|
|
283
|
+
await resultsLoaded.waitFor();
|
|
284
|
+
items = await component.getItems();
|
|
285
|
+
expect(items.length).toBeGreaterThan(0);
|
|
286
|
+
await expect(component.dropDown).toBeVisible();
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
['', 'rtl'].forEach((direction) => {
|
|
291
|
+
test(`${!!direction ? 'rtl ' : ''}select item and clear`, async ({
|
|
292
|
+
page,
|
|
293
|
+
}) => {
|
|
294
|
+
await page.goto(getStoryUrl(storyName, { direction }));
|
|
295
|
+
const component = createAddressFieldTestDriver(
|
|
296
|
+
page.locator(componentName),
|
|
297
|
+
);
|
|
298
|
+
await component.insertValue('fastmock');
|
|
299
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
300
|
+
hasText: ' Custom Road, Sample City,',
|
|
301
|
+
});
|
|
302
|
+
await resultsLoaded.waitFor();
|
|
303
|
+
await component.selectItem('mock');
|
|
304
|
+
expect(await component.getValue()).toBe(
|
|
305
|
+
'fastmock Custom Road, Sample City, SC 54321',
|
|
306
|
+
);
|
|
307
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
308
|
+
await component.openDropdown();
|
|
309
|
+
expect(await component.dropDown.screenshot()).toMatchSnapshot();
|
|
310
|
+
await component.blur();
|
|
311
|
+
await component.clearSelection();
|
|
312
|
+
expect(await component.getValue()).toBe('');
|
|
313
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test.describe('set value', () => {
|
|
318
|
+
test('allow custom value', async ({ page }) => {
|
|
319
|
+
await page.goto(getStoryUrl(storyName, { 'allow-custom-value': 'true' }));
|
|
320
|
+
const component = createAddressFieldTestDriver(
|
|
321
|
+
page.locator(componentName),
|
|
322
|
+
);
|
|
323
|
+
await component.setValue('set value');
|
|
324
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
325
|
+
expect(await component.getValue()).toBe('set value');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('not allow custom value', async ({ page }) => {
|
|
329
|
+
await page.goto(
|
|
330
|
+
getStoryUrl(storyName, { 'allow-custom-value': 'false' }),
|
|
331
|
+
);
|
|
332
|
+
const component = createAddressFieldTestDriver(
|
|
333
|
+
page.locator(componentName),
|
|
334
|
+
);
|
|
335
|
+
await component.setValue('set value');
|
|
336
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
337
|
+
expect(await component.getValue()).toBe('set value');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test.describe('search and blur', () => {
|
|
342
|
+
test('allow custom value', async ({ page }) => {
|
|
343
|
+
await page.goto(getStoryUrl(storyName, { 'allow-custom-value': 'true' }));
|
|
344
|
+
const component = createAddressFieldTestDriver(
|
|
345
|
+
page.locator(componentName),
|
|
346
|
+
);
|
|
347
|
+
await component.insertValue('fastmock1');
|
|
348
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
349
|
+
hasText: 'Custom Road, Sample City,',
|
|
350
|
+
});
|
|
351
|
+
await resultsLoaded.waitFor();
|
|
352
|
+
const items = await component.getItems();
|
|
353
|
+
expect(items.length).toBeGreaterThan(0);
|
|
354
|
+
await expect(component.dropDown).toBeVisible();
|
|
355
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
356
|
+
await expect(component.dropDown).not.toBeVisible({ timeout: 1000 });
|
|
357
|
+
expect(await component.getValue()).toBe('fastmock1');
|
|
358
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test('not allow custom value', async ({ page }) => {
|
|
362
|
+
await page.goto(
|
|
363
|
+
getStoryUrl(storyName, { 'allow-custom-value': 'false' }),
|
|
364
|
+
);
|
|
365
|
+
const component = createAddressFieldTestDriver(
|
|
366
|
+
page.locator(componentName),
|
|
367
|
+
);
|
|
368
|
+
await component.insertValue('fastmock1');
|
|
369
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
370
|
+
hasText: 'Custom Road, Sample City,',
|
|
371
|
+
});
|
|
372
|
+
await resultsLoaded.waitFor();
|
|
373
|
+
const items = await component.getItems();
|
|
374
|
+
expect(items.length).toBeGreaterThan(0);
|
|
375
|
+
await expect(component.dropDown).toBeVisible();
|
|
376
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
377
|
+
await expect(component.dropDown).not.toBeVisible({ timeout: 1000 });
|
|
378
|
+
expect(await component.getValue()).toBe('');
|
|
379
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test('select - allow custom value', async ({ page }) => {
|
|
383
|
+
await page.goto(getStoryUrl(storyName, { 'allow-custom-value': 'true' }));
|
|
384
|
+
const locator = page.locator(componentName);
|
|
385
|
+
const component = createAddressFieldTestDriver(locator);
|
|
386
|
+
await component.insertValue('fastmock');
|
|
387
|
+
let resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
388
|
+
hasText: 'Custom Road, Sample City,',
|
|
389
|
+
});
|
|
390
|
+
await resultsLoaded.waitFor();
|
|
391
|
+
await component.selectItem('mock');
|
|
392
|
+
expect(await component.getValue()).toBe(
|
|
393
|
+
'fastmock Custom Road, Sample City, SC 54321',
|
|
394
|
+
);
|
|
395
|
+
await expect(component.dropDown).not.toBeVisible();
|
|
396
|
+
await component.replaceSearchValue('fasthello');
|
|
397
|
+
resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
398
|
+
hasText: 'fasthello Custom Road, Sample City,',
|
|
399
|
+
});
|
|
400
|
+
await resultsLoaded.waitFor();
|
|
401
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
402
|
+
await expect(component.dropDown).not.toBeVisible({ timeout: 1000 });
|
|
403
|
+
expect(await component.getValue()).toBe('fasthello');
|
|
404
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test('select - not allow custom value', async ({ page }) => {
|
|
408
|
+
await page.goto(
|
|
409
|
+
getStoryUrl(storyName, { 'allow-custom-value': 'false' }),
|
|
410
|
+
);
|
|
411
|
+
const locator = page.locator(componentName);
|
|
412
|
+
const component = createAddressFieldTestDriver(locator);
|
|
413
|
+
await component.insertValue('fastmock');
|
|
414
|
+
let resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
415
|
+
hasText: 'Custom Road, Sample City,',
|
|
416
|
+
});
|
|
417
|
+
await resultsLoaded.waitFor();
|
|
418
|
+
await component.selectItem('mock');
|
|
419
|
+
expect(await component.getValue()).toBe(
|
|
420
|
+
'fastmock Custom Road, Sample City, SC 54321',
|
|
421
|
+
);
|
|
422
|
+
await expect(component.dropDown).not.toBeVisible();
|
|
423
|
+
await component.replaceSearchValue('fasthello');
|
|
424
|
+
resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
425
|
+
hasText: 'fasthello Custom Road, Sample City,',
|
|
426
|
+
});
|
|
427
|
+
await resultsLoaded.waitFor();
|
|
428
|
+
await page.getByRole('button').getByText('Submit').click();
|
|
429
|
+
await expect(component.dropDown).not.toBeVisible({ timeout: 1000 });
|
|
430
|
+
expect(await component.getValue()).toBe(
|
|
431
|
+
'fastmock Custom Road, Sample City, SC 54321',
|
|
432
|
+
);
|
|
433
|
+
expect(await component.screenshot()).toMatchSnapshot();
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test('no results', async ({ page }) => {
|
|
438
|
+
await page.goto(getStoryUrl(storyName, {}));
|
|
439
|
+
const component = createAddressFieldTestDriver(page.locator(componentName));
|
|
440
|
+
await component.insertValue('no ');
|
|
441
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
442
|
+
hasText: 'No results',
|
|
443
|
+
});
|
|
444
|
+
await resultsLoaded.waitFor();
|
|
445
|
+
await expect(component.dropDown).toBeVisible();
|
|
446
|
+
expect(await component.dropDown.screenshot()).toMatchSnapshot();
|
|
447
|
+
const item = page.locator(componentName).getByRole('option').first();
|
|
448
|
+
await expect(item).toHaveAttribute('disabled', 'true');
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('error searching', async ({ page }) => {
|
|
452
|
+
await page.goto(getStoryUrl(storyName, {}));
|
|
453
|
+
const component = createAddressFieldTestDriver(page.locator(componentName));
|
|
454
|
+
await component.insertValue('error');
|
|
455
|
+
const resultsLoaded = page.locator('vaadin-combo-box-item', {
|
|
456
|
+
hasText: 'An error occurred',
|
|
457
|
+
});
|
|
458
|
+
await resultsLoaded.waitFor();
|
|
459
|
+
await expect(component.dropDown).toBeVisible();
|
|
460
|
+
expect(await component.dropDown.screenshot()).toMatchSnapshot();
|
|
461
|
+
const item = page.locator(componentName).getByRole('option').first();
|
|
462
|
+
await expect(item).toHaveAttribute('disabled', 'true');
|
|
463
|
+
});
|
|
464
|
+
});
|
package/e2e/mocks.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const MOCK_SUGGESTIONS = {
|
|
2
|
+
suggestions: [
|
|
3
|
+
{
|
|
4
|
+
placePrediction: {
|
|
5
|
+
placeId: 'place1',
|
|
6
|
+
text: {
|
|
7
|
+
text: '123 Mock Street, Mock City, MC 12345',
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
placePrediction: {
|
|
13
|
+
placeId: 'place2',
|
|
14
|
+
text: {
|
|
15
|
+
text: '456 Test Avenue, Mock Town, TT 67890',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
placePrediction: {
|
|
21
|
+
placeId: 'place3',
|
|
22
|
+
text: {
|
|
23
|
+
text: '789 Sample Boulevard, Mock City, DC 54321',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const MOCK_SUGGESTIONS_SINGLE = {
|
|
31
|
+
suggestions: [
|
|
32
|
+
{
|
|
33
|
+
placePrediction: {
|
|
34
|
+
placeId: 'place1',
|
|
35
|
+
text: {
|
|
36
|
+
text: '123 Mock Street, Mock City, MC 12345',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@descope-ui/descope-address-field",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"import": "./src/component/index.js"
|
|
7
|
+
},
|
|
8
|
+
"./theme": {
|
|
9
|
+
"import": "./src/theme.js"
|
|
10
|
+
},
|
|
11
|
+
"./class": {
|
|
12
|
+
"import": "./src/component/AddressFieldClass.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@playwright/test": "1.38.1",
|
|
17
|
+
"e2e-utils": "0.0.1",
|
|
18
|
+
"test-drivers": "0.0.1"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@vaadin/custom-field": "24.3.4",
|
|
22
|
+
"@descope-ui/common": "0.0.4",
|
|
23
|
+
"@descope-ui/theme-input-wrapper": "0.0.4",
|
|
24
|
+
"@descope-ui/descope-autocomplete-field": "0.0.2"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"link-workspace-packages": false
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "echo 'No tests defined' && exit 0",
|
|
31
|
+
"test:e2e": "echo 'No e2e tests defined' && exit 0"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@descope-ui/descope-address-field",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/web-components/components/descope-address-field/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"targets": {
|
|
7
|
+
"version": {
|
|
8
|
+
"executor": "@jscutlery/semver:version",
|
|
9
|
+
"options": {
|
|
10
|
+
"trackDeps": true,
|
|
11
|
+
"push": false,
|
|
12
|
+
"preset": "conventional"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"tags": []
|
|
17
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createStyleMixin,
|
|
3
|
+
draggableMixin,
|
|
4
|
+
createProxy,
|
|
5
|
+
proxyInputMixin,
|
|
6
|
+
componentNameValidationMixin,
|
|
7
|
+
} from '@descope-ui/common/components-mixins';
|
|
8
|
+
import {
|
|
9
|
+
getComponentName,
|
|
10
|
+
forwardAttrs,
|
|
11
|
+
syncAttrs,
|
|
12
|
+
} from '@descope-ui/common/components-helpers';
|
|
13
|
+
import { compose } from '@descope-ui/common/utils';
|
|
14
|
+
import { AutocompleteFieldClass } from '@descope-ui/descope-autocomplete-field/class';
|
|
15
|
+
import { componentName as descopeInternalComponentName } from './descope-address-field-internal/AddressFieldInternal';
|
|
16
|
+
|
|
17
|
+
export const componentName = getComponentName('address-field');
|
|
18
|
+
|
|
19
|
+
const customMixin = (superclass) =>
|
|
20
|
+
class AddressFieldMixinClass extends superclass {
|
|
21
|
+
get defaultValue() {
|
|
22
|
+
return this.getAttribute('default-value');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setDefaultValue() {
|
|
26
|
+
if (this.defaultValue) {
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
this.inputElement.value = this.defaultValue;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
set connectorClasses(value) {
|
|
34
|
+
this.inputElement.connectorClasses = value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get connectorClasses() {
|
|
38
|
+
return this.inputElement.connectorClasses;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
init() {
|
|
42
|
+
super.init?.();
|
|
43
|
+
const template = document.createElement('template');
|
|
44
|
+
|
|
45
|
+
template.innerHTML = `
|
|
46
|
+
<${descopeInternalComponentName}
|
|
47
|
+
tabindex="-1"
|
|
48
|
+
></${descopeInternalComponentName}>
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
this.baseElement.appendChild(template.content.cloneNode(true));
|
|
52
|
+
|
|
53
|
+
this.inputElement = this.shadowRoot.querySelector(
|
|
54
|
+
descopeInternalComponentName,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
forwardAttrs(this, this.inputElement, {
|
|
58
|
+
includeAttrs: [
|
|
59
|
+
'size',
|
|
60
|
+
'bordered',
|
|
61
|
+
'label',
|
|
62
|
+
'required',
|
|
63
|
+
'label-type',
|
|
64
|
+
'placeholder',
|
|
65
|
+
'full-width',
|
|
66
|
+
'allow-custom-value',
|
|
67
|
+
'min-search-length',
|
|
68
|
+
'no-results-message',
|
|
69
|
+
'error-fetching-results-message',
|
|
70
|
+
'data-errormessage-value-missing',
|
|
71
|
+
'invalid',
|
|
72
|
+
'error-message',
|
|
73
|
+
'readonly',
|
|
74
|
+
'disabled',
|
|
75
|
+
'st-host-direction',
|
|
76
|
+
'st-error-message-icon',
|
|
77
|
+
'st-error-message-icon-size',
|
|
78
|
+
'st-error-message-icon-padding',
|
|
79
|
+
'connector-template',
|
|
80
|
+
'public-api-key',
|
|
81
|
+
'address-types',
|
|
82
|
+
'address-language',
|
|
83
|
+
'address-region',
|
|
84
|
+
'address-limit',
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// This is required since when we remove the invalid attribute from the internal mappings field,
|
|
89
|
+
// we want to reflect the change in the parent component
|
|
90
|
+
syncAttrs(this, this.inputElement, { includeAttrs: ['invalid'] });
|
|
91
|
+
this.setDefaultValue();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const { host } = {
|
|
96
|
+
host: { selector: () => ':host' },
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const AddressFieldClass = compose(
|
|
100
|
+
createStyleMixin({
|
|
101
|
+
componentNameOverride: getComponentName('input-wrapper'),
|
|
102
|
+
}),
|
|
103
|
+
createStyleMixin({
|
|
104
|
+
mappings: {
|
|
105
|
+
hostWidth: { ...host, property: 'width' },
|
|
106
|
+
hostDirection: { ...host, property: 'direction' },
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
draggableMixin,
|
|
110
|
+
proxyInputMixin({
|
|
111
|
+
proxyProps: ['value', 'selectionStart'],
|
|
112
|
+
inputEvent: 'input',
|
|
113
|
+
proxyParentValidation: true,
|
|
114
|
+
}),
|
|
115
|
+
componentNameValidationMixin,
|
|
116
|
+
customMixin,
|
|
117
|
+
)(
|
|
118
|
+
createProxy({
|
|
119
|
+
slots: [],
|
|
120
|
+
wrappedEleName: 'vaadin-custom-field',
|
|
121
|
+
style: () => `
|
|
122
|
+
:host {
|
|
123
|
+
display: inline-flex;
|
|
124
|
+
max-width: 100%;
|
|
125
|
+
direction: ltr;
|
|
126
|
+
}
|
|
127
|
+
vaadin-custom-field {
|
|
128
|
+
line-height: unset;
|
|
129
|
+
width: 100%;
|
|
130
|
+
}
|
|
131
|
+
`,
|
|
132
|
+
excludeAttrsSync: ['tabindex', 'error-message', 'label'],
|
|
133
|
+
componentName,
|
|
134
|
+
}),
|
|
135
|
+
);
|