Skip to content
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

feat(components/lookup): add search test harness #2798

Merged
merged 7 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -10,9 +10,11 @@
</sky-toolbar-item>
<sky-toolbar-item>
<sky-search
data-sky-id="demo-search"
[ariaLabel]="searchAriaLabel"
[searchText]="searchText"
[debounceTime]="250"
[placeholderText]="placeholderText"
(searchApply)="searchApplied($event)"
(searchChange)="searchApplied($event)"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { SkyMediaBreakpoints, SkyMediaQueryService } from '@skyux/core';
import { MockSkyMediaQueryService } from '@skyux/core/testing';
Blackbaud-SandhyaRajasabeson marked this conversation as resolved.
Show resolved Hide resolved
import { SkySearchComponent } from '@skyux/lookup';
Blackbaud-SteveBrush marked this conversation as resolved.
Show resolved Hide resolved
import { SkySearchHarness } from '@skyux/lookup/testing';

import { DemoComponent } from './demo.component';

describe('Basic search demo', () => {
async function setupTest(options: { dataSkyId: string }): Promise<{
harness: SkySearchHarness;
fixture: ComponentFixture<DemoComponent>;
mockMediaQuery: MockSkyMediaQueryService;
}> {
const mockMediaQuery = new MockSkyMediaQueryService();

await TestBed.configureTestingModule({
providers: [
{
provide: SkyMediaQueryService,
useValue: mockMediaQuery,
},
],
}).compileComponents();
const fixture = TestBed.overrideComponent(SkySearchComponent, {
add: {
providers: [
{
provide: SkyMediaQueryService,
useValue: mockMediaQuery,
},
],
},
}).createComponent(DemoComponent);
const loader = TestbedHarnessEnvironment.loader(fixture);

const harness = await loader.getHarness(
SkySearchHarness.with({ dataSkyId: options.dataSkyId }),
);

fixture.detectChanges();
await fixture.whenStable();

return { harness, fixture, mockMediaQuery };
}

beforeEach(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, DemoComponent],
});
});

it('should setup search component', async () => {
const { harness } = await setupTest({
dataSkyId: 'demo-search',
});

await expectAsync(harness.getAriaLabel()).toBeResolvedTo(
'Search reminders',
);
await expectAsync(harness.getPlaceholderText()).toBeResolvedTo(
'Search through reminders.',
);
});

it('should interact with search function', async () => {
const { harness } = await setupTest({
dataSkyId: 'demo-search',
});

await harness.enterText('Send');
await expectAsync(harness.getValue()).toBeResolvedTo('Send');

await harness.clickClearButton();
await expectAsync(harness.getValue()).toBeResolvedTo('');
});

it('should interact with search on mobile', async () => {
const { harness, fixture, mockMediaQuery } = await setupTest({
dataSkyId: 'demo-search',
});

mockMediaQuery.fire(SkyMediaBreakpoints.xs);
fixture.detectChanges();
await fixture.whenStable();

await harness.clickSearchOpenButton();
await expectAsync(harness.isCollapsed()).toBeResolvedTo(false);

await harness.enterText('Send');
await expectAsync(harness.getValue()).toBeResolvedTo('Send');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class DemoComponent {
},
];

protected placeholderText = 'Search through reminders.';
protected searchAriaLabel = 'Search reminders';
protected searchText = '';

Expand Down
120 changes: 117 additions & 3 deletions libs/components/lookup/testing/src/search/search-harness.spec.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SkyMediaBreakpoints, SkyMediaQueryService } from '@skyux/core';
import { MockSkyMediaQueryService } from '@skyux/core/testing';
import { SkySearchComponent } from '@skyux/lookup';

import { SearchHarnessTestComponent } from './fixtures/search-harness-test.component';
import { SearchHarnessTestModule } from './fixtures/search-harness-test.module';
import { SkySearchHarness } from './search-harness';

