Skip to content

Commit 716b7c2

Browse files
authored
Merge branch 'main' into backend-operations
2 parents 232ba58 + 3e15d82 commit 716b7c2

File tree

32 files changed

+28532
-327
lines changed

32 files changed

+28532
-327
lines changed

package-lock.json

Lines changed: 28211 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"codelyzer": "^6.0.1",
9696
"commitizen": "^4.2.3",
9797
"cz-conventional-changelog": "^3.3.0",
98-
"husky": "^5.1.2",
98+
"husky": "^4.3.8",
9999
"jest": "^26.6.3",
100100
"jest-config": "^26.6.3",
101101
"jest-html-reporter": "^3.2.0",

projects/components/src/multi-select/multi-select.component.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@
6363
.multi-select-content {
6464
@include dropdown(6px);
6565
min-width: 120px;
66+
display: flex;
67+
flex-direction: column;
68+
69+
.divider {
70+
padding: 0px 16px 4px 16px;
71+
}
6672

6773
.multi-select-option {
6874
display: flex;

projects/components/src/multi-select/multi-select.component.test.ts

Lines changed: 107 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
1+
import { CommonModule } from '@angular/common';
12
import { fakeAsync, flush } from '@angular/core/testing';
23
import { IconType } from '@hypertrace/assets-library';
3-
import { SearchBoxComponent } from '@hypertrace/components';
4-
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
4+
import { NavigationService } from '@hypertrace/common';
5+
import { createHostFactory, mockProvider, SpectatorHost } from '@ngneat/spectator/jest';
56
import { MockComponent } from 'ng-mocks';
7+
import { NEVER } from 'rxjs';
8+
import { ButtonComponent } from '../button/button.component';
69
import { DividerComponent } from '../divider/divider.component';
710
import { LabelComponent } from '../label/label.component';
8-
import { LetAsyncModule } from '../let-async/let-async.module';
11+
import { PopoverComponent } from '../popover/popover.component';
12+
import { PopoverModule } from '../popover/popover.module';
13+
import { SearchBoxComponent } from '../search-box/search-box.component';
914
import { SelectOptionComponent } from '../select/select-option.component';
1015
import { MultiSelectJustify } from './multi-select-justify';
1116
import { MultiSelectComponent, TriggerLabelDisplayMode } from './multi-select.component';
1217

1318
describe('Multi Select Component', () => {
1419
const hostFactory = createHostFactory<MultiSelectComponent<string>>({
1520
component: MultiSelectComponent,
16-
imports: [LetAsyncModule],
17-
entryComponents: [SelectOptionComponent],
18-
declarations: [MockComponent(LabelComponent), MockComponent(DividerComponent), MockComponent(SearchBoxComponent)],
21+
imports: [PopoverModule, CommonModule],
22+
providers: [
23+
mockProvider(NavigationService, {
24+
navigation$: NEVER
25+
})
26+
],
27+
declarations: [
28+
SelectOptionComponent,
29+
MockComponent(LabelComponent),
30+
MockComponent(DividerComponent),
31+
MockComponent(SearchBoxComponent),
32+
MockComponent(ButtonComponent)
33+
],
1934
shallow: true
2035
});
2136

@@ -24,27 +39,50 @@ describe('Multi Select Component', () => {
2439
const selectionOptions = [
2540
{ label: 'first', value: 'first-value' },
2641
{ label: 'second', value: 'second-value' },
27-
{ label: 'third', value: 'third-value' }
42+
{ label: 'third', value: 'third-value' },
43+
{ label: 'fourth', value: 'fourth-value' },
44+
{ label: 'fifth', value: 'fifth-value' },
45+
{ label: 'sixth', value: 'sixth-value' }
2846
];
2947

3048
test('should display initial selections', fakeAsync(() => {
3149
spectator = hostFactory(
3250
`
33-
<ht-multi-select [selected]="selected">
51+
<ht-multi-select [selected]="selected" [triggerLabelDisplayMode]="triggerLabelDisplayMode" [enableSearch]="true">
3452
<ht-select-option *ngFor="let option of options" [label]="option.label" [value]="option.value">
3553
</ht-select-option>
3654
</ht-multi-select>`,
3755
{
3856
hostProps: {
3957
options: selectionOptions,
40-
selected: [selectionOptions[1].value]
58+
selected: [selectionOptions[1].value],
59+
triggerLabelDisplayMode: TriggerLabelDisplayMode.Selection
4160
}
4261
}
4362
);
63+
4464
spectator.tick();
4565

66+
expect(spectator.component.triggerLabel).toEqual(selectionOptions[1].label);
67+
expect(spectator.query('.trigger-content')).toExist();
68+
expect(spectator.query('.trigger-label-container')).toExist();
69+
expect(spectator.query('.trigger-label')).toExist();
70+
expect(spectator.query('.trigger-icon')).toExist();
71+
72+
const popoverComponent = spectator.query(PopoverComponent);
73+
expect(popoverComponent?.closeOnClick).toEqual(false);
74+
expect(popoverComponent?.closeOnNavigate).toEqual(true);
75+
4676
spectator.click('.trigger-content');
47-
expect(spectator.element).toHaveText(selectionOptions[1].label);
77+
78+
expect(spectator.query('.multi-select-content', { root: true })).toExist();
79+
expect(spectator.query('.multi-select-content .search-bar', { root: true })).toExist();
80+
expect(spectator.query('.multi-select-content .multi-select-option', { root: true })).toExist();
81+
82+
expect(spectator.query('.multi-select-content', { root: true })).toExist();
83+
const optionElements = spectator.queryAll('.multi-select-option', { root: true });
84+
85+
expect(optionElements.length).toEqual(6);
4886

4987
spectator.setHostInput({
5088
selected: [selectionOptions[1].value, selectionOptions[2].value]
@@ -79,7 +117,7 @@ describe('Multi Select Component', () => {
79117
spectator.click('.trigger-content');
80118
const optionElements = spectator.queryAll('.multi-select-option:not(.all-options)', { root: true });
81119
expect(spectator.query('.multi-select-content', { root: true })).toExist();
82-
expect(optionElements.length).toBe(3);
120+
expect(optionElements.length).toBe(6);
83121

84122
const selectedElements = spectator.queryAll('input:checked', { root: true });
85123
expect(selectedElements.length).toBe(2);
@@ -144,12 +182,12 @@ describe('Multi Select Component', () => {
144182
flush();
145183
}));
146184

147-
test('should notify and update selection when all checkbox is selected', fakeAsync(() => {
185+
test('should show select all and clear selected buttons', fakeAsync(() => {
148186
const onChange = jest.fn();
149187

150188
spectator = hostFactory(
151189
`
152-
<ht-multi-select [selected]="selected" (selectedChange)="onChange($event)" [placeholder]="placeholder" [showAllOptionControl]="showAllOptionControl">
190+
<ht-multi-select [selected]="selected" (selectedChange)="onChange($event)" [placeholder]="placeholder" [enableSearch]="enableSearch">
153191
<ht-select-option *ngFor="let option of options" [label]="option.label" [value]="option.value">
154192
</ht-select-option>
155193
</ht-multi-select>`,
@@ -158,7 +196,7 @@ describe('Multi Select Component', () => {
158196
options: selectionOptions,
159197
selected: [selectionOptions[1].value],
160198
placeholder: 'Select options',
161-
showAllOptionControl: true,
199+
enableSearch: true,
162200
onChange: onChange
163201
}
164202
}
@@ -167,19 +205,39 @@ describe('Multi Select Component', () => {
167205
spectator.tick();
168206
spectator.click('.trigger-content');
169207

170-
const allOptionElement = spectator.query('.all-options', { root: true });
208+
expect(spectator.query('.search-bar', { root: true })).toExist();
209+
expect(spectator.query('.divider', { root: true })).toExist();
210+
211+
expect(spectator.component.isAnyOptionSelected()).toEqual(true);
212+
const clearSelectedButton = spectator.query('.clear-selected', { root: true });
213+
expect(clearSelectedButton).toExist();
214+
spectator.click(clearSelectedButton!);
215+
216+
spectator.tick();
217+
expect(spectator.queryAll('input:checked', { root: true }).length).toBe(0);
218+
expect(onChange).toHaveBeenCalledTimes(1);
219+
expect(onChange).toHaveBeenLastCalledWith([]);
220+
expect(spectator.query(LabelComponent)?.label).toEqual('Select options');
221+
222+
const allOptionElement = spectator.query('.select-all', { root: true });
171223
expect(allOptionElement).toExist();
172224
spectator.click(allOptionElement!);
173225

174-
expect(onChange).toHaveBeenCalledTimes(1);
226+
spectator.tick();
227+
const selectedElements = spectator.queryAll('input:checked', { root: true });
228+
expect(selectedElements.length).toBe(6);
229+
175230
expect(onChange).toHaveBeenCalledWith(selectionOptions.map(option => option.value));
176-
expect(spectator.query(LabelComponent)?.label).toEqual('first and 2 more');
231+
expect(spectator.query(LabelComponent)?.label).toEqual('first and 5 more');
177232

178-
// De select all
179-
spectator.click(allOptionElement!);
180-
expect(onChange).toHaveBeenCalledTimes(2);
181-
expect(onChange).toHaveBeenLastCalledWith([]);
182-
expect(spectator.query(LabelComponent)?.label).toEqual('Select options');
233+
spectator.setHostInput({
234+
enableSearch: false
235+
});
236+
237+
expect(spectator.query('.search-bar', { root: true })).not.toExist();
238+
expect(spectator.query('.divider', { root: true })).not.toExist();
239+
expect(spectator.query('.clear-selected', { root: true })).not.toExist();
240+
expect(spectator.query('.select-all', { root: true })).not.toExist();
183241

184242
flush();
185243
}));
@@ -234,21 +292,23 @@ describe('Multi Select Component', () => {
234292
);
235293
spectator.tick();
236294

237-
expect(spectator.element).toHaveText(selectionOptions[1].label);
295+
expect(spectator.component.triggerLabel).toEqual(selectionOptions[1].label);
296+
expect(spectator.query('.trigger-content')).toExist();
297+
expect(spectator.query('.trigger-label-container')).toExist();
298+
expect(spectator.query('.trigger-label')).toExist();
299+
expect(spectator.query('.trigger-icon')).toExist();
238300
expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: flex-start;');
239301

240302
spectator.setInput({
241303
justify: MultiSelectJustify.Center
242304
});
243305

244-
expect(spectator.element).toHaveText(selectionOptions[1].label);
245306
expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: center;');
246307

247308
spectator.setInput({
248309
justify: MultiSelectJustify.Right
249310
});
250311

251-
expect(spectator.element).toHaveText(selectionOptions[1].label);
252312
expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: flex-end;');
253313
}));
254314

@@ -267,24 +327,39 @@ describe('Multi Select Component', () => {
267327
}
268328
);
269329

270-
spectator.tick();
271-
expect(spectator.query('.search-bar')).toExist();
272-
spectator.click('.search-bar');
330+
spectator.click('.trigger-content');
331+
332+
const searchBar = spectator.query('.search-bar', { root: true });
333+
expect(searchBar).toExist();
273334

274-
spectator.triggerEventHandler(SearchBoxComponent, 'valueChange', 'fi');
335+
spectator.component.searchOptions('fi');
275336
spectator.tick();
276337

277338
let options = spectator.queryAll('.multi-select-option', { root: true });
278-
expect(options.length).toBe(1);
339+
expect(options.length).toBe(2);
279340
expect(options[0]).toContainText('first');
280341

281-
spectator.triggerEventHandler(SearchBoxComponent, 'valueChange', 'i');
342+
spectator.component.searchOptions('i');
282343
spectator.tick();
283344

284345
options = spectator.queryAll('.multi-select-option', { root: true });
285-
expect(options.length).toBe(2);
346+
expect(options.length).toBe(4);
286347
expect(options[0]).toContainText('first');
287348
expect(options[1]).toContainText('third');
349+
350+
expect(spectator.query('.divider', { root: true })).toExist();
351+
expect(spectator.query('.clear-selected', { root: true })).not.toExist(); // Due to initial selection
352+
expect(spectator.query('.select-all', { root: true })).toExist();
353+
354+
// Set selected options to less than 5 and search box and buttons should hide
355+
spectator.setHostInput({
356+
options: selectionOptions.slice(0, 3)
357+
});
358+
359+
expect(spectator.query('.search-bar', { root: true })).not.toExist();
360+
expect(spectator.query('.divider', { root: true })).not.toExist();
361+
expect(spectator.query('.clear-selected', { root: true })).not.toExist();
362+
expect(spectator.query('.select-all', { root: true })).not.toExist();
288363
flush();
289364
}));
290365
});

0 commit comments

Comments
 (0)