From 3c148859c61a54a3f65f682b91ae2e1bb35079cc Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Thu, 29 Aug 2019 21:59:13 +0200 Subject: [PATCH 1/3] feat: add component.selectOptions --- .../src/lib/testing-library.ts | 3 +- .../src/lib/user-events/index.ts | 5 +- .../src/lib/user-events/selectOptions.ts | 65 +++++ .../tests/user-events/selectOptions.spec.ts | 236 ++++++++++++++++++ .../__snapshots__/app.component.spec.ts.snap | 42 ++++ src/app/app.component.html | 5 + src/app/app.component.spec.ts | 9 + src/app/app.component.ts | 3 + 8 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 projects/testing-library/src/lib/user-events/selectOptions.ts create mode 100644 projects/testing-library/tests/user-events/selectOptions.spec.ts diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index abd08e81..41c5c50f 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -4,7 +4,7 @@ import { NoopAnimationsModule, BrowserAnimationsModule } from '@angular/platform import { TestBed, ComponentFixture } from '@angular/core/testing'; import { getQueriesForElement, prettyDOM, fireEvent, FireObject, FireFunction } from '@testing-library/dom'; import { RenderResult, RenderOptions } from './models'; -import { createType } from './user-events'; +import { createType, createSelectOptions } from './user-events'; @Component({ selector: 'wrapper-component', template: '' }) class WrapperComponent implements OnInit { @@ -87,6 +87,7 @@ export async function render( ...getQueriesForElement(fixture.nativeElement, queries), ...eventsWithDetectChanges, type: createType(eventsWithDetectChanges), + selectOptions: createSelectOptions(eventsWithDetectChanges), } as any; } diff --git a/projects/testing-library/src/lib/user-events/index.ts b/projects/testing-library/src/lib/user-events/index.ts index 412f7708..06b9ff92 100644 --- a/projects/testing-library/src/lib/user-events/index.ts +++ b/projects/testing-library/src/lib/user-events/index.ts @@ -1,10 +1,13 @@ import { fireEvent } from '@testing-library/dom'; import { createType } from './type'; +import { createSelectOptions } from './selectOptions'; export interface UserEvents { type: ReturnType; + selectOptions: ReturnType; } const type = createType(fireEvent); +const selectOptions = createSelectOptions(fireEvent); -export { createType, type }; +export { createType, type, createSelectOptions, selectOptions }; diff --git a/projects/testing-library/src/lib/user-events/selectOptions.ts b/projects/testing-library/src/lib/user-events/selectOptions.ts new file mode 100644 index 00000000..5cd4a284 --- /dev/null +++ b/projects/testing-library/src/lib/user-events/selectOptions.ts @@ -0,0 +1,65 @@ +import { + FireFunction, + FireObject, + Matcher, + getByText, + SelectorMatcherOptions, + queryByText, +} from '@testing-library/dom'; + +// implementation from https://github.com/testing-library/user-event +export function createSelectOptions(fireEvent: FireFunction & FireObject) { + function clickElement(element: HTMLElement) { + fireEvent.mouseOver(element); + fireEvent.mouseMove(element); + fireEvent.mouseDown(element); + fireEvent.focus(element); + fireEvent.mouseUp(element); + fireEvent.click(element); + } + + function selectOption(select: HTMLSelectElement, index: number, matcher: Matcher, options?: SelectorMatcherOptions) { + if (!select.multiple && index > 0) { + return; + } + + // fallback to document.body, because libraries as Angular Material will have their custom select component + const option = (queryByText(select, matcher, options) || + getByText(document.body, matcher, options)) as HTMLOptionElement; + + fireEvent.mouseOver(option); + fireEvent.mouseMove(option); + fireEvent.mouseDown(option); + fireEvent.focus(option); + fireEvent.mouseUp(option); + fireEvent.click(option, { ctrlKey: index > 0 }); + + option.selected = true; + fireEvent.change(select); + } + + return async function selectOptions( + element: HTMLElement, + matcher: Matcher | Matcher[], + matcherOptions?: SelectorMatcherOptions, + ) { + const selectElement = element as HTMLSelectElement; + Array.from(selectElement.selectedOptions).forEach(option => (option.selected = false)); + const focusedElement = document.activeElement; + const wasAnotherElementFocused = focusedElement !== document.body && focusedElement !== selectElement; + + if (wasAnotherElementFocused) { + fireEvent.mouseMove(focusedElement); + fireEvent.mouseLeave(focusedElement); + } + + clickElement(selectElement); + + const values = Array.isArray(matcher) ? matcher : [matcher]; + values.forEach((val, index) => selectOption(selectElement, index, val, matcherOptions)); + + if (wasAnotherElementFocused) { + fireEvent.blur(focusedElement); + } + }; +} diff --git a/projects/testing-library/tests/user-events/selectOptions.spec.ts b/projects/testing-library/tests/user-events/selectOptions.spec.ts new file mode 100644 index 00000000..fb5c35bb --- /dev/null +++ b/projects/testing-library/tests/user-events/selectOptions.spec.ts @@ -0,0 +1,236 @@ +import { ReactiveFormsModule, FormsModule, FormControl } from '@angular/forms'; +import { render, RenderResult } from '../../src/public_api'; +import { Component, ViewChild, Input } from '@angular/core'; + +describe('selectOption: single', () => { + test('with a template-driven form', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value }}

