Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
* knowledge of the CeCILL-C license and that you accept its terms.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SelectComponent } from './select.component';
import { SelectComponent, VitamuiSelectOptions } from './select.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { Component, ViewChild } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
Expand All @@ -47,7 +47,7 @@ import { input } from '../../../../testing/src';

const placeholder = 'test';
const searchBarPlaceHolder = 'search test';
const options = {
const defaultOptions = {
options: [
{ key: 'option1', label: 'option 1' },
{ key: 'option2', label: 'option 2' },
Expand All @@ -58,14 +58,15 @@ const options = {

@Component({
template:
'<vitamui-select [placeholder]="placeholder" [options]="options" [formControl]="control" [multiple]="multiple"></vitamui-select>',
'<vitamui-select [placeholder]="placeholder" [options]="options" [formControl]="control" [multiple]="multiple" [enableSelectAll]="enableSelectAll"></vitamui-select>',
imports: [ReactiveFormsModule, SelectComponent],
})
class TestHostComponent {
@ViewChild(SelectComponent)
selectComponent: SelectComponent;

options = options;
options: VitamuiSelectOptions | any[];
enableSelectAll: boolean;
placeholder = placeholder;
searchBarPlaceHolder = searchBarPlaceHolder;
multiple?: boolean;
Expand All @@ -77,14 +78,22 @@ describe('SelectComponent', () => {
let testHostComponent: TestHostComponent;
let selectHarness: MatSelectHarness;

function init(isMultiple?: boolean) {
function init(
isMultiple?: boolean,
{ enableSelectAll, options }: { enableSelectAll: boolean; options: VitamuiSelectOptions | any[] } = {
enableSelectAll: true,
options: defaultOptions,
},
) {
return async () => {
await TestBed.configureTestingModule({
imports: [NoopAnimationsModule, TranslateModule.forRoot(), TestHostComponent],
}).compileComponents();

hostFixture = TestBed.createComponent(TestHostComponent);
hostFixture.componentInstance.options = options;
hostFixture.componentInstance.multiple = isMultiple;
hostFixture.componentInstance.enableSelectAll = enableSelectAll;
testHostComponent = hostFixture.componentInstance;
hostFixture.detectChanges();

Expand Down Expand Up @@ -114,7 +123,7 @@ describe('SelectComponent', () => {
input(document.querySelector('input'), search);
hostFixture.detectChanges();

const expectedOptions = options.options.filter((option) => option.label.includes(search));
const expectedOptions = defaultOptions.options.filter((option) => option.label.includes(search));
expect(testHostComponent.selectComponent.displayedOptions.length).toEqual(expectedOptions.length);
}
});
Expand All @@ -135,11 +144,11 @@ describe('SelectComponent', () => {

expect(testHostComponent.control.value).toBeNull();

for (const option of options.options) {
const i = options.options.indexOf(option);
for (const option of defaultOptions.options) {
const i = defaultOptions.options.indexOf(option);
labelElement.click();
const selectOptions = await selectHarness.getOptions();
expect(selectOptions.length).toBe(options.options.length);
expect(selectOptions.length).toBe(defaultOptions.options.length);

await selectOptions[i].click();
const valueElement = hostFixture.debugElement.query(By.css('mat-select-trigger')).nativeElement;
Expand All @@ -152,9 +161,9 @@ describe('SelectComponent', () => {
const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;

// Set 1st value
testHostComponent.control.setValue(options.options[0].key);
testHostComponent.control.setValue(defaultOptions.options[0].key);
// Check value is set
expect(testHostComponent.control.value).toEqual(options.options[0].key);
expect(testHostComponent.control.value).toEqual(defaultOptions.options[0].key);

// Click on 1st value (should deselect it)
labelElement.click();
Expand Down Expand Up @@ -185,12 +194,12 @@ describe('SelectComponent', () => {

labelElement.click();
const selectOptions = await selectHarness.getOptions();
expect(selectOptions.length).toBe(options.options.length + 1); // +1 for select all
expect(selectOptions.length).toBe(defaultOptions.options.length + 1); // +1 for select all

const expectedValues = [];

for (const option of options.options) {
const i = options.options.indexOf(option);
for (const option of defaultOptions.options) {
const i = defaultOptions.options.indexOf(option);

await selectOptions[i + 1].click();
expectedValues.push(option.key);
Expand All @@ -201,7 +210,7 @@ describe('SelectComponent', () => {
});

it('should toggle selecting all values when user clicks on select all', async () => {
const allValues = options.options.map((option) => option.key);
const allValues = defaultOptions.options.map((option) => option.key);

const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;
await labelElement.click();
Expand All @@ -228,8 +237,167 @@ describe('SelectComponent', () => {
await selectOptions[0].click();
await selectOptions[0].click();

const allValues = options.options.map((option) => option.key);
const allValues = defaultOptions.options.map((option) => option.key);
expect(testHostComponent.control.value).toEqual(allValues);
});

it('should correctly deselect an option without affecting others', async () => {
testHostComponent.control.setValue(['option1', 'option2', 'option3']);
hostFixture.detectChanges();
await hostFixture.whenStable();

const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;
labelElement.click();

const selectOptions = await selectHarness.getOptions();
await selectOptions[2].click();

expect(testHostComponent.control.value).toEqual(['option1', 'option3']);
expect(testHostComponent.control.value).not.toContain('option2');
});

it('should display preselected values correctly on load', async () => {
const preselectedValues = ['option2', 'option3'];
testHostComponent.control.setValue(preselectedValues);
hostFixture.detectChanges();
await hostFixture.whenStable();

const valueElement = hostFixture.debugElement.query(By.css('mat-select-trigger')).nativeElement;
expect(valueElement.textContent.trim().startsWith('2')).toBeTrue();
});

it('should maintain selection integrity when options are reloaded', async () => {
testHostComponent.control.setValue(['option1', 'option3']);
hostFixture.detectChanges();
await hostFixture.whenStable();

testHostComponent.options = {
options: [
{ key: 'option1', label: 'Updated Option 1' },
{ key: 'option2', label: 'Updated Option 2' },
{ key: 'option3', label: 'Updated Option 3' },
],
};
hostFixture.detectChanges();
await hostFixture.whenStable();

expect(testHostComponent.control.value).toEqual(['option1', 'option3']);
});
});

describe('in NON multiple mode (selection integrity)', () => {
beforeEach(init(false));

it('should only select one option at a time', async () => {
const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;

labelElement.click();
const selectOptions = await selectHarness.getOptions();
await selectOptions[0].click();

expect(testHostComponent.control.value).toBe('option1');

labelElement.click();
const selectOptions2 = await selectHarness.getOptions();
await selectOptions2[1].click();

expect(testHostComponent.control.value).toBe('option2');
});

it('should only select the chosen value and not others', async () => {
const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;

labelElement.click();
const selectOptions = await selectHarness.getOptions();
await selectOptions[1].click();

expect(testHostComponent.control.value).toBe('option2');
expect(testHostComponent.control.value).not.toBe('option1');
expect(testHostComponent.control.value).not.toBe('option3');
expect(testHostComponent.control.value).not.toBe('something-else');
});

it('should display preselected value correctly on load', async () => {
testHostComponent.control.setValue('option3');
hostFixture.detectChanges();
await hostFixture.whenStable();

const valueElement = hostFixture.debugElement.query(By.css('mat-select-trigger')).nativeElement;
expect(valueElement.textContent.trim()).toBe('option 3');
});
});

describe('in multiple mode, without select all and with custom options', () => {
beforeEach(
init(true, {
enableSelectAll: false,
options: {
options: [
{ key: 'DE', label: 'Allemagne', disabled: false },
{ key: 'BE', label: 'Belgique', disabled: false },
{ key: 'DK', label: 'Danemark', disabled: true },
{ key: 'ES', label: 'Espagne', disabled: false },
{ key: 'FR', label: 'France', disabled: false },
{ key: 'IT', label: 'Italie', disabled: false },
{ key: 'PT', label: 'Portugal', disabled: false },
{ key: 'GB', label: 'Royaume-Uni', disabled: false },
],
},
}),
);

it('should only select chosen options and not others', async () => {
const labelElement = hostFixture.debugElement.query(By.css('mat-label')).nativeElement;
labelElement.click();

const selectOptions = await selectHarness.getOptions();
await selectOptions[0].click();
await selectOptions[3].click();

expect(testHostComponent.control.value).toEqual(['DE', 'ES']);
expect(testHostComponent.control.value).not.toContain('BE');
});
});

describe('regression test for bug (Referential fields appear empty in edit mode despite a saved value)', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [NoopAnimationsModule, TranslateModule.forRoot(), TestHostComponent],
}).compileComponents();

hostFixture = TestBed.createComponent(TestHostComponent);
testHostComponent = hostFixture.componentInstance;
});

it('should display preselected value in edit mode even when it is far down in a long list', async () => {
// Create a large list of options (100 items)
const largeOptionList = Array.from({ length: 100 }, (_, i) => ({
key: `option${i}`,
label: `Option ${i}`,
}));

testHostComponent.options = { options: largeOptionList };
testHostComponent.multiple = false;

// Preselect an option far down the list (option #95)
testHostComponent.control.setValue('option95');

hostFixture.detectChanges();
await hostFixture.whenStable();

selectHarness = await TestbedHarnessEnvironment.loader(hostFixture).getHarness(MatSelectHarness);

// Verify the selected value is displayed in the trigger
const valueText = await selectHarness.getValueText();
expect(valueText).toBe('Option 95');

// Open the select
await selectHarness.open();
await hostFixture.whenStable();

// Verify the value is still displayed after opening
const valueTextAfterOpen = await selectHarness.getValueText();
expect(valueTextAfterOpen).toBe('Option 95');
});
});
});
Loading
Loading