lightning-base-components 1.18.4-alpha → 1.18.5-alpha
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/metadata/raptor.json +21 -0
- package/package.json +3 -2
- package/src/lightning/baseCombobox/baseCombobox.js +20 -14
- package/src/lightning/buttonIcon/buttonIcon.js +19 -16
- package/src/lightning/combobox/combobox.js +17 -16
- package/src/lightning/tab/tab.css +2 -0
- package/src/lightning/tab/tab.js +22 -14
- package/src/lightning/tab/tab.slds.css +47 -0
- package/src/lightning/tabset/tabset.css +10 -0
- package/src/lightning/tabset/tabset.js +28 -10
- package/src/lightning/button/__wdio__/utam/utam.html +0 -3
- package/src/lightning/button/__wdio__/utam/utam.js +0 -3
- package/src/lightning/button/__wdio__/utam/utam.spec.js +0 -20
- package/src/lightning/datatable/__wdio__/utam/utam.html +0 -32
- package/src/lightning/datatable/__wdio__/utam/utam.js +0 -91
- package/src/lightning/datatable/__wdio__/utam/utam.spec.js +0 -214
package/metadata/raptor.json
CHANGED
|
@@ -3169,6 +3169,27 @@
|
|
|
3169
3169
|
{
|
|
3170
3170
|
"name": "value"
|
|
3171
3171
|
}
|
|
3172
|
+
],
|
|
3173
|
+
"methods": [
|
|
3174
|
+
{
|
|
3175
|
+
"name": "blur"
|
|
3176
|
+
},
|
|
3177
|
+
{
|
|
3178
|
+
"name": "focus"
|
|
3179
|
+
}
|
|
3180
|
+
]
|
|
3181
|
+
},
|
|
3182
|
+
"recordPickerGetRecord": {
|
|
3183
|
+
"properties": [
|
|
3184
|
+
{
|
|
3185
|
+
"name": "displayInfo"
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
"name": "objectApiName"
|
|
3189
|
+
},
|
|
3190
|
+
{
|
|
3191
|
+
"name": "recordId"
|
|
3192
|
+
}
|
|
3172
3193
|
]
|
|
3173
3194
|
},
|
|
3174
3195
|
"recordUtils": {},
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightning-base-components",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.5-alpha",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"external",
|
|
7
7
|
"scopedImports",
|
|
8
8
|
"metadata",
|
|
9
|
-
"src/lightning/*/!(__container__|
|
|
9
|
+
"src/lightning/*/!(__container__|__perf__|__raptorMocks__|__test__|__tests__)",
|
|
10
10
|
"package.json"
|
|
11
11
|
],
|
|
12
12
|
"engines": {
|
|
@@ -1306,6 +1306,7 @@
|
|
|
1306
1306
|
"lightning-radio-group",
|
|
1307
1307
|
"lightning-select",
|
|
1308
1308
|
"lightning-spinner",
|
|
1309
|
+
"lightning-tab",
|
|
1309
1310
|
"lightning-tab-bar",
|
|
1310
1311
|
"lightning-timepicker",
|
|
1311
1312
|
"lightning-vertical-navigation",
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
import { AutoPosition, Direction } from 'lightning/positionLibrary';
|
|
22
22
|
import { VARIANT } from 'lightning/inputUtils';
|
|
23
23
|
import AriaObserver from 'lightning/ariaObserver';
|
|
24
|
-
|
|
24
|
+
import { isCSR } from 'lightning/utilsPrivate';
|
|
25
25
|
const i18n = {
|
|
26
26
|
ariaSelectedOptions: labelAriaSelectedOptions,
|
|
27
27
|
deselectOptionKeyboard: labelDeselectOptionKeyboard,
|
|
@@ -51,6 +51,7 @@ const ARIA_INVALID = 'aria-invalid';
|
|
|
51
51
|
|
|
52
52
|
export default class LightningBaseCombobox extends LightningShadowBaseClass {
|
|
53
53
|
static delegatesFocus = true;
|
|
54
|
+
static validationOptOut = ['class'];
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
57
|
* Controls auto-filling of the input. Set the attribute to pass
|
|
@@ -82,17 +83,16 @@ export default class LightningBaseCombobox extends LightningShadowBaseClass {
|
|
|
82
83
|
@api attributionLogoUrl;
|
|
83
84
|
@api attributionLogoAssistiveText;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
_showDropdownActivityIndicator = false;
|
|
86
87
|
@track _items = [];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
_disabled = false;
|
|
89
|
+
_dropdownVisible = false;
|
|
90
|
+
_hasDropdownOpened = false;
|
|
91
|
+
_highlightedOptionElementId = null;
|
|
92
|
+
_variant;
|
|
93
|
+
_dropdownHeight = 'standard';
|
|
94
|
+
_readonly = false;
|
|
95
|
+
_logoLoaded = false;
|
|
96
96
|
_inputDescribedBy = [];
|
|
97
97
|
_inputAriaControls;
|
|
98
98
|
_activeElementDomId;
|
|
@@ -126,7 +126,9 @@ export default class LightningBaseCombobox extends LightningShadowBaseClass {
|
|
|
126
126
|
connectedCallback() {
|
|
127
127
|
super.connectedCallback();
|
|
128
128
|
this.setupAriaObserverIfAbsent();
|
|
129
|
-
|
|
129
|
+
if (isCSR) {
|
|
130
|
+
this.overrideDropdownAlignment();
|
|
131
|
+
}
|
|
130
132
|
this.classList.add('slds-combobox_container');
|
|
131
133
|
this._connected = true;
|
|
132
134
|
this._keyboardInterface = this.dropdownKeyboardInterface();
|
|
@@ -597,7 +599,9 @@ export default class LightningBaseCombobox extends LightningShadowBaseClass {
|
|
|
597
599
|
}
|
|
598
600
|
|
|
599
601
|
get dropdownElement() {
|
|
600
|
-
return
|
|
602
|
+
return isCSR
|
|
603
|
+
? this.template.querySelector('[data-dropdown-element]')
|
|
604
|
+
: null;
|
|
601
605
|
}
|
|
602
606
|
|
|
603
607
|
get i18n() {
|
|
@@ -942,7 +946,9 @@ export default class LightningBaseCombobox extends LightningShadowBaseClass {
|
|
|
942
946
|
}
|
|
943
947
|
|
|
944
948
|
get inputElement() {
|
|
945
|
-
return
|
|
949
|
+
return isCSR
|
|
950
|
+
? this.template.querySelector(INPUT_ELEMENT_SELECTOR)
|
|
951
|
+
: null;
|
|
946
952
|
}
|
|
947
953
|
|
|
948
954
|
// remove-next-line-for-c-namespace
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { api } from 'lwc';
|
|
2
2
|
import { classSet } from 'lightning/utils';
|
|
3
|
-
import { normalizeString as normalize } from 'lightning/utilsPrivate';
|
|
3
|
+
import { normalizeString as normalize, isCSR } from 'lightning/utilsPrivate';
|
|
4
4
|
// remove-next-line-for-c-namespace
|
|
5
5
|
import { Tooltip, TooltipType } from 'lightning/tooltipLibrary';
|
|
6
6
|
import LightningPrimitiveButton from 'lightning/primitiveButton';
|
|
@@ -89,6 +89,7 @@ export default class LightningButtonIcon extends LightningPrimitiveButton {
|
|
|
89
89
|
* @default medium
|
|
90
90
|
*/
|
|
91
91
|
_size = DEFAULT_SIZE;
|
|
92
|
+
|
|
92
93
|
@api
|
|
93
94
|
get size() {
|
|
94
95
|
return this._originalSize;
|
|
@@ -319,22 +320,24 @@ export default class LightningButtonIcon extends LightningPrimitiveButton {
|
|
|
319
320
|
connectedCallback() {
|
|
320
321
|
super.connectedCallback();
|
|
321
322
|
this._connected = true;
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
323
|
+
if (isCSR) {
|
|
324
|
+
this.dispatchEvent(
|
|
325
|
+
new CustomEvent('privatebuttoniconregister', {
|
|
326
|
+
cancelable: true,
|
|
327
|
+
bubbles: true,
|
|
328
|
+
detail: {
|
|
329
|
+
// Tooltip type should be toggle for some consumers like helptext
|
|
330
|
+
setTooltipType: (tooltipType) => {
|
|
331
|
+
this.tooltipType = tooltipType;
|
|
332
|
+
},
|
|
333
|
+
// Title should not be set for some consumers like helptext (see W-12496300)
|
|
334
|
+
showTitle: (showTitle) => {
|
|
335
|
+
this.showTitle = showTitle;
|
|
336
|
+
},
|
|
334
337
|
},
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
+
})
|
|
339
|
+
);
|
|
340
|
+
}
|
|
338
341
|
}
|
|
339
342
|
|
|
340
343
|
renderedCallback() {
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
VARIANT,
|
|
20
20
|
} from 'lightning/inputUtils';
|
|
21
21
|
|
|
22
|
+
import { isCSR } from 'lightning/utilsPrivate';
|
|
23
|
+
|
|
22
24
|
const i18n = {
|
|
23
25
|
required: labelRequired,
|
|
24
26
|
placeholder: labelPlaceholder,
|
|
@@ -30,15 +32,20 @@ const i18n = {
|
|
|
30
32
|
*/
|
|
31
33
|
export default class LightningCombobox extends LightningShadowBaseClass {
|
|
32
34
|
static delegatesFocus = true;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
static validationOptOut = ['class'];
|
|
36
|
+
|
|
37
|
+
_ariaLabelledBy = '';
|
|
38
|
+
_ariaDescribedBy = '';
|
|
39
|
+
_fieldLevelHelp = '';
|
|
40
|
+
_selectedLabel = '';
|
|
41
|
+
_disabled = false;
|
|
42
|
+
_readOnly = false;
|
|
43
|
+
_spinnerActive = false;
|
|
44
|
+
_required = false;
|
|
45
|
+
_variant;
|
|
46
|
+
_helpMessage;
|
|
47
|
+
_labelForId;
|
|
48
|
+
@track _items = [];
|
|
42
49
|
|
|
43
50
|
/**
|
|
44
51
|
* Reserved for internal use. Controls auto-filling of the field.
|
|
@@ -84,12 +91,6 @@ export default class LightningCombobox extends LightningShadowBaseClass {
|
|
|
84
91
|
*/
|
|
85
92
|
@api name;
|
|
86
93
|
|
|
87
|
-
@track _items = [];
|
|
88
|
-
@track _variant;
|
|
89
|
-
@track _helpMessage;
|
|
90
|
-
|
|
91
|
-
_labelForId;
|
|
92
|
-
|
|
93
94
|
renderedCallback() {
|
|
94
95
|
this.synchronizeA11y();
|
|
95
96
|
}
|
|
@@ -376,7 +377,7 @@ export default class LightningCombobox extends LightningShadowBaseClass {
|
|
|
376
377
|
}
|
|
377
378
|
|
|
378
379
|
get templateRootNode() {
|
|
379
|
-
return this.template.host.getRootNode();
|
|
380
|
+
return isCSR ? this.template.host.getRootNode() : null;
|
|
380
381
|
}
|
|
381
382
|
|
|
382
383
|
get i18n() {
|
package/src/lightning/tab/tab.js
CHANGED
|
@@ -1,28 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { api, track } from 'lwc';
|
|
2
2
|
import { normalizeBoolean } from 'lightning/utilsPrivate';
|
|
3
|
-
|
|
3
|
+
import LightningShadowBaseClass from 'lightning/shadowBaseClassPrivate';
|
|
4
4
|
/**
|
|
5
5
|
* A single tab in a tabset component.
|
|
6
6
|
* @slot default Placeholder for your content in lightning-tab.
|
|
7
7
|
*/
|
|
8
|
-
export default class LightningTab extends
|
|
8
|
+
export default class LightningTab extends LightningShadowBaseClass {
|
|
9
9
|
@track _loadContent = false;
|
|
10
|
+
_registered = false;
|
|
10
11
|
|
|
11
12
|
connectedCallback() {
|
|
13
|
+
super.connectedCallback();
|
|
12
14
|
this._connected = true;
|
|
15
|
+
}
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
renderedCallback() {
|
|
18
|
+
if (!this._registered) {
|
|
19
|
+
this._registered = true;
|
|
20
|
+
this.dispatchEvent(
|
|
21
|
+
new CustomEvent('privatetabregister', {
|
|
22
|
+
cancelable: true,
|
|
23
|
+
bubbles: true,
|
|
24
|
+
composed: true,
|
|
25
|
+
detail: {
|
|
26
|
+
setDeRegistrationCallback: (deRegistrationCallback) => {
|
|
27
|
+
this._deRegistrationCallback =
|
|
28
|
+
deRegistrationCallback;
|
|
29
|
+
},
|
|
22
30
|
},
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
@supports (--styling-hooks: '') {
|
|
3
|
+
/* Reassignments for parity with SLDS blueprint
|
|
4
|
+
https://www.lightningdesignsystem.com/components/tabs/#Styling-Hooks-Overview */
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
:host([data-render-mode="shadow"].slds-tabs_default__content) {
|
|
8
|
+
--slds-c-tabs-panel-spacing-block-start: var(--slds-c-tab-panel-spacing-block-start);
|
|
9
|
+
--slds-c-tabs-panel-spacing-block-end: var(--slds-c-tab-panel-spacing-block-end);
|
|
10
|
+
--slds-c-tabs-panel-spacing-inline-end: var(--slds-c-tab-panel-spacing-inline-end);
|
|
11
|
+
--slds-c-tabs-panel-spacing-inline-start: var(--slds-c-tab-panel-spacing-inline-start);
|
|
12
|
+
|
|
13
|
+
position: relative;
|
|
14
|
+
padding-block-start: var(--slds-c-tab-panel-spacing-block-start, var(--sds-g-spacing-3, 0.75rem));
|
|
15
|
+
padding-inline-end: var(--slds-c-tab-panel-spacing-inline-end, 0);
|
|
16
|
+
padding-block-end: var(--slds-c-tab-panel-spacing-block-end, var(--sds-g-spacing-3, 0.75rem));
|
|
17
|
+
padding-inline-start: var(--slds-c-tab-panel-spacing-inline-start, 0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:host([data-render-mode="shadow"].slds-tabs_scoped__content) {
|
|
21
|
+
background-color: var(--slds-g-color-neutral-base-100, var(--sds-g-color-neutral-base-100, #ffffff));
|
|
22
|
+
border: var(--sds-g-sizing-border-1, 1px) solid var(--slds-g-color-border-base-4, var(--sds-g-color-neutral-base-80, #c9c9c9));
|
|
23
|
+
border-block-start: 0;
|
|
24
|
+
border-start-start-radius: 0;
|
|
25
|
+
border-start-end-radius: 0;
|
|
26
|
+
border-end-end-radius: var(--sds-g-spacing-1, 0.25rem);
|
|
27
|
+
border-end-start-radius: var(--sds-g-spacing-1, 0.25rem);
|
|
28
|
+
padding: var(--sds-g-spacing-4, 1rem);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:host([data-render-mode="shadow"].slds-vertical-tabs__content) {
|
|
32
|
+
flex: 1;
|
|
33
|
+
padding: var(--sds-g-spacing-4, 1rem);
|
|
34
|
+
background: var(--slds-g-color-neutral-base-100, var(--sds-g-color-neutral-base-100, #ffffff));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* TODO W-12674349: Replace with Visibility Utility Classes when available */
|
|
38
|
+
:host([data-render-mode="shadow"].slds-show) {
|
|
39
|
+
display: block;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* TODO W-12674349: Replace with Visibility Utility Classes when available */
|
|
43
|
+
:host([data-render-mode="shadow"].slds-hide) {
|
|
44
|
+
display: none !important
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* TODO W-12129682: styles are commented out for the future migration of `tabset`
|
|
2
|
+
to Native Shadow
|
|
3
|
+
|
|
4
|
+
:host([data-render-mode="shadow"]) .slds-vertical-tabs {
|
|
5
|
+
display: flex;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
border: 1px solid var(--slds-g-color-border-base-1, #e5e5e5);
|
|
8
|
+
border-radius: 0.25rem;]
|
|
9
|
+
}
|
|
10
|
+
*/
|
|
@@ -23,6 +23,8 @@ export default class LightningTabset extends LightningElement {
|
|
|
23
23
|
|
|
24
24
|
@track _tabHeaders = [];
|
|
25
25
|
|
|
26
|
+
_rerender = false;
|
|
27
|
+
|
|
26
28
|
connectedCallback() {
|
|
27
29
|
this._tabByValue = {};
|
|
28
30
|
this._connected = true;
|
|
@@ -36,6 +38,19 @@ export default class LightningTabset extends LightningElement {
|
|
|
36
38
|
);
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
// must wait for this entire `tab-set` component to be rendered in order to
|
|
42
|
+
// successfully querySelect `tab-bar` from it, in methods such as _updateTabBarHeaders
|
|
43
|
+
// or _selectTab.
|
|
44
|
+
// using _rerender to trigger renderedCallback and execute these methods in here
|
|
45
|
+
// instead of the handleTabRegister method, where `tab-bar` is not querySelectable.
|
|
46
|
+
renderedCallback() {
|
|
47
|
+
if (this._rerender) {
|
|
48
|
+
this._rerender = false;
|
|
49
|
+
this._updateTabBarHeaders(this._tabHeaders);
|
|
50
|
+
this._selectTab(this._activeTabValue);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
39
54
|
disconnectedCallback() {
|
|
40
55
|
this._connected = false;
|
|
41
56
|
}
|
|
@@ -84,7 +99,8 @@ export default class LightningTabset extends LightningElement {
|
|
|
84
99
|
|
|
85
100
|
handleTabRegister(event) {
|
|
86
101
|
event.stopPropagation();
|
|
87
|
-
|
|
102
|
+
// setting this to true, will trigger _updateTabBarHeaders and _selectTab in renderedCallback
|
|
103
|
+
this._rerender = true;
|
|
88
104
|
const tab = event.target;
|
|
89
105
|
|
|
90
106
|
tab.role = 'tabpanel';
|
|
@@ -149,6 +165,11 @@ export default class LightningTabset extends LightningElement {
|
|
|
149
165
|
endIconAlternativeText: tab.endIconAlternativeText,
|
|
150
166
|
showErrorIndicator: tab.showErrorIndicator,
|
|
151
167
|
});
|
|
168
|
+
|
|
169
|
+
// need to leave this _updateTabBarHeaders here so that `tab-bar` can be updated
|
|
170
|
+
// in the case of a "conditional tab". the _updateTabBarHeaders in the renderedCallback
|
|
171
|
+
// has no knowledge of the new tab being added.
|
|
172
|
+
// this call works here in the "conditional tab" case, as `tab-set` is already rendered.
|
|
152
173
|
this._updateTabBarHeaders(this._tabHeaders);
|
|
153
174
|
|
|
154
175
|
this._tabByValue[tabValue] = tab;
|
|
@@ -157,10 +178,6 @@ export default class LightningTabset extends LightningElement {
|
|
|
157
178
|
if (!this._activeTabValue) {
|
|
158
179
|
this._activeTabValue = tab.value;
|
|
159
180
|
}
|
|
160
|
-
|
|
161
|
-
if (this._activeTabValue === tab.value) {
|
|
162
|
-
this._selectTab(tabValue);
|
|
163
|
-
}
|
|
164
181
|
}
|
|
165
182
|
|
|
166
183
|
_selectTab(value) {
|
|
@@ -242,16 +259,17 @@ export default class LightningTabset extends LightningElement {
|
|
|
242
259
|
* @param {Array} headers
|
|
243
260
|
*/
|
|
244
261
|
_updateTabBarHeaders(headers) {
|
|
245
|
-
this.template.querySelector('lightning-tab-bar')
|
|
246
|
-
|
|
262
|
+
if (this.template.querySelector('lightning-tab-bar')) {
|
|
263
|
+
this.template.querySelector('lightning-tab-bar').tabHeaders =
|
|
264
|
+
headers.slice();
|
|
265
|
+
}
|
|
247
266
|
}
|
|
248
267
|
|
|
249
268
|
_selectTabHeaderByTabValue(value) {
|
|
250
|
-
|
|
269
|
+
const tabBar = this.template.querySelector('lightning-tab-bar');
|
|
270
|
+
if (!this._connected || !tabBar) {
|
|
251
271
|
return;
|
|
252
272
|
}
|
|
253
|
-
|
|
254
|
-
const tabBar = this.template.querySelector('lightning-tab-bar');
|
|
255
273
|
tabBar.selectTabByValue(value);
|
|
256
274
|
}
|
|
257
275
|
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const Button = require('pageobjects/button');
|
|
2
|
-
|
|
3
|
-
describe('button utam test', () => {
|
|
4
|
-
let root;
|
|
5
|
-
|
|
6
|
-
beforeEach(async () => {
|
|
7
|
-
await browser.url('/button/utam');
|
|
8
|
-
root = await $('button-utam');
|
|
9
|
-
await root.waitForDisplayed();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should get the button name', async () => {
|
|
13
|
-
const button = await utam.load(Button, {
|
|
14
|
-
element: await root.shadow$('lightning-button'),
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const label = await button.getButtonName();
|
|
18
|
-
expect(label).toBe('Click me');
|
|
19
|
-
});
|
|
20
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div style="height:160px">
|
|
3
|
-
<lightning-datatable
|
|
4
|
-
data-render-mode="default"
|
|
5
|
-
key-field="id"
|
|
6
|
-
columns={columns}
|
|
7
|
-
data={data}
|
|
8
|
-
default-sort-direction={defaultSortDirection}
|
|
9
|
-
sorted-direction={sortDirection}
|
|
10
|
-
sorted-by={sortedBy}
|
|
11
|
-
onsort={onHandleSort}
|
|
12
|
-
is-loading={loading}>
|
|
13
|
-
</lightning-datatable>
|
|
14
|
-
</div>
|
|
15
|
-
<div style="height:160px">
|
|
16
|
-
<lightning-datatable
|
|
17
|
-
data-render-mode="role-based"
|
|
18
|
-
key-field="id"
|
|
19
|
-
columns={columns}
|
|
20
|
-
data={data}
|
|
21
|
-
default-sort-direction={defaultSortDirection}
|
|
22
|
-
sorted-direction={sortDirection}
|
|
23
|
-
sorted-by={sortedBy}
|
|
24
|
-
onsort={onHandleSort}
|
|
25
|
-
is-loading={loading}
|
|
26
|
-
render-mode="role-based">
|
|
27
|
-
</lightning-datatable>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<lightning-button label="Enable Loading State" onclick={handleLoadingClick}></lightning-button>
|
|
31
|
-
<lightning-button label="Add More Rows" onclick={handleMoreRowsClick}></lightning-button>
|
|
32
|
-
</template>
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { LightningElement } from 'lwc';
|
|
2
|
-
|
|
3
|
-
const data = [
|
|
4
|
-
{ id: 1, name: 'Billy Simmons', age: 40, email: 'billy@salesforce.com' },
|
|
5
|
-
{ id: 2, name: 'Kelsey Denesik', age: 35, email: 'kelsey@salesforce.com' },
|
|
6
|
-
{ id: 3, name: 'Kyle Ruecker', age: 50, email: 'kyle@salesforce.com' },
|
|
7
|
-
{
|
|
8
|
-
id: 4,
|
|
9
|
-
name: 'Krystina Kerluke',
|
|
10
|
-
age: 37,
|
|
11
|
-
email: 'krystina@salesforce.com',
|
|
12
|
-
},
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const actions = [
|
|
16
|
-
{ label: 'Show details', name: 'show_details' },
|
|
17
|
-
{ label: 'Delete', name: 'delete' },
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
const columns = [
|
|
21
|
-
{ label: 'Name', fieldName: 'name' },
|
|
22
|
-
{
|
|
23
|
-
label: 'Age',
|
|
24
|
-
fieldName: 'age',
|
|
25
|
-
type: 'number',
|
|
26
|
-
sortable: true,
|
|
27
|
-
cellAttributes: { alignment: 'left' },
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
label: 'Email',
|
|
31
|
-
fieldName: 'email',
|
|
32
|
-
type: 'email',
|
|
33
|
-
hideDefaultActions: true,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: 'action',
|
|
37
|
-
typeAttributes: { rowActions: actions, menuAlignment: 'right' },
|
|
38
|
-
},
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
export default class DemoApp extends LightningElement {
|
|
42
|
-
data = data;
|
|
43
|
-
columns = columns;
|
|
44
|
-
defaultSortDirection = 'asc';
|
|
45
|
-
sortDirection = 'asc';
|
|
46
|
-
sortedBy;
|
|
47
|
-
loading = false;
|
|
48
|
-
|
|
49
|
-
// Used to sort the 'Age' column
|
|
50
|
-
sortBy(field, reverse, primer) {
|
|
51
|
-
const key = primer
|
|
52
|
-
? function (x) {
|
|
53
|
-
return primer(x[field]);
|
|
54
|
-
}
|
|
55
|
-
: function (x) {
|
|
56
|
-
return x[field];
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
return function (a, b) {
|
|
60
|
-
a = key(a);
|
|
61
|
-
b = key(b);
|
|
62
|
-
return reverse * ((a > b) - (b > a));
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
onHandleSort(event) {
|
|
67
|
-
const { fieldName: sortedBy, sortDirection } = event.detail;
|
|
68
|
-
const cloneData = [...this.data];
|
|
69
|
-
|
|
70
|
-
cloneData.sort(this.sortBy(sortedBy, sortDirection === 'asc' ? 1 : -1));
|
|
71
|
-
this.data = cloneData;
|
|
72
|
-
this.sortDirection = sortDirection;
|
|
73
|
-
this.sortedBy = sortedBy;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
handleLoadingClick() {
|
|
77
|
-
this.loading = !this.loading;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
handleMoreRowsClick() {
|
|
81
|
-
const control = [
|
|
82
|
-
{
|
|
83
|
-
id: 20,
|
|
84
|
-
name: 'Jacqueline Palmer',
|
|
85
|
-
age: 60,
|
|
86
|
-
email: 'jacqueline@salesforce.com',
|
|
87
|
-
},
|
|
88
|
-
];
|
|
89
|
-
this.data = this.data.concat(this.data).concat(control);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
const Datatable = require('pageobjects/datatable');
|
|
2
|
-
const Button = require('pageobjects/button');
|
|
3
|
-
|
|
4
|
-
const tableTypes = {
|
|
5
|
-
default: '[data-render-mode="default"]',
|
|
6
|
-
roleBased: '[data-render-mode="role-based"]',
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
describe('Datatable UTAM Page Object Tests', () => {
|
|
10
|
-
Object.keys(tableTypes).forEach((type) => {
|
|
11
|
-
describe(`${type} table`, () => {
|
|
12
|
-
const TABLE_SELECTOR = tableTypes[type];
|
|
13
|
-
|
|
14
|
-
let root;
|
|
15
|
-
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
await browser.url('/datatable/utam');
|
|
18
|
-
root = await $('datatable-utam');
|
|
19
|
-
await root.waitForDisplayed();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should get the cell value by row and column index', async () => {
|
|
23
|
-
const datatable = await utam.load(Datatable, {
|
|
24
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const cellValue = await datatable.getCellValueByIndex(1, 2);
|
|
28
|
-
expect(cellValue).toBe('Billy Simmons');
|
|
29
|
-
});
|
|
30
|
-
it('should get the cell value by row index and column label', async () => {
|
|
31
|
-
const datatable = await utam.load(Datatable, {
|
|
32
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const cellValue = await datatable.getCellValueByLabel(2, 'Age');
|
|
36
|
-
expect(cellValue).toBe('35');
|
|
37
|
-
});
|
|
38
|
-
it('should get the number of rows in the table', async () => {
|
|
39
|
-
const datatable = await utam.load(Datatable, {
|
|
40
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const cellValue = await datatable.getNumRows();
|
|
44
|
-
expect(cellValue).toBe(4);
|
|
45
|
-
});
|
|
46
|
-
it('should tell if the table has any rows', async () => {
|
|
47
|
-
const datatable = await utam.load(Datatable, {
|
|
48
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const cellValue = await datatable.hasRows();
|
|
52
|
-
expect(cellValue).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
it('should toggle selection of row - comprehensive', async () => {
|
|
55
|
-
const datatable = await utam.load(Datatable, {
|
|
56
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
for (let i = 1; i <= 4; i++) {
|
|
60
|
-
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
await datatable.toggleRowSelection(1);
|
|
64
|
-
expect(await datatable.isRowSelected(1)).toBe('true');
|
|
65
|
-
[2, 3, 4].forEach(async (i) => {
|
|
66
|
-
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
await datatable.toggleRowSelection(2);
|
|
70
|
-
expect(await datatable.isRowSelected(2)).toBe('true');
|
|
71
|
-
[3, 4].forEach(async (i) => {
|
|
72
|
-
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
await datatable.toggleRowSelection(3);
|
|
76
|
-
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
77
|
-
expect(await datatable.isRowSelected(4)).toBe('false');
|
|
78
|
-
|
|
79
|
-
await datatable.toggleRowSelection(4);
|
|
80
|
-
expect(await datatable.isRowSelected(4)).toBe('true');
|
|
81
|
-
});
|
|
82
|
-
it('should toggle selection of row', async () => {
|
|
83
|
-
const datatable = await utam.load(Datatable, {
|
|
84
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
await datatable.toggleRowSelection(3);
|
|
88
|
-
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
89
|
-
|
|
90
|
-
await datatable.toggleRowSelection(3);
|
|
91
|
-
expect(await datatable.isRowSelected(3)).toBe('false');
|
|
92
|
-
});
|
|
93
|
-
it('should get the number of selected rows when not all rows are selected', async () => {
|
|
94
|
-
const datatable = await utam.load(Datatable, {
|
|
95
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
await datatable.toggleRowSelection(3);
|
|
99
|
-
expect(await datatable.getNumSelectedRows()).toBe(1);
|
|
100
|
-
|
|
101
|
-
await datatable.toggleRowSelection(2);
|
|
102
|
-
expect(await datatable.getNumSelectedRows()).toBe(2);
|
|
103
|
-
});
|
|
104
|
-
it('should get the number of selected rows when all rows are selected', async () => {
|
|
105
|
-
const datatable = await utam.load(Datatable, {
|
|
106
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await datatable.clickSelectAllCheckbox();
|
|
110
|
-
expect(await datatable.getNumSelectedRows()).toBe(4);
|
|
111
|
-
});
|
|
112
|
-
it('should get the number of columns in the table', async () => {
|
|
113
|
-
const datatable = await utam.load(Datatable, {
|
|
114
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
expect(await datatable.getNumColumns()).toBe(5);
|
|
118
|
-
});
|
|
119
|
-
it('should tell whether or not a column is sortable', async () => {
|
|
120
|
-
const datatable = await utam.load(Datatable, {
|
|
121
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
expect(await datatable.isSortableColumn('Age')).toBe(true);
|
|
125
|
-
|
|
126
|
-
// Need to speak to UTAM (about isPresent) or find a better way to write this method
|
|
127
|
-
// If column is not sortable, the test fails with the error:
|
|
128
|
-
// "Can't find elements with locator 'lightning-primitive-header-factory.slds-is-sortable' inside its scope element."
|
|
129
|
-
// expect(await datatable.isSortableColumn('Name')).toBe(false);
|
|
130
|
-
});
|
|
131
|
-
it('should tell whether or not the row is selectable', async () => {
|
|
132
|
-
const datatable = await utam.load(Datatable, {
|
|
133
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
expect(await datatable.isSelectableRow(1)).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
it('should get the width of a column', async () => {
|
|
139
|
-
const datatable = await utam.load(Datatable, {
|
|
140
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
const datatableElement = await root.shadow$(
|
|
144
|
-
'lightning-datatable'
|
|
145
|
-
);
|
|
146
|
-
const columnHeader = await datatableElement.shadow$(
|
|
147
|
-
'[aria-label="Name"]'
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
// Remove intermediate white spaces
|
|
151
|
-
let expectedWidth = await columnHeader.getAttribute('style');
|
|
152
|
-
expectedWidth = expectedWidth.replace(/\s/g, '');
|
|
153
|
-
let actualWidth = await datatable.getWidth('Name');
|
|
154
|
-
actualWidth = actualWidth.replace(/\s/g, '');
|
|
155
|
-
|
|
156
|
-
// Using indexOf in case of presence of ';'
|
|
157
|
-
expect(actualWidth.indexOf(expectedWidth) >= 0).toBe(true);
|
|
158
|
-
});
|
|
159
|
-
it('should tell whether or not a column has header actions', async () => {
|
|
160
|
-
const datatable = await utam.load(Datatable, {
|
|
161
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
expect(await datatable.hasHeaderActions('Name')).toBe(true);
|
|
165
|
-
expect(await datatable.hasHeaderActions('Age')).toBe(true);
|
|
166
|
-
// false fails; need to check for true or null; check with UTAM if expected
|
|
167
|
-
expect(await datatable.hasHeaderActions('Email')).toBe(null);
|
|
168
|
-
});
|
|
169
|
-
it('should get the text of the rowheader cell of the specified row', async () => {
|
|
170
|
-
const datatable = await utam.load(Datatable, {
|
|
171
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
expect(await datatable.getRowHeaderText(2)).toBe(
|
|
175
|
-
'Kelsey Denesik'
|
|
176
|
-
);
|
|
177
|
-
});
|
|
178
|
-
it('should click column header of the sortable column', async () => {
|
|
179
|
-
const datatable = await utam.load(Datatable, {
|
|
180
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
let cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
184
|
-
expect(cellValue).toBe('40');
|
|
185
|
-
|
|
186
|
-
await datatable.clickSortHeaderButton('Age');
|
|
187
|
-
|
|
188
|
-
cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
189
|
-
expect(cellValue).toBe('35');
|
|
190
|
-
});
|
|
191
|
-
it('should tell whether the specified row has row actions or not', async () => {
|
|
192
|
-
const datatable = await utam.load(Datatable, {
|
|
193
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(await datatable.hasRowActionInRow(2)).toBe(true);
|
|
197
|
-
});
|
|
198
|
-
it('should tell whether or not the datatable has the loading indicator visible', async () => {
|
|
199
|
-
const datatable = await utam.load(Datatable, {
|
|
200
|
-
element: await root.shadow$(TABLE_SELECTOR),
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
expect(await datatable.isLoading()).toBe(false);
|
|
204
|
-
|
|
205
|
-
const button = await utam.load(Button, {
|
|
206
|
-
element: await root.shadow$('lightning-button'),
|
|
207
|
-
});
|
|
208
|
-
await button.click();
|
|
209
|
-
|
|
210
|
-
expect(await datatable.isLoading()).toBe(true);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
});
|