+ `, + }) + class FixtureComponent { + value: string; + } + + const component = await render(FixtureComponent, { + imports: [FormsModule], + }); + + assertSelectOptions(component, () => component.fixture.componentInstance.value); + }); + + test('with a reactive form', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value.value }}

+ `, + }) + class FixtureComponent { + value = new FormControl(''); + } + + const component = await render(FixtureComponent, { + imports: [ReactiveFormsModule], + }); + + assertSelectOptions(component, () => component.fixture.componentInstance.value.value); + }); + + test('with change event', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value }}

+ `, + }) + class FixtureComponent { + value = ''; + + onChange(event: KeyboardEvent) { + this.value = (event.target).value; + } + } + + const component = await render(FixtureComponent); + + assertSelectOptions(component, () => component.fixture.componentInstance.value); + }); + + test('by reference', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ input.value }}

+ `, + }) + class FixtureComponent { + @ViewChild('input', { static: false }) value; + } + + const component = await render(FixtureComponent); + + assertSelectOptions(component, () => component.fixture.componentInstance.value.nativeElement.value); + }); + + function assertSelectOptions(component: RenderResult, value: () => string) { + const inputControl = component.getByTestId('select') as HTMLSelectElement; + component.selectOptions(inputControl, /apples/i); + component.selectOptions(inputControl, 'Oranges'); + + expect(value()).toBe('2'); + expect(component.getByTestId('text').textContent).toBe('2'); + expect(inputControl.value).toBe('2'); + + expect((component.getByTestId('apples') as HTMLOptionElement).selected).toBe(false); + expect((component.getByTestId('oranges') as HTMLOptionElement).selected).toBe(true); + expect((component.getByTestId('lemons') as HTMLOptionElement).selected).toBe(false); + } +}); + +describe('selectOption: multiple', () => { + test('with a template-driven form', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value }}

+ `, + }) + class FixtureComponent { + value: string; + } + + const component = await render(FixtureComponent, { + imports: [FormsModule], + }); + assertSelectOptions(component, () => component.fixture.componentInstance.value); + }); + + test('with a reactive form', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value.value }}

+ `, + }) + class FixtureComponent { + value = new FormControl(''); + } + + const component = await render(FixtureComponent, { + imports: [ReactiveFormsModule], + }); + + assertSelectOptions(component, () => component.fixture.componentInstance.value.value); + }); + + test('with change event', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ value }}

+ `, + }) + class FixtureComponent { + value = []; + + onChange(event: KeyboardEvent) { + this.value = Array.from((event.target).selectedOptions).map(o => o.value); + } + } + + const component = await render(FixtureComponent); + + assertSelectOptions(component, () => component.fixture.componentInstance.value); + }); + + test('by reference', async () => { + @Component({ + selector: 'fixture', + template: ` + + +

{{ input.value }}

