-
Notifications
You must be signed in to change notification settings - Fork 11
Multi select changes #696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multi select changes #696
Changes from 6 commits
92f0832
1cda1c7
134c991
bae4bc8
1b1d758
664accd
4789f70
7c75ed5
0c346a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,36 @@ | ||
| import { CommonModule } from '@angular/common'; | ||
| import { fakeAsync, flush } from '@angular/core/testing'; | ||
| import { IconType } from '@hypertrace/assets-library'; | ||
| import { SearchBoxComponent } from '@hypertrace/components'; | ||
| import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; | ||
| import { NavigationService } from '@hypertrace/common'; | ||
| import { createHostFactory, mockProvider, SpectatorHost } from '@ngneat/spectator/jest'; | ||
| import { MockComponent } from 'ng-mocks'; | ||
| import { NEVER } from 'rxjs'; | ||
| import { ButtonComponent } from '../button/button.component'; | ||
| import { DividerComponent } from '../divider/divider.component'; | ||
| import { LabelComponent } from '../label/label.component'; | ||
| import { LetAsyncModule } from '../let-async/let-async.module'; | ||
| import { PopoverComponent } from '../popover/popover.component'; | ||
| import { PopoverModule } from '../popover/popover.module'; | ||
| import { SearchBoxComponent } from '../search-box/search-box.component'; | ||
| import { SelectOptionComponent } from '../select/select-option.component'; | ||
| import { MultiSelectJustify } from './multi-select-justify'; | ||
| import { MultiSelectComponent, TriggerLabelDisplayMode } from './multi-select.component'; | ||
|
|
||
| describe('Multi Select Component', () => { | ||
| const hostFactory = createHostFactory<MultiSelectComponent<string>>({ | ||
| component: MultiSelectComponent, | ||
| imports: [LetAsyncModule], | ||
| entryComponents: [SelectOptionComponent], | ||
| declarations: [MockComponent(LabelComponent), MockComponent(DividerComponent), MockComponent(SearchBoxComponent)], | ||
| imports: [PopoverModule, CommonModule], | ||
| providers: [ | ||
| mockProvider(NavigationService, { | ||
| navigation$: NEVER | ||
| }) | ||
| ], | ||
| declarations: [ | ||
| SelectOptionComponent, | ||
| MockComponent(LabelComponent), | ||
| MockComponent(DividerComponent), | ||
| MockComponent(SearchBoxComponent), | ||
| MockComponent(ButtonComponent) | ||
| ], | ||
| shallow: true | ||
| }); | ||
|
|
||
|
|
@@ -30,21 +45,41 @@ describe('Multi Select Component', () => { | |
| test('should display initial selections', fakeAsync(() => { | ||
| spectator = hostFactory( | ||
| ` | ||
| <ht-multi-select [selected]="selected"> | ||
| <ht-multi-select [selected]="selected" [triggerLabelDisplayMode]="triggerLabelDisplayMode" [enableSearch]="true"> | ||
| <ht-select-option *ngFor="let option of options" [label]="option.label" [value]="option.value"> | ||
| </ht-select-option> | ||
| </ht-multi-select>`, | ||
| { | ||
| hostProps: { | ||
| options: selectionOptions, | ||
| selected: [selectionOptions[1].value] | ||
| selected: [selectionOptions[1].value], | ||
| triggerLabelDisplayMode: TriggerLabelDisplayMode.Selection | ||
| } | ||
| } | ||
| ); | ||
|
|
||
| spectator.tick(); | ||
|
|
||
| expect(spectator.component.triggerLabel).toEqual(selectionOptions[1].label); | ||
| expect(spectator.query('.trigger-content')).toExist(); | ||
| expect(spectator.query('.trigger-label-container')).toExist(); | ||
| expect(spectator.query('.trigger-label')).toExist(); | ||
| expect(spectator.query('.trigger-icon')).toExist(); | ||
|
|
||
| const popoverComponent = spectator.query(PopoverComponent); | ||
| expect(popoverComponent?.closeOnClick).toEqual(false); | ||
| expect(popoverComponent?.closeOnNavigate).toEqual(true); | ||
|
|
||
| spectator.click('.trigger-content'); | ||
| expect(spectator.element).toHaveText(selectionOptions[1].label); | ||
|
|
||
| expect(spectator.query('.multi-select-content', { root: true })).toExist(); | ||
| expect(spectator.query('.multi-select-content .search-bar', { root: true })).toExist(); | ||
| expect(spectator.query('.multi-select-content .multi-select-option', { root: true })).toExist(); | ||
|
|
||
| expect(spectator.query('.multi-select-content', { root: true })).toExist(); | ||
| const optionElements = spectator.queryAll('.multi-select-option', { root: true }); | ||
|
|
||
| expect(optionElements.length).toEqual(3); | ||
|
|
||
| spectator.setHostInput({ | ||
| selected: [selectionOptions[1].value, selectionOptions[2].value] | ||
|
|
@@ -144,12 +179,12 @@ describe('Multi Select Component', () => { | |
| flush(); | ||
| })); | ||
|
|
||
| test('should notify and update selection when all checkbox is selected', fakeAsync(() => { | ||
| test('should show select all and clear selected buttons', fakeAsync(() => { | ||
| const onChange = jest.fn(); | ||
|
|
||
| spectator = hostFactory( | ||
| ` | ||
| <ht-multi-select [selected]="selected" (selectedChange)="onChange($event)" [placeholder]="placeholder" [showAllOptionControl]="showAllOptionControl"> | ||
| <ht-multi-select [selected]="selected" (selectedChange)="onChange($event)" [placeholder]="placeholder"> | ||
| <ht-select-option *ngFor="let option of options" [label]="option.label" [value]="option.value"> | ||
| </ht-select-option> | ||
| </ht-multi-select>`, | ||
|
|
@@ -158,7 +193,6 @@ describe('Multi Select Component', () => { | |
| options: selectionOptions, | ||
| selected: [selectionOptions[1].value], | ||
| placeholder: 'Select options', | ||
| showAllOptionControl: true, | ||
| onChange: onChange | ||
| } | ||
| } | ||
|
|
@@ -167,20 +201,27 @@ describe('Multi Select Component', () => { | |
| spectator.tick(); | ||
| spectator.click('.trigger-content'); | ||
|
|
||
| const allOptionElement = spectator.query('.all-options', { root: true }); | ||
| expect(allOptionElement).toExist(); | ||
| spectator.click(allOptionElement!); | ||
| expect(spectator.component.isAnyOptionSelected()).toEqual(true); | ||
| const clearSelectedButton = spectator.query('.clear-selected', { root: true }); | ||
| expect(clearSelectedButton).toExist(); | ||
| spectator.click(clearSelectedButton!); | ||
|
|
||
| spectator.tick(); | ||
| expect(spectator.queryAll('input:checked', { root: true }).length).toBe(0); | ||
| expect(onChange).toHaveBeenCalledTimes(1); | ||
| expect(onChange).toHaveBeenCalledWith(selectionOptions.map(option => option.value)); | ||
| expect(spectator.query(LabelComponent)?.label).toEqual('first and 2 more'); | ||
|
|
||
| // De select all | ||
| spectator.click(allOptionElement!); | ||
| expect(onChange).toHaveBeenCalledTimes(2); | ||
| expect(onChange).toHaveBeenLastCalledWith([]); | ||
| expect(spectator.query(LabelComponent)?.label).toEqual('Select options'); | ||
|
|
||
| const allOptionElement = spectator.query('.select-all', { root: true }); | ||
| expect(allOptionElement).toExist(); | ||
| spectator.click(allOptionElement!); | ||
|
|
||
| spectator.tick(); | ||
| const selectedElements = spectator.queryAll('input:checked', { root: true }); | ||
| expect(selectedElements.length).toBe(3); | ||
|
|
||
| expect(onChange).toHaveBeenCalledWith(selectionOptions.map(option => option.value)); | ||
| expect(spectator.query(LabelComponent)?.label).toEqual('first and 2 more'); | ||
| flush(); | ||
| })); | ||
|
|
||
|
|
@@ -234,21 +275,23 @@ describe('Multi Select Component', () => { | |
| ); | ||
| spectator.tick(); | ||
|
|
||
| expect(spectator.element).toHaveText(selectionOptions[1].label); | ||
| expect(spectator.component.triggerLabel).toEqual(selectionOptions[1].label); | ||
| expect(spectator.query('.trigger-content')).toExist(); | ||
| expect(spectator.query('.trigger-label-container')).toExist(); | ||
| expect(spectator.query('.trigger-label')).toExist(); | ||
| expect(spectator.query('.trigger-icon')).toExist(); | ||
| expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: flex-start;'); | ||
|
|
||
| spectator.setInput({ | ||
| justify: MultiSelectJustify.Center | ||
| }); | ||
|
|
||
| expect(spectator.element).toHaveText(selectionOptions[1].label); | ||
| expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: center;'); | ||
|
|
||
| spectator.setInput({ | ||
| justify: MultiSelectJustify.Right | ||
| }); | ||
|
|
||
| expect(spectator.element).toHaveText(selectionOptions[1].label); | ||
| expect(spectator.query('.trigger-content')!.getAttribute('style')).toBe('justify-content: flex-end;'); | ||
| })); | ||
|
|
||
|
|
@@ -267,18 +310,19 @@ describe('Multi Select Component', () => { | |
| } | ||
| ); | ||
|
|
||
| spectator.tick(); | ||
| expect(spectator.query('.search-bar')).toExist(); | ||
| spectator.click('.search-bar'); | ||
| spectator.click('.trigger-content'); | ||
|
|
||
| const searchBar = spectator.query('.search-bar', { root: true }); | ||
| expect(searchBar).toExist(); | ||
|
|
||
| spectator.triggerEventHandler(SearchBoxComponent, 'valueChange', 'fi'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how these tests worked before. PopoverModule was not added in the shallow test. So the popover content could never get projected. Also,
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's how - it wasn't using the real popover (so those tags are basically ignored), which your test is now. So only the searchbox was mocked as an actual component - but it was never projected. That's also why the root wasn't there before.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You also might be able to use |
||
| spectator.component.searchOptions('fi'); | ||
| spectator.tick(); | ||
|
|
||
| let options = spectator.queryAll('.multi-select-option', { root: true }); | ||
| expect(options.length).toBe(1); | ||
| expect(options[0]).toContainText('first'); | ||
|
|
||
| spectator.triggerEventHandler(SearchBoxComponent, 'valueChange', 'i'); | ||
| spectator.component.searchOptions('i'); | ||
| spectator.tick(); | ||
|
|
||
| options = spectator.queryAll('.multi-select-option', { root: true }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this downgrade intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. v5 is not free and requires some additional setup to make it work. So we reverted this change.