describe('Search harness', () => {
async function setupTest(options: { dataSkyId: string }) {
const mediaQuery = new MockSkyMediaQueryService();

await TestBed.configureTestingModule({
imports: [SearchHarnessTestModule],
providers: [
{
provide: SkyMediaQueryService,
useValue: mediaQuery,
},
],
}).compileComponents();

const fixture = TestBed.createComponent(SearchHarnessTestComponent);
const fixture = TestBed.overrideComponent(SkySearchComponent, {
add: {
providers: [
{
provide: SkyMediaQueryService,
useValue: mediaQuery,
},
],
},
}).createComponent(SearchHarnessTestComponent);
const loader = TestbedHarnessEnvironment.loader(fixture);

const searchHarness = await loader.getHarness(
SkySearchHarness.with({ dataSkyId: options.dataSkyId }),
);

return { searchHarness, fixture, loader };
return { searchHarness, fixture, loader, mediaQuery };
}

it('should focus and blur input', async () => {
Expand Down Expand Up @@ -93,4 +113,98 @@ describe('Search harness', () => {
'My placeholder text.',
);
});

it('should click the clear button', async () => {
const { searchHarness } = await setupTest({
dataSkyId: 'my-search-1',
});

await searchHarness.enterText('abc');
await expectAsync(searchHarness.getValue()).toBeResolvedTo('abc');

await searchHarness.clickClearButton();
await expectAsync(searchHarness.getValue()).toBeResolvedTo('');
});

it('should should throw an error when trying to click dismiss on a non collapsible search', async () => {
const { searchHarness } = await setupTest({
dataSkyId: 'my-search-1',
});
await expectAsync(
searchHarness.clickDismissSearchButton(),
).toBeRejectedWithError(
'Cannot find dismiss search button. Is a collapsed search open?',
);
});

it('should should throw an error when trying to click open on a non collapsed search', async () => {
const { searchHarness } = await setupTest({
dataSkyId: 'my-search-1',
});
await expectAsync(
searchHarness.clickSearchOpenButton(),
).toBeRejectedWithError(
'Cannot click search open button as search is not collapsed',
);
});

describe('In mobile view', () => {
async function setMobileView(
fixture: ComponentFixture<SearchHarnessTestComponent>,
mockMediaQueryService: MockSkyMediaQueryService,
): Promise<void> {
mockMediaQueryService.fire(SkyMediaBreakpoints.xs);
fixture.detectChanges();
await fixture.whenStable();
}
it('should throw errors trying to interact with collapsed search input', async () => {
const { fixture, searchHarness, mediaQuery } = await setupTest({
dataSkyId: 'my-search-1',
});

await setMobileView(fixture, mediaQuery);

await expectAsync(searchHarness.blur()).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(searchHarness.clear()).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(searchHarness.clickClearButton()).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(
searchHarness.clickSubmitButton(),
).toBeRejectedWithError('Search is collapsed.');
await expectAsync(searchHarness.enterText('abc')).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(searchHarness.focus()).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(
searchHarness.getPlaceholderText(),
).toBeRejectedWithError('Search is collapsed.');
await expectAsync(searchHarness.getValue()).toBeRejectedWithError(
'Search is collapsed.',
);
await expectAsync(searchHarness.isFocused()).toBeRejectedWithError(
'Search is collapsed.',
);
});

it('should open and close a collapsible search get whether the search is collapsed', async () => {
const { fixture, searchHarness, mediaQuery } = await setupTest({
dataSkyId: 'my-search-1',
});

await setMobileView(fixture, mediaQuery);

await expectAsync(searchHarness.isCollapsed()).toBeResolvedTo(true);
await searchHarness.clickSearchOpenButton();
await expectAsync(searchHarness.isCollapsed()).toBeResolvedTo(false);
await searchHarness.clickDismissSearchButton();
await expectAsync(searchHarness.isCollapsed()).toBeResolvedTo(true);
});
});
});
Loading
Loading