+ `, + }) + class FixtureComponent { + @ViewChild('input', { static: false }) value; + } + + const component = await render(FixtureComponent); + + const inputControl = component.getByTestId('select') as HTMLSelectElement; + component.selectOptions(inputControl, /apples/i); + component.selectOptions(inputControl, ['Oranges', 'Lemons']); + + const options = component.fixture.componentInstance.value.nativeElement.selectedOptions; + const value = Array.from(options).map((o: any) => o.value); + + expect(value).toEqual(['2', '3']); + // shouldn't this be an empty string? - https://stackblitz.com/edit/angular-pdvm9n + expect(component.getByTestId('text').textContent).toBe('2'); + expect((component.getByTestId('apples') as HTMLOptionElement).selected).toBe(false); + expect((component.getByTestId('oranges') as HTMLOptionElement).selected).toBe(true); + expect((component.getByTestId('lemons') as HTMLOptionElement).selected).toBe(true); + }); + + function assertSelectOptions(component: RenderResult, value: () => string) { + const inputControl = component.getByTestId('select') as HTMLSelectElement; + component.selectOptions(inputControl, /apples/i); + component.selectOptions(inputControl, ['Oranges', 'Lemons']); + + expect(value()).toEqual(['2', '3']); + expect(component.getByTestId('text').textContent).toBe('2,3'); + expect((component.getByTestId('apples') as HTMLOptionElement).selected).toBe(false); + expect((component.getByTestId('oranges') as HTMLOptionElement).selected).toBe(true); + expect((component.getByTestId('lemons') as HTMLOptionElement).selected).toBe(true); + } +}); diff --git a/src/app/__snapshots__/app.component.spec.ts.snap b/src/app/__snapshots__/app.component.spec.ts.snap index dafd7f11..58a6bef4 100644 --- a/src/app/__snapshots__/app.component.spec.ts.snap +++ b/src/app/__snapshots__/app.component.spec.ts.snap @@ -112,6 +112,48 @@ exports[`matches snapshot 1`] = ` type="number" /> + +
Angular bl Age: + + +
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 09e94333..d10d3e12 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -70,6 +70,7 @@ describe('Forms', () => { const nameInput = component.getByLabelText('Name:'); const ageInput = component.getByLabelText('Age:'); + const colorInput = component.getByLabelText('Favorite color:'); const nameValue = appComponent.form.get('name'); const ageValue = appComponent.form.get('age'); @@ -89,6 +90,14 @@ describe('Forms', () => { component.type(ageInput, '20'); expect(ageValue.valid).toBe(true); + component.selectOptions(colorInput, 'ink', { exact: false }); + component.selectOptions(colorInput, /YELLOW/i); + expect(appComponent.form.valid).toBe(true); + expect(appComponent.form.value).toEqual({ + name: 'Bob', + age: 20, + favoriteColor: 'yellow', + }); }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index af80c27b..a958e948 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -34,9 +34,12 @@ import { FormBuilder, Validators } from '@angular/forms'; export class AppComponent { isOpen = true; title = 'app'; + + colors = ['red', 'blue', 'yellow', 'pink']; form = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], age: ['', [Validators.min(18), Validators.max(28)]], + favoriteColor: [], }); constructor(private store: Store, private greetService: GreetService, private fb: FormBuilder) {} From 01dd48540fd334562e2ae98b3da01df97084e4ec Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 30 Aug 2019 15:41:57 +0200 Subject: [PATCH 2/3] test: add angular material tests --- package.json | 2 + .../src/lib/user-events/selectOptions.ts | 6 +- .../__snapshots__/app.component.spec.ts.snap | 221 +++++++++++++++++- src/app/app.component.html | 24 +- src/app/app.component.spec.ts | 21 +- src/app/app.component.ts | 11 +- src/app/app.module.ts | 5 +- src/app/material.mode.ts | 9 + src/styles.css | 2 +- yarn.lock | 23 +- 10 files changed, 308 insertions(+), 16 deletions(-) create mode 100644 src/app/material.mode.ts diff --git a/package.json b/package.json index e1e4525e..38f80794 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,12 @@ }, "dependencies": { "@angular/animations": "^8.0.0", + "@angular/cdk": "^8.1.4", "@angular/common": "^8.0.0", "@angular/compiler": "^8.0.0", "@angular/core": "^8.0.0", "@angular/forms": "^8.0.0", + "@angular/material": "^8.1.4", "@angular/platform-browser": "^8.0.0", "@angular/platform-browser-dynamic": "^8.0.0", "@angular/router": "^8.0.0", diff --git a/projects/testing-library/src/lib/user-events/selectOptions.ts b/projects/testing-library/src/lib/user-events/selectOptions.ts index 5cd4a284..0aaa5641 100644 --- a/projects/testing-library/src/lib/user-events/selectOptions.ts +++ b/projects/testing-library/src/lib/user-events/selectOptions.ts @@ -44,7 +44,11 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { matcherOptions?: SelectorMatcherOptions, ) { const selectElement = element as HTMLSelectElement; - Array.from(selectElement.selectedOptions).forEach(option => (option.selected = false)); + + if (selectElement.selectedOptions) { + Array.from(selectElement.selectedOptions).forEach(option => (option.selected = false)); + } + const focusedElement = document.activeElement; const wasAnotherElementFocused = focusedElement !== document.body && focusedElement !== selectElement; diff --git a/src/app/__snapshots__/app.component.spec.ts.snap b/src/app/__snapshots__/app.component.spec.ts.snap index 58a6bef4..f395d977 100644 --- a/src/app/__snapshots__/app.component.spec.ts.snap +++ b/src/app/__snapshots__/app.component.spec.ts.snap @@ -120,9 +120,9 @@ exports[`matches snapshot 1`] = ` +

+ mat select +

+ +
+
+ + +
+ + + +
+ +
+ +
+
+ + +
+ +
+
+
+
+ +

+ native html select +

+ +
+
+ + +
+ + + + + +
+ +
+ +
+ +
+
+ + +
+ +
+
+
+
+
Angular bl - + +

mat select

+ + Favorite animal: + + -- + + {{ animal.name }} + + + + +

native html select

+ + Select your car: + +
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index d10d3e12..d9a25a43 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -8,11 +8,12 @@ import { provideMock } from '@testing-library/angular/jest-utils'; import { AppComponent } from './app.component'; import { GreetService } from './greet.service'; import { ReactiveFormsModule } from '@angular/forms'; +import { MaterialModule } from './material.mode'; test(`matches snapshot`, async () => { const { container } = await render('', { declarations: [AppComponent], - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore()], }); expect(container).toMatchSnapshot(); @@ -21,7 +22,7 @@ test(`matches snapshot`, async () => { test(`should have a title`, async () => { const { getByText } = await render('', { declarations: [AppComponent], - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore()], }); expect(getByText('Welcome to app!')).toBeDefined(); @@ -30,7 +31,7 @@ test(`should have a title`, async () => { test(`should render title in a h1 tag`, async () => { const { container } = await render('', { declarations: [AppComponent], - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore()], }); expect(container.querySelector('h1').textContent).toContain('Welcome to app!'); @@ -39,7 +40,7 @@ test(`should render title in a h1 tag`, async () => { test(`should be able to get the Store`, async () => { await render('', { declarations: [AppComponent], - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore()], }); expect(TestBed.get>(Store)).toBeDefined(); @@ -48,7 +49,7 @@ test(`should be able to get the Store`, async () => { test(`should provide a mock greet service`, async () => { const component = await render(AppComponent, { declarations: [AppComponent], - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore(), provideMock(GreetService)], }); const service: GreetService = TestBed.get(GreetService); @@ -61,7 +62,7 @@ test(`should provide a mock greet service`, async () => { describe('Forms', () => { test(`should have form validations`, async () => { const component = await render(AppComponent, { - imports: [ReactiveFormsModule], + imports: [ReactiveFormsModule, MaterialModule], providers: [provideMockStore()], }); @@ -71,6 +72,8 @@ describe('Forms', () => { const nameInput = component.getByLabelText('Name:'); const ageInput = component.getByLabelText('Age:'); const colorInput = component.getByLabelText('Favorite color:'); + const animalInput = component.getByLabelText('Favorite animal:'); + const carInput = component.getByLabelText(/car/); const nameValue = appComponent.form.get('name'); const ageValue = appComponent.form.get('age'); @@ -92,12 +95,16 @@ describe('Forms', () => { component.selectOptions(colorInput, 'ink', { exact: false }); component.selectOptions(colorInput, /YELLOW/i); + component.selectOptions(animalInput, 'Cow'); + component.selectOptions(carInput, 'Audi'); expect(appComponent.form.valid).toBe(true); expect(appComponent.form.value).toEqual({ name: 'Bob', age: 20, - favoriteColor: 'yellow', + color: 'yellow', + animal: { name: 'Cow', sound: 'Moo!' }, + car: 'audi', }); }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a958e948..878211cf 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -36,10 +36,19 @@ export class AppComponent { title = 'app'; colors = ['red', 'blue', 'yellow', 'pink']; + animals = [ + { name: 'Dog', sound: 'Woof!' }, + { name: 'Cat', sound: 'Meow!' }, + { name: 'Cow', sound: 'Moo!' }, + { name: 'Fox', sound: 'Wa-pa-pa-pa-pa-pa-pow!' }, + ]; + form = this.fb.group({ name: ['', [Validators.required, Validators.minLength(2)]], age: ['', [Validators.min(18), Validators.max(28)]], - favoriteColor: [], + color: [], + animal: [], + car: [], }); constructor(private store: Store, private greetService: GreetService, private fb: FormBuilder) {} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index c6b3c600..1cbdb449 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -2,13 +2,14 @@ import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; +import { StoreModule } from '@ngrx/store'; import { AppComponent } from './app.component'; -import { StoreModule } from '@ngrx/store'; +import { MaterialModule } from './material.mode'; @NgModule({ declarations: [AppComponent], - imports: [BrowserModule, ReactiveFormsModule, BrowserAnimationsModule, StoreModule.forRoot({})], + imports: [BrowserModule, ReactiveFormsModule, BrowserAnimationsModule, StoreModule.forRoot({}), MaterialModule], providers: [], bootstrap: [AppComponent], }) diff --git a/src/app/material.mode.ts b/src/app/material.mode.ts new file mode 100644 index 00000000..9f5c3368 --- /dev/null +++ b/src/app/material.mode.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; +import { A11yModule } from '@angular/cdk/a11y'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; + +@NgModule({ + exports: [A11yModule, MatInputModule, MatSelectModule], +}) +export class MaterialModule {} diff --git a/src/styles.css b/src/styles.css index 90d4ee00..dd3d5ed2 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1 +1 @@ -/* You can add global styles to this file, and also import other style files */ +@import '@angular/material/prebuilt-themes/deeppurple-amber.css'; diff --git a/yarn.lock b/yarn.lock index 35c004eb..10e2427b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -119,6 +119,15 @@ dependencies: tslib "^1.9.0" +"@angular/cdk@^8.1.4": + version "8.1.4" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-8.1.4.tgz#69066053fe4cbd80cee2bb7fa238f1c9abb963fc" + integrity sha512-U0tjhAZM4qqUHGGKIKFZZ9d8929s2U/HO0FdoT/eX+oHPOA6mm3bBep7myrSzlkP9V7O1JJfYdhEgijXhYxprQ== + dependencies: + tslib "^1.7.1" + optionalDependencies: + parse5 "^5.0.0" + "@angular/cli@~8.0.0": version "8.0.0" resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.0.0.tgz#0f65f60e8714b7b99f9425b862221e818959b0ac" @@ -192,6 +201,13 @@ resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-8.0.0.tgz#1ee4ce5003897cad53597da28f4c94fe30519bfb" integrity sha512-vGk14oWroEo6ycO4cooznx57nn2sASmCQ/sdE8UVwySUKl940TsVzijgaGqapTepFof9sMqN77y2G15eRKQeAQ== +"@angular/material@^8.1.4": + version "8.1.4" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-8.1.4.tgz#8bda747bb023af8ccce2c2d3e9e8dc25f05b3605" + integrity sha512-HV1qU63MaOtAc+cWg21Y2ygQKdEDjsGQ/3d3qym9sfR0xU2vvY7OG6gH48BfPeU63oMYxQkhxfoGP8wWMXSU1w== + dependencies: + tslib "^1.7.1" + "@angular/platform-browser-dynamic@^8.0.0": version "8.0.0" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.0.0.tgz#c15f394579ff44f3752033de58edc1afa5065d59" @@ -7515,7 +7531,7 @@ parse5@4.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== -parse5@5.1.0: +parse5@5.1.0, parse5@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== @@ -9805,6 +9821,11 @@ tsickle@0.35.0: mkdirp "^0.5.1" source-map "^0.7.3" +tslib@^1.7.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" From 7215a77054165964a74df061477994c030cc4e20 Mon Sep 17 00:00:00 2001 From: timdeschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 30 Aug 2019 15:56:45 +0200 Subject: [PATCH 3/3] refactor: move filter around --- .../testing-library/src/lib/user-events/selectOptions.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/projects/testing-library/src/lib/user-events/selectOptions.ts b/projects/testing-library/src/lib/user-events/selectOptions.ts index 0aaa5641..236f3b09 100644 --- a/projects/testing-library/src/lib/user-events/selectOptions.ts +++ b/projects/testing-library/src/lib/user-events/selectOptions.ts @@ -19,10 +19,6 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { } function selectOption(select: HTMLSelectElement, index: number, matcher: Matcher, options?: SelectorMatcherOptions) { - if (!select.multiple && index > 0) { - return; - } - // fallback to document.body, because libraries as Angular Material will have their custom select component const option = (queryByText(select, matcher, options) || getByText(document.body, matcher, options)) as HTMLOptionElement; @@ -60,7 +56,9 @@ export function createSelectOptions(fireEvent: FireFunction & FireObject) { clickElement(selectElement); const values = Array.isArray(matcher) ? matcher : [matcher]; - values.forEach((val, index) => selectOption(selectElement, index, val, matcherOptions)); + values + .filter((_, index) => index === 0 || selectElement.multiple) + .forEach((val, index) => selectOption(selectElement, index, val, matcherOptions)); if (wasAnotherElementFocused) { fireEvent.blur(focusedElement);