From d79afdab97c8d788b7e32535afcb9be7b9f943c6 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Wed, 15 Jan 2025 11:59:06 -0500 Subject: [PATCH 01/18] adding files --- .../tabs/testing/src/modules/tabs/tabset-harness-filters.ts | 0 .../tabs/testing/src/modules/tabs/tabset-harness.spec.ts | 0 libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts new file mode 100644 index 0000000000..e69de29bb2 From c33c7361746acbf39c31cfb004cf1f882938db27 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Thu, 16 Jan 2025 11:40:11 -0500 Subject: [PATCH 02/18] more files --- .../tabs/testing/src/modules/tabs/tab-harness-filters.ts | 0 libs/components/tabs/testing/src/modules/tabs/tab-harness.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness.ts diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts new file mode 100644 index 0000000000..e69de29bb2 From af5db4020551e13e3e3ae08aa5eeb667eb80d906 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Tue, 21 Jan 2025 23:37:33 -0500 Subject: [PATCH 03/18] tab buttons and tabset --- .../components/tabs/tabs/tabs.component.html | 56 ++----------- .../components/tabs/tabs/tabs.component.ts | 8 +- .../lib/modules/tabs/tabset.component.html | 1 + .../tabs/tab-button-harness-filters.ts | 12 +++ .../src/modules/tabs/tab-button-harness.ts | 59 +++++++++++++ .../src/modules/tabs/tab-harness-filters.ts | 0 .../testing/src/modules/tabs/tab-harness.ts | 0 .../modules/tabs/tabset-harness-filters.ts | 7 ++ .../src/modules/tabs/tabset-harness.ts | 84 +++++++++++++++++++ .../components/tabs/testing/src/public-api.ts | 5 ++ 10 files changed, 181 insertions(+), 51 deletions(-) create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-button-harness-filters.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts delete mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts delete mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness.ts diff --git a/apps/playground/src/app/components/tabs/tabs/tabs.component.html b/apps/playground/src/app/components/tabs/tabs/tabs.component.html index 0030fa05f5..5d83b37460 100644 --- a/apps/playground/src/app/components/tabs/tabs/tabs.component.html +++ b/apps/playground/src/app/components/tabs/tabs/tabs.component.html @@ -1,47 +1,9 @@ - -
- - - Tab 1 Content - - - Tab 2 Content - - - Tab 3 Content - - - Tab 4 Content - - - This tab cannot be closed - - - Tab 3 Content - - -
- -
- - - Tab 1 Content - - Tab 2 Content - -
-
+ + Content for Tab 1 + Content for Tab 2 + @if (showTab3) { + + Content for Tab 3 + + } + diff --git a/apps/playground/src/app/components/tabs/tabs/tabs.component.ts b/apps/playground/src/app/components/tabs/tabs/tabs.component.ts index 4a9ea0b40c..a92a37dbc2 100644 --- a/apps/playground/src/app/components/tabs/tabs/tabs.component.ts +++ b/apps/playground/src/app/components/tabs/tabs/tabs.component.ts @@ -6,9 +6,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class TabsComponent { - public newTabClick() {} + protected showTab3 = true; - public openTabClick() {} - - public closeTab() {} + protected onNewTabClick(): void { + alert('Add tab clicked!'); + } } diff --git a/libs/components/tabs/src/lib/modules/tabs/tabset.component.html b/libs/components/tabs/src/lib/modules/tabs/tabset.component.html index f1297c3cfd..7a412fb55d 100644 --- a/libs/components/tabs/src/lib/modules/tabs/tabset.component.html +++ b/libs/components/tabs/src/lib/modules/tabs/tabset.component.html @@ -1,3 +1,4 @@ +
{ + return new HarnessPredicate(SkyTabButtonHarness, filters).addOption( + 'tabHeading', + filters.tabHeading, + async (harness, tabHeading) => { + const harnessTabHeading = await harness.getTabHeading(); + return await HarnessPredicate.stringMatches( + harnessTabHeading, + tabHeading, + ); + }, + ); + } + + public async getTabHeading(): Promise { + return ( + await (await this.locatorFor('.sky-tab-heading > span[skyid]')()).text() + ).trim(); + } + + public async isActive(): Promise { + return await (await this.#getTabButton()).hasClass('sky-btn-tab-selected'); + } + + public async isDisabled(): Promise { + return await (await this.#getTabButton()).hasClass('sky-btn-tab-disabled'); + } + + /**ß + * @internal + */ + public async getTabId(): Promise { + return ( + (await (await this.#getTabButton()).getAttribute('aria-controls')) || '' + ); + } +} diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts index e69de29bb2..44657ff03e 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness-filters.ts @@ -0,0 +1,7 @@ +import { SkyHarnessFilters } from '@skyux/core/testing'; + +/** + * A set of criteria that can be used to filter a list of `SkyTabsetHarness` instances. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type +export interface SkyTabsetHarnessFilters extends SkyHarnessFilters {} diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index e69de29bb2..3196c031f1 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -0,0 +1,84 @@ +import { SkyComponentHarness } from '@skyux/core/testing'; +import { SkyTabsetButtonsDisplayMode } from '@skyux/tabs'; + +import { SkyTabButtonHarness } from './tab-button-harness'; + +/** + * Harness for interacting with a tabset component in tests. + */ +export class SkyTabsetHarness extends SkyComponentHarness { + /** + * @internal + */ + public static hostSelector = 'sky-tabset'; + + #getTabset = this.locatorFor('.sky-tabset'); + #getTabs = this.locatorForAll(SkyTabButtonHarness); + + public async clickNewTabButton(): Promise { + const newTabButton = await this.locatorForOptional( + 'button.sky-tabset-btn-new', + )(); + + if (!newTabButton) { + throw new Error('Unable to find the new tab button.'); + } + + return await newTabButton.click(); + } + + public async clickOpenTabButton(): Promise { + const openTabButton = await this.locatorForOptional( + 'button.sky-tabset-btn-open', + )(); + + if (!openTabButton) { + throw new Error('Unable to find the open tab button.'); + } + + return await openTabButton.click(); + } + + public async getAriaLabel(): Promise { + return await (await this.#getTabset()).getAttribute('aria-label'); + } + + public async getAriaLabelledBy(): Promise { + return await (await this.#getTabset()).getAttribute('aria-labelledby'); + } + + public async getPermalinkId(): Promise { + return await (await this.host()).getAttribute('permalinkId'); + } + + public async getTabButtonHarness( + tabHeading: string, + ): Promise { + return await this.locatorFor( + SkyTabButtonHarness.with({ tabHeading: tabHeading }), + )(); + } + + public async getTabButtonHarnesses(): Promise { + return await this.#getTabs(); + } + + public async getActiveTabButton(): Promise { + const tabButtonHarnesses = await this.getTabButtonHarnesses(); + + for (const harness of tabButtonHarnesses) { + if (await harness.isActive()) { + return harness; + } + } + + return null; + } + + public async getMode(): Promise { + if (await (await this.#getTabset()).hasClass('sky-tabset-mode-tabs')) { + return 'tabs'; + } + return 'dropdown'; + } +} diff --git a/libs/components/tabs/testing/src/public-api.ts b/libs/components/tabs/testing/src/public-api.ts index bc42224f92..67507ddf22 100644 --- a/libs/components/tabs/testing/src/public-api.ts +++ b/libs/components/tabs/testing/src/public-api.ts @@ -1,2 +1,7 @@ export { SkyTabsetFixtureTab } from './legacy/tabs/tab-fixture-tab'; export { SkyTabsetFixture } from './legacy/tabs/tabset-fixture'; + +export { SkyTabsetHarness } from './modules/tabs/tabset-harness'; +export { SkyTabsetHarnessFilters } from './modules/tabs/tabset-harness-filters'; +export { SkyTabButtonHarness } from './modules/tabs/tab-button-harness'; +export { SkyTabButtonHarnessFilters } from './modules/tabs/tab-button-harness-filters'; From 235e09deab12c53f535945e649127f35fbb122dc Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Wed, 22 Jan 2025 10:39:09 -0500 Subject: [PATCH 04/18] missing files --- .../tabs/tab-button-harness-filters.ts | 2 +- .../src/modules/tabs/tab-button-harness.ts | 29 ++++++---- .../src/modules/tabs/tab-harness-filters.ts | 12 +++++ .../testing/src/modules/tabs/tab-harness.ts | 54 +++++++++++++++++++ .../src/modules/tabs/tabset-harness.ts | 11 +++- 5 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness.ts diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness-filters.ts index 8978781d6b..0b77631d7c 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness-filters.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness-filters.ts @@ -6,7 +6,7 @@ import { SkyHarnessFilters } from '@skyux/core/testing'; // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type export interface SkyTabButtonHarnessFilters extends SkyHarnessFilters { /** - * Finds tabs whose tab heading matches this value. + * Finds tab button whose tab heading matches this value. */ tabHeading: string; } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index 22177dec06..848609dcf8 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -2,9 +2,10 @@ import { HarnessPredicate } from '@angular/cdk/testing'; import { SkyComponentHarness } from '@skyux/core/testing'; import { SkyTabButtonHarnessFilters } from './tab-button-harness-filters'; +import { SkyTabHarness } from './tab-harness'; /** - * Harness for interacting with a tab component in tests. + * Harness for interacting with a tab button component in tests. */ export class SkyTabButtonHarness extends SkyComponentHarness { /** @@ -34,10 +35,21 @@ export class SkyTabButtonHarness extends SkyComponentHarness { ); } + public async click(): Promise { + return await (await this.#getTabButton()).click(); + } + public async getTabHeading(): Promise { return ( - await (await this.locatorFor('.sky-tab-heading > span[skyid]')()).text() - ).trim(); + // eslint-disable-next-line @cspell/spellchecker + ( + await (await this.locatorFor('.sky-tab-heading > span[skyid]')()).text() + ).trim() + ); + } + + public async getPermalink(): Promise { + return await (await this.#getTabButton()).getAttribute('href'); } public async isActive(): Promise { @@ -48,12 +60,9 @@ export class SkyTabButtonHarness extends SkyComponentHarness { return await (await this.#getTabButton()).hasClass('sky-btn-tab-disabled'); } - /**ß - * @internal - */ - public async getTabId(): Promise { - return ( - (await (await this.#getTabButton()).getAttribute('aria-controls')) || '' - ); + public async getTabHarness(): Promise { + return await this.documentRootLocatorFactory().locatorFor( + SkyTabHarness.with({ tabHeading: await this.getTabHeading() }), + )(); } } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts new file mode 100644 index 0000000000..aed370aca8 --- /dev/null +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts @@ -0,0 +1,12 @@ +import { SkyHarnessFilters } from '@skyux/core/testing'; + +/** + * A set of criteria that can be used to filter a list of `SkyTabHarness` instances. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type +export interface SkyTabHarnessFilters extends SkyHarnessFilters { + /** + * Finds tabs whose tab heading matches this value. + */ + tabHeading: string; +} diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts new file mode 100644 index 0000000000..48a3216fad --- /dev/null +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts @@ -0,0 +1,54 @@ +import { HarnessPredicate } from '@angular/cdk/testing'; +import { SkyQueryableComponentHarness } from '@skyux/core/testing'; + +import { SkyTabHarnessFilters } from './tab-harness-filters'; + +/** + * Harness for interacting with a tab component in tests. + */ +export class SkyTabHarness extends SkyQueryableComponentHarness { + /** + * @internal + */ + public static hostSelector = 'sky-tab'; + + #getTab = this.locatorFor('.sky-tab'); + + /** + * Gets a `HarnessPredicate` that can be used to search for a + * `SkyTabHarness` that meets certain criteria. + */ + public static with( + filters: SkyTabHarnessFilters, + ): HarnessPredicate { + return new HarnessPredicate(SkyTabHarness, filters).addOption( + 'tabHeading', + filters.tabHeading, + async (harness, tabHeading) => { + const harnessTabHeading = await harness.getTabHeading(); + return await HarnessPredicate.stringMatches( + harnessTabHeading, + tabHeading, + ); + }, + ); + } + + public async getTabHeading(): Promise { + // eslint-disable-next-line @cspell/spellchecker + return await (await this.host()).getAttribute('tabheading'); + } + + public async getLayout(): Promise { + return await (await this.host()).getAttribute('layout'); + } + + public async isVisible(): Promise { + return await (await this.#getTab()).getProperty('hidden'); + } + + public async getTabIndexValue(): Promise { + // eslint-disable-next-line @cspell/spellchecker + return await (await this.host()).getAttribute('tabindexvalue'); + } +} diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 3196c031f1..85a495ce36 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -2,6 +2,7 @@ import { SkyComponentHarness } from '@skyux/core/testing'; import { SkyTabsetButtonsDisplayMode } from '@skyux/tabs'; import { SkyTabButtonHarness } from './tab-button-harness'; +import { SkyTabHarness } from './tab-harness'; /** * Harness for interacting with a tabset component in tests. @@ -13,7 +14,7 @@ export class SkyTabsetHarness extends SkyComponentHarness { public static hostSelector = 'sky-tabset'; #getTabset = this.locatorFor('.sky-tabset'); - #getTabs = this.locatorForAll(SkyTabButtonHarness); + #getTabButtons = this.locatorForAll(SkyTabButtonHarness); public async clickNewTabButton(): Promise { const newTabButton = await this.locatorForOptional( @@ -59,8 +60,14 @@ export class SkyTabsetHarness extends SkyComponentHarness { )(); } + public async getTabHarness(tabHeading: string): Promise { + return await this.locatorFor( + SkyTabHarness.with({ tabHeading: tabHeading }), + )(); + } + public async getTabButtonHarnesses(): Promise { - return await this.#getTabs(); + return await this.#getTabButtons(); } public async getActiveTabButton(): Promise { From e2d61457e4fa0fdb3539941fa79e996bfa0bc47a Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 27 Jan 2025 09:37:52 -0500 Subject: [PATCH 05/18] non dropdown unit testing done --- .../components/tabs/tabs/tabs.component.html | 4 +- .../components/tabs/tabs/tabs.component.ts | 2 + .../src/modules/tabs/tab-button-harness.ts | 13 +- .../src/modules/tabs/tab-harness-filters.ts | 4 +- .../testing/src/modules/tabs/tab-harness.ts | 24 +- .../src/modules/tabs/tabset-harness.spec.ts | 224 ++++++++++++++++++ .../src/modules/tabs/tabset-harness.ts | 30 ++- 7 files changed, 270 insertions(+), 31 deletions(-) diff --git a/apps/playground/src/app/components/tabs/tabs/tabs.component.html b/apps/playground/src/app/components/tabs/tabs/tabs.component.html index 5d83b37460..59d8f54145 100644 --- a/apps/playground/src/app/components/tabs/tabs/tabs.component.html +++ b/apps/playground/src/app/components/tabs/tabs/tabs.component.html @@ -1,5 +1,7 @@ - Content for Tab 1 + + Content for Tab 1 Content for Tab 2 @if (showTab3) { diff --git a/apps/playground/src/app/components/tabs/tabs/tabs.component.ts b/apps/playground/src/app/components/tabs/tabs/tabs.component.ts index a92a37dbc2..0925de5033 100644 --- a/apps/playground/src/app/components/tabs/tabs/tabs.component.ts +++ b/apps/playground/src/app/components/tabs/tabs/tabs.component.ts @@ -1,4 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { SkyTabIndex } from '@skyux/tabs'; @Component({ selector: 'app-tabs', @@ -7,6 +8,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; }) export class TabsComponent { protected showTab3 = true; + protected tabIndexValue: SkyTabIndex = '2'; protected onNewTabClick(): void { alert('Add tab clicked!'); diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index 848609dcf8..f31c2e0c21 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -62,7 +62,18 @@ export class SkyTabButtonHarness extends SkyComponentHarness { public async getTabHarness(): Promise { return await this.documentRootLocatorFactory().locatorFor( - SkyTabHarness.with({ tabHeading: await this.getTabHeading() }), + SkyTabHarness.with({ tabId: await this.getTabId() }), )(); } + + /** + * @internal + */ + public async getTabId(): Promise { + return ( + (await (await this.#getTabButton()).getAttribute('aria-controls')) || + /* istanbul ignore next */ + '' + ); + } } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts index aed370aca8..41e45cf3e6 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts @@ -6,7 +6,7 @@ import { SkyHarnessFilters } from '@skyux/core/testing'; // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type export interface SkyTabHarnessFilters extends SkyHarnessFilters { /** - * Finds tabs whose tab heading matches this value. + * Finds tabs whose id matches given value. */ - tabHeading: string; + tabId: string; } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts index 48a3216fad..433f695723 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts @@ -22,21 +22,18 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { filters: SkyTabHarnessFilters, ): HarnessPredicate { return new HarnessPredicate(SkyTabHarness, filters).addOption( - 'tabHeading', - filters.tabHeading, - async (harness, tabHeading) => { - const harnessTabHeading = await harness.getTabHeading(); - return await HarnessPredicate.stringMatches( - harnessTabHeading, - tabHeading, - ); + 'tabId', + filters.tabId, + async (harness, tabId) => { + const harnessId = await harness.getTabId(); + return await HarnessPredicate.stringMatches(harnessId, tabId); }, ); } - public async getTabHeading(): Promise { + public async getTabId(): Promise { // eslint-disable-next-line @cspell/spellchecker - return await (await this.host()).getAttribute('tabheading'); + return await (await this.#getTab()).getAttribute('id'); } public async getLayout(): Promise { @@ -44,11 +41,6 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { } public async isVisible(): Promise { - return await (await this.#getTab()).getProperty('hidden'); - } - - public async getTabIndexValue(): Promise { - // eslint-disable-next-line @cspell/spellchecker - return await (await this.host()).getAttribute('tabindexvalue'); + return !(await (await this.#getTab()).getProperty('hidden')); } } diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts index e69de29bb2..e277b8a4c3 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts @@ -0,0 +1,224 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { Component } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { SkyAppTestUtility } from '@skyux-sdk/testing'; +import { SkyTabIndex, SkyTabsModule } from '@skyux/tabs'; + +import { SkyTabButtonHarness } from './tab-button-harness'; +import { SkyTabsetHarness } from './tabset-harness'; + +@Component({ + standalone: true, + imports: [SkyTabsModule], + template: ` + + + Tab 1 Content + + Tab 2 Content + Tab 3 Content + + + + + + `, +}) +class TestComponent { + public active = false; + public ariaLabel: string | undefined; + public ariaLabelledBy: string | undefined; + public permalinkId: string | undefined; + public permalinkValue: string | undefined; + public tabHeading: string | undefined = 'Tab 1'; + public tabIndexValue: SkyTabIndex | undefined; + + public newTabAction(): void { + // This function is for the spy. + } + + public openTabAction(): void { + // This function is for the spy. + } +} + +fdescribe('Tab harness', () => { + async function setupTest(options: { dataSkyId?: string } = {}): Promise<{ + tabsetHarness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(TestComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + const tabsetHarness: SkyTabsetHarness = options.dataSkyId + ? await loader.getHarness( + SkyTabsetHarness.with({ dataSkyId: options.dataSkyId }), + ) + : await loader.getHarness(SkyTabsetHarness); + + return { tabsetHarness, fixture }; + } + + it('should click the new tab button', async () => { + const { tabsetHarness, fixture } = await setupTest(); + const newTabClickSpy = spyOn(fixture.componentInstance, 'newTabAction'); + + await tabsetHarness.clickNewTabButton(); + + expect(newTabClickSpy).toHaveBeenCalled(); + }); + + it('should throw an error if attempting to click new tab if it is not enabled', async () => { + const { tabsetHarness } = await setupTest({ + dataSkyId: 'other-tabset', + }); + + await expectAsync(tabsetHarness.clickNewTabButton()).toBeRejectedWithError( + 'Unable to find the new tab button.', + ); + }); + + it('should click the open tab button', async () => { + const { tabsetHarness, fixture } = await setupTest(); + const openTabClickSpy = spyOn(fixture.componentInstance, 'openTabAction'); + + await tabsetHarness.clickOpenTabButton(); + + expect(openTabClickSpy).toHaveBeenCalled(); + }); + + it('should throw an error if attempting to click open tab if it is not enabled', async () => { + const { tabsetHarness } = await setupTest({ + dataSkyId: 'other-tabset', + }); + + await expectAsync(tabsetHarness.clickOpenTabButton()).toBeRejectedWithError( + 'Unable to find the open tab button.', + ); + }); + + it('should get aria-label', async () => { + const { tabsetHarness, fixture } = await setupTest(); + fixture.componentInstance.ariaLabel = 'aria label'; + fixture.detectChanges(); + + await expectAsync(tabsetHarness.getAriaLabel()).toBeResolvedTo( + 'aria label', + ); + }); + + it('should get aria-labelledby', async () => { + const { tabsetHarness, fixture } = await setupTest(); + fixture.componentInstance.ariaLabelledBy = 'aria-labelledby'; + fixture.detectChanges(); + + await expectAsync(tabsetHarness.getAriaLabelledBy()).toBeResolvedTo( + 'aria-labelledby', + ); + }); + + it('should get a tab button harness by tab heading', async () => { + const { tabsetHarness } = await setupTest(); + const tabOne = await tabsetHarness.getTabButtonHarness('Tab 1'); + + await expectAsync(tabOne.getTabHeading()).toBeResolvedTo('Tab 1'); + }); + + it('should get all tab button harnesses', async () => { + const { tabsetHarness } = await setupTest(); + const tabs = await tabsetHarness.getTabButtonHarnesses(); + + expect(tabs.length).toBe(4); + }); + + it('should get the active tab button', async () => { + const { tabsetHarness } = await setupTest(); + const activeTab = await tabsetHarness.getActiveTabButton(); + + await expectAsync(activeTab?.getTabHeading()).toBeResolvedTo('Tab 1'); + }); + + it('should get the mode when tab', async () => { + const { tabsetHarness } = await setupTest(); + + await expectAsync(tabsetHarness.getMode()).toBeResolvedTo('tabs'); + }); + + it('should get the mode when dropdown', async () => { + const { tabsetHarness, fixture } = await setupTest(); + fixture.nativeElement.style.width = '50px'; + SkyAppTestUtility.fireDomEvent(window, 'resize'); + fixture.detectChanges(); + await fixture.whenStable(); + + await expectAsync(tabsetHarness.getMode()).toBeResolvedTo('dropdown'); + }); + + it('should get the tab harness from tab heading', async () => { + const { tabsetHarness } = await setupTest(); + let tabHarness = await tabsetHarness.getTabHarness('Tab 1'); + await expectAsync(tabHarness.isVisible()).toBeResolvedTo(true); + tabHarness = await tabsetHarness.getTabHarness('Tab 2'); + await expectAsync(tabHarness.isVisible()).toBeResolvedTo(false); + }); + + describe('tab button harness', () => { + async function setupTabButtonTest(tabHeading: string): Promise<{ + tabButtonHarness: SkyTabButtonHarness; + tabsetHarness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + const { tabsetHarness, fixture } = await setupTest(); + const tabButtonHarness = + await tabsetHarness.getTabButtonHarness(tabHeading); + return { tabButtonHarness, tabsetHarness, fixture }; + } + + it('should click the tab button and change the active tab', async () => { + const { tabButtonHarness } = await setupTabButtonTest('Tab 2'); + await expectAsync(tabButtonHarness.isActive()).toBeResolvedTo(false); + await tabButtonHarness.click(); + await expectAsync(tabButtonHarness.isActive()).toBeResolvedTo(true); + }); + + it('should get the permalink for a tab button', async () => { + const { tabButtonHarness, fixture } = await setupTabButtonTest('Tab 1'); + fixture.componentInstance.permalinkId = 'test-tab'; + fixture.componentInstance.permalinkValue = 'tab-1'; + fixture.detectChanges(); + + await expectAsync(tabButtonHarness.getPermalink()).toBeResolvedTo( + '/?test-tab-active-tab=tab-1', + ); + }); + + it('should get when tab is disabled', async () => { + const { tabButtonHarness } = await setupTabButtonTest('Disabled tab'); + await expectAsync(tabButtonHarness.isDisabled()).toBeResolvedTo(true); + }); + + it('should get when tab is not disabled', async () => { + const { tabButtonHarness } = await setupTabButtonTest('Tab 1'); + await expectAsync(tabButtonHarness.isDisabled()).toBeResolvedTo(false); + }); + + it('should get a tab harness', async () => { + const { tabButtonHarness } = await setupTabButtonTest('Tab 1'); + const tabHarness = await tabButtonHarness.getTabHarness(); + await expectAsync(tabHarness.isVisible()).toBeResolvedTo(true); + }); + }); +}); diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 85a495ce36..2c7ff34b10 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -1,8 +1,10 @@ +import { HarnessPredicate } from '@angular/cdk/testing'; import { SkyComponentHarness } from '@skyux/core/testing'; import { SkyTabsetButtonsDisplayMode } from '@skyux/tabs'; import { SkyTabButtonHarness } from './tab-button-harness'; import { SkyTabHarness } from './tab-harness'; +import { SkyTabsetHarnessFilters } from './tabset-harness-filters'; /** * Harness for interacting with a tabset component in tests. @@ -16,6 +18,16 @@ export class SkyTabsetHarness extends SkyComponentHarness { #getTabset = this.locatorFor('.sky-tabset'); #getTabButtons = this.locatorForAll(SkyTabButtonHarness); + /** + * Gets a `HarnessPredicate` that can be used to search for a + * `SkyTabsetHarness` that meets certain criteria. + */ + public static with( + filters: SkyTabsetHarnessFilters, + ): HarnessPredicate { + return SkyTabsetHarness.getDataSkyIdPredicate(filters); + } + public async clickNewTabButton(): Promise { const newTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-new', @@ -48,10 +60,6 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await (await this.#getTabset()).getAttribute('aria-labelledby'); } - public async getPermalinkId(): Promise { - return await (await this.host()).getAttribute('permalinkId'); - } - public async getTabButtonHarness( tabHeading: string, ): Promise { @@ -59,17 +67,16 @@ export class SkyTabsetHarness extends SkyComponentHarness { SkyTabButtonHarness.with({ tabHeading: tabHeading }), )(); } - - public async getTabHarness(tabHeading: string): Promise { - return await this.locatorFor( - SkyTabHarness.with({ tabHeading: tabHeading }), - )(); - } - public async getTabButtonHarnesses(): Promise { return await this.#getTabButtons(); } + public async getTabHarness(tabHeading: string): Promise { + const tabButton = await this.getTabButtonHarness(tabHeading); + const id = await tabButton.getTabId(); + return await this.locatorFor(SkyTabHarness.with({ tabId: id }))(); + } + public async getActiveTabButton(): Promise { const tabButtonHarnesses = await this.getTabButtonHarnesses(); @@ -79,6 +86,7 @@ export class SkyTabsetHarness extends SkyComponentHarness { } } + /* istanbul ignore next */ return null; } From deebf6c157203595c2d283df792c43e029c9ec85 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 27 Jan 2025 21:29:57 -0500 Subject: [PATCH 06/18] 100 code coverage --- .../modules/dropdown/dropdown-menu-harness.ts | 7 +- .../src/modules/tabs/tab-button-harness.ts | 8 ++ .../testing/src/modules/tabs/tab-harness.ts | 4 +- .../src/modules/tabs/tabset-harness.spec.ts | 106 +++++++++++++++--- .../src/modules/tabs/tabset-harness.ts | 36 ++++++ 5 files changed, 143 insertions(+), 18 deletions(-) diff --git a/libs/components/popovers/testing/src/modules/dropdown/dropdown-menu-harness.ts b/libs/components/popovers/testing/src/modules/dropdown/dropdown-menu-harness.ts index 3aa733557f..2fcdbe4b0c 100644 --- a/libs/components/popovers/testing/src/modules/dropdown/dropdown-menu-harness.ts +++ b/libs/components/popovers/testing/src/modules/dropdown/dropdown-menu-harness.ts @@ -1,5 +1,8 @@ import { HarnessPredicate } from '@angular/cdk/testing'; -import { SkyComponentHarness, SkyOverlayHarness } from '@skyux/core/testing'; +import { + SkyOverlayHarness, + SkyQueryableComponentHarness, +} from '@skyux/core/testing'; import { SkyDropdownItemHarness } from './dropdown-item-harness'; import { SkyDropdownItemHarnessFilters } from './dropdown-item-harness.filters'; @@ -8,7 +11,7 @@ import { SkyDropdownMenuHarnessFilters } from './dropdown-menu-harness.filters'; /** * Harness for interacting with dropdown menu in tests. */ -export class SkyDropdownMenuHarness extends SkyComponentHarness { +export class SkyDropdownMenuHarness extends SkyQueryableComponentHarness { /** * @internal */ diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index f31c2e0c21..62cfb68873 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -39,6 +39,14 @@ export class SkyTabButtonHarness extends SkyComponentHarness { return await (await this.#getTabButton()).click(); } + public async clickRemoveButton(): Promise { + const button = await this.locatorForOptional('.sky-btn-tab-close')(); + if (!button) { + throw new Error('Unable to find remove tab button.'); + } + return await button.click(); + } + public async getTabHeading(): Promise { return ( // eslint-disable-next-line @cspell/spellchecker diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts index 433f695723..f62d79cf11 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts @@ -36,8 +36,8 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { return await (await this.#getTab()).getAttribute('id'); } - public async getLayout(): Promise { - return await (await this.host()).getAttribute('layout'); + public async getLayout(): Promise { + return (await (await this.host()).getAttribute('layout')) || 'none'; } public async isVisible(): Promise { diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts index e277b8a4c3..9f6e628a90 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts @@ -3,6 +3,7 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { SkyAppTestUtility } from '@skyux-sdk/testing'; +import { SkyPageModule } from '@skyux/pages'; import { SkyTabIndex, SkyTabsModule } from '@skyux/tabs'; import { SkyTabButtonHarness } from './tab-button-harness'; @@ -10,19 +11,20 @@ import { SkyTabsetHarness } from './tabset-harness'; @Component({ standalone: true, - imports: [SkyTabsModule], + imports: [SkyTabsModule, SkyPageModule], template: ` Tab 1 Content @@ -30,9 +32,13 @@ import { SkyTabsetHarness } from './tabset-harness'; Tab 3 Content - - - + + + + + + + `, }) class TestComponent { @@ -44,16 +50,12 @@ class TestComponent { public tabHeading: string | undefined = 'Tab 1'; public tabIndexValue: SkyTabIndex | undefined; - public newTabAction(): void { - // This function is for the spy. - } - - public openTabAction(): void { + public tabAction(): void { // This function is for the spy. } } -fdescribe('Tab harness', () => { +describe('Tab harness', () => { async function setupTest(options: { dataSkyId?: string } = {}): Promise<{ tabsetHarness: SkyTabsetHarness; fixture: ComponentFixture; @@ -74,7 +76,7 @@ fdescribe('Tab harness', () => { it('should click the new tab button', async () => { const { tabsetHarness, fixture } = await setupTest(); - const newTabClickSpy = spyOn(fixture.componentInstance, 'newTabAction'); + const newTabClickSpy = spyOn(fixture.componentInstance, 'tabAction'); await tabsetHarness.clickNewTabButton(); @@ -93,7 +95,7 @@ fdescribe('Tab harness', () => { it('should click the open tab button', async () => { const { tabsetHarness, fixture } = await setupTest(); - const openTabClickSpy = spyOn(fixture.componentInstance, 'openTabAction'); + const openTabClickSpy = spyOn(fixture.componentInstance, 'tabAction'); await tabsetHarness.clickOpenTabButton(); @@ -175,6 +177,18 @@ fdescribe('Tab harness', () => { await expectAsync(tabHarness.isVisible()).toBeResolvedTo(false); }); + it('should get the tab layout in pages', async () => { + const { tabsetHarness } = await setupTest({ dataSkyId: 'other-tabset' }); + const tabHarness = await tabsetHarness.getTabHarness('Tab 1'); + await expectAsync(tabHarness.getLayout()).toBeResolvedTo('blocks'); + }); + + it('should get the default tab layout', async () => { + const { tabsetHarness } = await setupTest(); + const tabHarness = await tabsetHarness.getTabHarness('Tab 1'); + await expectAsync(tabHarness.getLayout()).toBeResolvedTo('none'); + }); + describe('tab button harness', () => { async function setupTabButtonTest(tabHeading: string): Promise<{ tabButtonHarness: SkyTabButtonHarness; @@ -220,5 +234,69 @@ fdescribe('Tab harness', () => { const tabHarness = await tabButtonHarness.getTabHarness(); await expectAsync(tabHarness.isVisible()).toBeResolvedTo(true); }); + + it('should throw an error if trying to click dropdown when not in dropdown mode', async () => { + const { tabsetHarness } = await setupTest(); + await expectAsync(tabsetHarness.clickDropdownTab()).toBeRejectedWithError( + 'Cannot click dropdown tab button, tab is not in dropdown mode.', + ); + }); + + it('should throw an error if trying to close a tab with no close button', async () => { + const { tabButtonHarness } = await setupTabButtonTest('Tab 2'); + await expectAsync( + tabButtonHarness.clickRemoveButton(), + ).toBeRejectedWithError('Unable to find remove tab button.'); + }); + + it('should click close button', async () => { + const { tabButtonHarness, fixture } = await setupTabButtonTest('Tab 1'); + const closeClickSpy = spyOn(fixture.componentInstance, 'tabAction'); + await tabButtonHarness.clickRemoveButton(); + expect(closeClickSpy).toHaveBeenCalled(); + }); + }); + + describe('in dropdown mode', () => { + async function shrinkScreen( + fixture: ComponentFixture, + ): Promise { + fixture.nativeElement.style.width = '50px'; + SkyAppTestUtility.fireDomEvent(window, 'resize'); + fixture.detectChanges(); + await fixture.whenStable(); + } + it('should click dropdown tab', async () => { + const { tabsetHarness, fixture } = await setupTest(); + await shrinkScreen(fixture); + await expectAsync(tabsetHarness.clickDropdownTab()).toBeResolved(); + }); + + it('should get a tab button harness from tab heading', async () => { + const { tabsetHarness, fixture } = await setupTest(); + await shrinkScreen(fixture); + await tabsetHarness.clickDropdownTab(); + const tabButtonHarness = await tabsetHarness.getTabButtonHarness('Tab 1'); + + await expectAsync(tabButtonHarness.isActive()).toBeResolvedTo(true); + }); + + it('should get all tab button harnesses', async () => { + const { tabsetHarness, fixture } = await setupTest(); + await shrinkScreen(fixture); + await tabsetHarness.clickDropdownTab(); + const tabButtonHarnesses = await tabsetHarness.getTabButtonHarnesses(); + expect(tabButtonHarnesses.length).toBe(4); + }); + + it('should throw an error when trying to get tab buttons when dropdown is closed', async () => { + const { tabsetHarness, fixture } = await setupTest(); + await shrinkScreen(fixture); + await expectAsync( + tabsetHarness.getTabButtonHarnesses(), + ).toBeRejectedWithError( + 'Cannot get tab button when tabs is in dropdown mode and is closed.', + ); + }); }); }); diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 2c7ff34b10..9b1203433a 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -1,5 +1,9 @@ import { HarnessPredicate } from '@angular/cdk/testing'; import { SkyComponentHarness } from '@skyux/core/testing'; +import { + SkyDropdownHarness, + SkyDropdownMenuHarness, +} from '@skyux/popovers/testing'; import { SkyTabsetButtonsDisplayMode } from '@skyux/tabs'; import { SkyTabButtonHarness } from './tab-button-harness'; @@ -17,6 +21,7 @@ export class SkyTabsetHarness extends SkyComponentHarness { #getTabset = this.locatorFor('.sky-tabset'); #getTabButtons = this.locatorForAll(SkyTabButtonHarness); + #getTabDropdown = this.locatorFor(SkyDropdownHarness); /** * Gets a `HarnessPredicate` that can be used to search for a @@ -40,6 +45,16 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await newTabButton.click(); } + public async clickDropdownTab(): Promise { + if (!((await this.getMode()) === 'dropdown')) { + throw new Error( + 'Cannot click dropdown tab button, tab is not in dropdown mode.', + ); + } + const button = await this.locatorFor(SkyDropdownHarness)(); + return await button.clickDropdownButton(); + } + public async clickOpenTabButton(): Promise { const openTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-open', @@ -63,11 +78,22 @@ export class SkyTabsetHarness extends SkyComponentHarness { public async getTabButtonHarness( tabHeading: string, ): Promise { + if ((await this.getMode()) === 'dropdown') { + const menu = await this.#getDropdownMenu(); + return await menu.queryHarness( + SkyTabButtonHarness.with({ tabHeading: tabHeading }), + ); + } return await this.locatorFor( SkyTabButtonHarness.with({ tabHeading: tabHeading }), )(); } + public async getTabButtonHarnesses(): Promise { + if ((await this.getMode()) === 'dropdown') { + const menu = await this.#getDropdownMenu(); + return await menu.queryHarnesses(SkyTabButtonHarness); + } return await this.#getTabButtons(); } @@ -96,4 +122,14 @@ export class SkyTabsetHarness extends SkyComponentHarness { } return 'dropdown'; } + + async #getDropdownMenu(): Promise { + const dropdown = await this.#getTabDropdown(); + if (!(await dropdown?.isOpen())) { + throw new Error( + 'Cannot get tab button when tabs is in dropdown mode and is closed.', + ); + } + return await dropdown.getDropdownMenu(); + } } From 6838403197687660d009c560e29e73ab42afa774 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 27 Jan 2025 21:38:33 -0500 Subject: [PATCH 07/18] alphabetize --- .../src/modules/tabs/tab-button-harness.ts | 24 ++++---- .../src/modules/tabs/tab-harness-filters.ts | 1 + .../testing/src/modules/tabs/tab-harness.ts | 13 ++-- .../src/modules/tabs/tabset-harness.ts | 60 +++++++++---------- 4 files changed, 50 insertions(+), 48 deletions(-) diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index 62cfb68873..96ee01bc3d 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -47,19 +47,23 @@ export class SkyTabButtonHarness extends SkyComponentHarness { return await button.click(); } + public async getPermalink(): Promise { + return await (await this.#getTabButton()).getAttribute('href'); + } + + public async getTabHarness(): Promise { + return await this.documentRootLocatorFactory().locatorFor( + SkyTabHarness.with({ tabId: await this.getTabId() }), + )(); + } + public async getTabHeading(): Promise { return ( // eslint-disable-next-line @cspell/spellchecker - ( - await (await this.locatorFor('.sky-tab-heading > span[skyid]')()).text() - ).trim() + await (await this.locatorFor('.sky-tab-heading > span[skyid]')()).text() ); } - public async getPermalink(): Promise { - return await (await this.#getTabButton()).getAttribute('href'); - } - public async isActive(): Promise { return await (await this.#getTabButton()).hasClass('sky-btn-tab-selected'); } @@ -68,12 +72,6 @@ export class SkyTabButtonHarness extends SkyComponentHarness { return await (await this.#getTabButton()).hasClass('sky-btn-tab-disabled'); } - public async getTabHarness(): Promise { - return await this.documentRootLocatorFactory().locatorFor( - SkyTabHarness.with({ tabId: await this.getTabId() }), - )(); - } - /** * @internal */ diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts index 41e45cf3e6..250dcb4beb 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts @@ -7,6 +7,7 @@ import { SkyHarnessFilters } from '@skyux/core/testing'; export interface SkyTabHarnessFilters extends SkyHarnessFilters { /** * Finds tabs whose id matches given value. + * @internal */ tabId: string; } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts index f62d79cf11..f8f906cfb9 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts @@ -17,6 +17,7 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { /** * Gets a `HarnessPredicate` that can be used to search for a * `SkyTabHarness` that meets certain criteria. + * @internal */ public static with( filters: SkyTabHarnessFilters, @@ -31,15 +32,17 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { ); } - public async getTabId(): Promise { - // eslint-disable-next-line @cspell/spellchecker - return await (await this.#getTab()).getAttribute('id'); - } - public async getLayout(): Promise { return (await (await this.host()).getAttribute('layout')) || 'none'; } + /** + * @internal + */ + public async getTabId(): Promise { + return await (await this.#getTab()).getAttribute('id'); + } + public async isVisible(): Promise { return !(await (await this.#getTab()).getProperty('hidden')); } diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 9b1203433a..4564680ced 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -33,6 +33,16 @@ export class SkyTabsetHarness extends SkyComponentHarness { return SkyTabsetHarness.getDataSkyIdPredicate(filters); } + public async clickDropdownTab(): Promise { + if (!((await this.getMode()) === 'dropdown')) { + throw new Error( + 'Cannot click dropdown tab button, tab is not in dropdown mode.', + ); + } + const button = await this.locatorFor(SkyDropdownHarness)(); + return await button.clickDropdownButton(); + } + public async clickNewTabButton(): Promise { const newTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-new', @@ -45,16 +55,6 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await newTabButton.click(); } - public async clickDropdownTab(): Promise { - if (!((await this.getMode()) === 'dropdown')) { - throw new Error( - 'Cannot click dropdown tab button, tab is not in dropdown mode.', - ); - } - const button = await this.locatorFor(SkyDropdownHarness)(); - return await button.clickDropdownButton(); - } - public async clickOpenTabButton(): Promise { const openTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-open', @@ -67,6 +67,19 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await openTabButton.click(); } + public async getActiveTabButton(): Promise { + const tabButtonHarnesses = await this.getTabButtonHarnesses(); + + for (const harness of tabButtonHarnesses) { + if (await harness.isActive()) { + return harness; + } + } + + /* istanbul ignore next */ + return null; + } + public async getAriaLabel(): Promise { return await (await this.#getTabset()).getAttribute('aria-label'); } @@ -75,6 +88,13 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await (await this.#getTabset()).getAttribute('aria-labelledby'); } + public async getMode(): Promise { + if (await (await this.#getTabset()).hasClass('sky-tabset-mode-tabs')) { + return 'tabs'; + } + return 'dropdown'; + } + public async getTabButtonHarness( tabHeading: string, ): Promise { @@ -103,26 +123,6 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await this.locatorFor(SkyTabHarness.with({ tabId: id }))(); } - public async getActiveTabButton(): Promise { - const tabButtonHarnesses = await this.getTabButtonHarnesses(); - - for (const harness of tabButtonHarnesses) { - if (await harness.isActive()) { - return harness; - } - } - - /* istanbul ignore next */ - return null; - } - - public async getMode(): Promise { - if (await (await this.#getTabset()).hasClass('sky-tabset-mode-tabs')) { - return 'tabs'; - } - return 'dropdown'; - } - async #getDropdownMenu(): Promise { const dropdown = await this.#getTabDropdown(); if (!(await dropdown?.isOpen())) { From ba2cfcd6997e075092bfae2449aed0ffc8501a7e Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 27 Jan 2025 21:45:48 -0500 Subject: [PATCH 08/18] documentation --- .../src/modules/tabs/tab-button-harness.ts | 21 +++++++++++++ .../testing/src/modules/tabs/tab-harness.ts | 6 ++++ .../src/modules/tabs/tabset-harness.ts | 30 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index 96ee01bc3d..625e881676 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -35,10 +35,16 @@ export class SkyTabButtonHarness extends SkyComponentHarness { ); } + /** + * Clicks the tab button. + */ public async click(): Promise { return await (await this.#getTabButton()).click(); } + /** + * Clicks the remove tab button if it is visible. + */ public async clickRemoveButton(): Promise { const button = await this.locatorForOptional('.sky-btn-tab-close')(); if (!button) { @@ -47,16 +53,25 @@ export class SkyTabButtonHarness extends SkyComponentHarness { return await button.click(); } + /** + * Gets the permalink that the page routes to when the tab is clicked. + */ public async getPermalink(): Promise { return await (await this.#getTabButton()).getAttribute('href'); } + /** + * Gets the `SkyTabHarness` controlled by this tab button. + */ public async getTabHarness(): Promise { return await this.documentRootLocatorFactory().locatorFor( SkyTabHarness.with({ tabId: await this.getTabId() }), )(); } + /** + * Gets the tab heading. + */ public async getTabHeading(): Promise { return ( // eslint-disable-next-line @cspell/spellchecker @@ -64,10 +79,16 @@ export class SkyTabButtonHarness extends SkyComponentHarness { ); } + /** + * Gets whether the tab button is active. + */ public async isActive(): Promise { return await (await this.#getTabButton()).hasClass('sky-btn-tab-selected'); } + /** + * Gets whether the tab button is disabled. + */ public async isDisabled(): Promise { return await (await this.#getTabButton()).hasClass('sky-btn-tab-disabled'); } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts index f8f906cfb9..756edbe788 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts @@ -32,6 +32,9 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { ); } + /** + * Gets the tab's layout. + */ public async getLayout(): Promise { return (await (await this.host()).getAttribute('layout')) || 'none'; } @@ -43,6 +46,9 @@ export class SkyTabHarness extends SkyQueryableComponentHarness { return await (await this.#getTab()).getAttribute('id'); } + /** + * Whether the tab content is visible. + */ public async isVisible(): Promise { return !(await (await this.#getTab()).getProperty('hidden')); } diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 4564680ced..2e7831b004 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -33,6 +33,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return SkyTabsetHarness.getDataSkyIdPredicate(filters); } + /** + * In `dropdown` mode, clicks the dropdown tab to open the tab dropdown menu. + */ public async clickDropdownTab(): Promise { if (!((await this.getMode()) === 'dropdown')) { throw new Error( @@ -43,6 +46,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await button.clickDropdownButton(); } + /** + * Clicks the new tab button if visible. + */ public async clickNewTabButton(): Promise { const newTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-new', @@ -55,6 +61,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await newTabButton.click(); } + /** + * Clicks the open tab button if visible. + */ public async clickOpenTabButton(): Promise { const openTabButton = await this.locatorForOptional( 'button.sky-tabset-btn-open', @@ -67,6 +76,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await openTabButton.click(); } + /** + * Gets the active tab button harness. + */ public async getActiveTabButton(): Promise { const tabButtonHarnesses = await this.getTabButtonHarnesses(); @@ -80,14 +92,23 @@ export class SkyTabsetHarness extends SkyComponentHarness { return null; } + /** + * Gets the tabset aria-label value. + */ public async getAriaLabel(): Promise { return await (await this.#getTabset()).getAttribute('aria-label'); } + /** + * Gets the tabset aria-labelledby value. + */ public async getAriaLabelledBy(): Promise { return await (await this.#getTabset()).getAttribute('aria-labelledby'); } + /** + * Gets the tabset's display mode. + */ public async getMode(): Promise { if (await (await this.#getTabset()).hasClass('sky-tabset-mode-tabs')) { return 'tabs'; @@ -95,6 +116,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return 'dropdown'; } + /** + * Gets a tab button harness with the given `tabHeading` + */ public async getTabButtonHarness( tabHeading: string, ): Promise { @@ -109,6 +133,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { )(); } + /** + * Gets an array of all tab button harnesses. + */ public async getTabButtonHarnesses(): Promise { if ((await this.getMode()) === 'dropdown') { const menu = await this.#getDropdownMenu(); @@ -117,6 +144,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await this.#getTabButtons(); } + /** + * Gets a tab harness for the tab with the given `tabHeading`. + */ public async getTabHarness(tabHeading: string): Promise { const tabButton = await this.getTabButtonHarness(tabHeading); const id = await tabButton.getTabId(); From ab2e686f54c2a3b6184eaa644d156441015d4593 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Tue, 28 Jan 2025 10:38:32 -0500 Subject: [PATCH 09/18] basic demo --- .../tabs/static-add-close/demo.component.html | 6 ++- .../static-add-close/demo.component.spec.ts | 54 +++++++++++++++++++ .../tabs/static-add-close/demo.component.ts | 2 +- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.html b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.html index 5d83b37460..692401afb8 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.html +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.html @@ -1,4 +1,8 @@ - + Content for Tab 1 Content for Tab 2 @if (showTab3) { diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts new file mode 100644 index 0000000000..d83f201f47 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts @@ -0,0 +1,54 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { SkyTabsetHarness } from '@skyux/tabs/testing'; + +import { DemoComponent } from './demo.component'; + +fdescribe('Static tabs demo with add and close', () => { + async function setupTest(options: { dataSkyId?: string }): Promise<{ + harness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(DemoComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + + const harness = await loader.getHarness( + SkyTabsetHarness.with({ dataSkyId: options.dataSkyId }), + ); + + return { harness, fixture }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [DemoComponent] }); + }); + + it('should set up tabs', async () => { + const { harness, fixture } = await setupTest({ dataSkyId: 'tab-demo' }); + + const spy = spyOn(fixture.componentInstance, 'onNewTabClick'); + await harness.clickNewTabButton(); + + expect(spy).toHaveBeenCalled(); + + const tabButtonHarnesses = await harness.getTabButtonHarnesses(); + expect(tabButtonHarnesses.length).toBe(3); + + const activeTab = await harness.getActiveTabButton(); + await expectAsync(activeTab?.getTabHeading()).toBeResolvedTo('Tab 1'); + }); + + it('should hide Tab 3 if it is closed', async () => { + const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); + + const tab3Harness = await harness.getTabButtonHarness('Tab 3'); + await tab3Harness.clickRemoveButton(); + + const tabButtons = await harness.getTabButtonHarnesses(); + expect(tabButtons.length).toBe(2); + }); +}); diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.ts index ca0cb0904c..8e381490cf 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.ts @@ -10,7 +10,7 @@ import { SkyTabsModule } from '@skyux/tabs'; export class DemoComponent { protected showTab3 = true; - protected onNewTabClick(): void { + public onNewTabClick(): void { alert('Add tab clicked!'); } } From 2a96310a01200716ed98bf228e1ceb2b0a4bd77d Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Tue, 28 Jan 2025 10:53:18 -0500 Subject: [PATCH 10/18] pages unit test --- .../record-page-content-component.spec.ts | 41 +++++++++++++++++++ .../record-page-overview-tab.component.ts | 9 ++++ .../static-add-close/demo.component.spec.ts | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts new file mode 100644 index 0000000000..f954fff495 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts @@ -0,0 +1,41 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; +import { SkyTabsetHarness } from '@skyux/tabs/testing'; + +import { RecordPageContentComponent } from './record-page-content.component'; +import { RecordPageOverviewTabHarness } from './record-page-overview-tab.component'; + +fdescribe('Record page content', () => { + async function setupTest(): Promise<{ + recordPageHarness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(RecordPageContentComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + + const recordPageHarness = await loader.getHarness(SkyTabsetHarness); + + return { recordPageHarness, fixture }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RecordPageContentComponent, NoopAnimationsModule], + }); + }); + + it('should get the overview tab harness', async () => { + const { recordPageHarness } = await setupTest(); + + const overviewTabHarness = await ( + await recordPageHarness.getTabHarness('Overview') + ).queryHarness(RecordPageOverviewTabHarness); + + await expectAsync(overviewTabHarness.isHarness()).toBeResolvedTo(true); + }); +}); diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts index 8b214083cd..3a7752fa39 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts @@ -1,3 +1,4 @@ +import { ComponentHarness } from '@angular/cdk/testing'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { SkyIconModule } from '@skyux/icon'; @@ -99,3 +100,11 @@ export class RecordPageOverviewTabComponent { }, ]; } + +export class RecordPageOverviewTabHarness extends ComponentHarness { + public static hostSelector = 'app-record-page-overview-tab'; + + public async isHarness(): Promise { + return true; + } +} diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts index d83f201f47..81dd164eec 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static-add-close/demo.component.spec.ts @@ -5,7 +5,7 @@ import { SkyTabsetHarness } from '@skyux/tabs/testing'; import { DemoComponent } from './demo.component'; -fdescribe('Static tabs demo with add and close', () => { +describe('Static tabs demo with add and close', () => { async function setupTest(options: { dataSkyId?: string }): Promise<{ harness: SkyTabsetHarness; fixture: ComponentFixture; From a1ca5d0e265aa73551c1b4885db6512f159ba34a Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Tue, 28 Jan 2025 10:58:39 -0500 Subject: [PATCH 11/18] missing fdescribe bleh --- .../record-page-content-component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts index f954fff495..f90e73f0b7 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts @@ -7,7 +7,7 @@ import { SkyTabsetHarness } from '@skyux/tabs/testing'; import { RecordPageContentComponent } from './record-page-content.component'; import { RecordPageOverviewTabHarness } from './record-page-overview-tab.component'; -fdescribe('Record page content', () => { +describe('Record page content', () => { async function setupTest(): Promise<{ recordPageHarness: SkyTabsetHarness; fixture: ComponentFixture; From 28c02f596501c0968c3e208d1f5eda04a2439681 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Tue, 28 Jan 2025 11:30:07 -0500 Subject: [PATCH 12/18] lint and peers --- .../record-page-overview-tab.component.ts | 2 +- libs/components/tabs/package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts index 3a7752fa39..c28c757040 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts @@ -105,6 +105,6 @@ export class RecordPageOverviewTabHarness extends ComponentHarness { public static hostSelector = 'app-record-page-overview-tab'; public async isHarness(): Promise { - return true; + return await Promise.resolve(true); } } diff --git a/libs/components/tabs/package.json b/libs/components/tabs/package.json index eb02b7ab0e..7a9b3bd18e 100644 --- a/libs/components/tabs/package.json +++ b/libs/components/tabs/package.json @@ -17,6 +17,7 @@ "homepage": "https://github.com/blackbaud/skyux#readme", "peerDependencies": { "@angular/animations": "^18.2.13", + "@angular/cdk": "^18.2.14", "@angular/common": "^18.2.13", "@angular/core": "^18.2.13", "@angular/platform-browser": "^18.2.13", From 62e1ee915abc1feca122f2cf7bf2ba289815617d Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Thu, 30 Jan 2025 16:09:25 -0500 Subject: [PATCH 13/18] pause --- .../src/modules/tabs/tab-button-harness.ts | 8 +-- .../src/modules/tabs/tab-harness-filters.ts | 13 ----- .../testing/src/modules/tabs/tab-harness.ts | 55 ------------------- .../src/modules/tabs/tabset-harness.ts | 8 ++- .../components/tabs/testing/src/public-api.ts | 1 + 5 files changed, 10 insertions(+), 75 deletions(-) delete mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts delete mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-harness.ts diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index 625e881676..fda653f99d 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -2,7 +2,7 @@ import { HarnessPredicate } from '@angular/cdk/testing'; import { SkyComponentHarness } from '@skyux/core/testing'; import { SkyTabButtonHarnessFilters } from './tab-button-harness-filters'; -import { SkyTabHarness } from './tab-harness'; +import { SkyTabContentHarness } from './tab-content-harness'; /** * Harness for interacting with a tab button component in tests. @@ -61,11 +61,11 @@ export class SkyTabButtonHarness extends SkyComponentHarness { } /** - * Gets the `SkyTabHarness` controlled by this tab button. + * Gets the `SkyTabContentHarness` controlled by this tab button. */ - public async getTabHarness(): Promise { + public async getTabHarness(): Promise { return await this.documentRootLocatorFactory().locatorFor( - SkyTabHarness.with({ tabId: await this.getTabId() }), + SkyTabContentHarness.with({ tabId: await this.getTabId() }), )(); } diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts deleted file mode 100644 index 250dcb4beb..0000000000 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness-filters.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SkyHarnessFilters } from '@skyux/core/testing'; - -/** - * A set of criteria that can be used to filter a list of `SkyTabHarness` instances. - */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type -export interface SkyTabHarnessFilters extends SkyHarnessFilters { - /** - * Finds tabs whose id matches given value. - * @internal - */ - tabId: string; -} diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts deleted file mode 100644 index 756edbe788..0000000000 --- a/libs/components/tabs/testing/src/modules/tabs/tab-harness.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { HarnessPredicate } from '@angular/cdk/testing'; -import { SkyQueryableComponentHarness } from '@skyux/core/testing'; - -import { SkyTabHarnessFilters } from './tab-harness-filters'; - -/** - * Harness for interacting with a tab component in tests. - */ -export class SkyTabHarness extends SkyQueryableComponentHarness { - /** - * @internal - */ - public static hostSelector = 'sky-tab'; - - #getTab = this.locatorFor('.sky-tab'); - - /** - * Gets a `HarnessPredicate` that can be used to search for a - * `SkyTabHarness` that meets certain criteria. - * @internal - */ - public static with( - filters: SkyTabHarnessFilters, - ): HarnessPredicate { - return new HarnessPredicate(SkyTabHarness, filters).addOption( - 'tabId', - filters.tabId, - async (harness, tabId) => { - const harnessId = await harness.getTabId(); - return await HarnessPredicate.stringMatches(harnessId, tabId); - }, - ); - } - - /** - * Gets the tab's layout. - */ - public async getLayout(): Promise { - return (await (await this.host()).getAttribute('layout')) || 'none'; - } - - /** - * @internal - */ - public async getTabId(): Promise { - return await (await this.#getTab()).getAttribute('id'); - } - - /** - * Whether the tab content is visible. - */ - public async isVisible(): Promise { - return !(await (await this.#getTab()).getProperty('hidden')); - } -} diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index 2e7831b004..beb9a88c16 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -7,7 +7,7 @@ import { import { SkyTabsetButtonsDisplayMode } from '@skyux/tabs'; import { SkyTabButtonHarness } from './tab-button-harness'; -import { SkyTabHarness } from './tab-harness'; +import { SkyTabContentHarness } from './tab-content-harness'; import { SkyTabsetHarnessFilters } from './tabset-harness-filters'; /** @@ -147,10 +147,12 @@ export class SkyTabsetHarness extends SkyComponentHarness { /** * Gets a tab harness for the tab with the given `tabHeading`. */ - public async getTabHarness(tabHeading: string): Promise { + public async getTabHarness( + tabHeading: string, + ): Promise { const tabButton = await this.getTabButtonHarness(tabHeading); const id = await tabButton.getTabId(); - return await this.locatorFor(SkyTabHarness.with({ tabId: id }))(); + return await this.locatorFor(SkyTabContentHarness.with({ tabId: id }))(); } async #getDropdownMenu(): Promise { diff --git a/libs/components/tabs/testing/src/public-api.ts b/libs/components/tabs/testing/src/public-api.ts index 67507ddf22..7c5bde1790 100644 --- a/libs/components/tabs/testing/src/public-api.ts +++ b/libs/components/tabs/testing/src/public-api.ts @@ -5,3 +5,4 @@ export { SkyTabsetHarness } from './modules/tabs/tabset-harness'; export { SkyTabsetHarnessFilters } from './modules/tabs/tabset-harness-filters'; export { SkyTabButtonHarness } from './modules/tabs/tab-button-harness'; export { SkyTabButtonHarnessFilters } from './modules/tabs/tab-button-harness-filters'; +export { SkyTabContentHarness } from './modules/tabs/tab-content-harness'; From 7b97f9707409df97d9bad769f9b5e931be1fbe33 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Thu, 30 Jan 2025 16:09:31 -0500 Subject: [PATCH 14/18] missed files --- .../tabs/tab-content-harness-filters.ts | 13 +++++ .../src/modules/tabs/tab-content-harness.ts | 55 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-content-harness-filters.ts create mode 100644 libs/components/tabs/testing/src/modules/tabs/tab-content-harness.ts diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-content-harness-filters.ts b/libs/components/tabs/testing/src/modules/tabs/tab-content-harness-filters.ts new file mode 100644 index 0000000000..0b35c84aa0 --- /dev/null +++ b/libs/components/tabs/testing/src/modules/tabs/tab-content-harness-filters.ts @@ -0,0 +1,13 @@ +import { SkyHarnessFilters } from '@skyux/core/testing'; + +/** + * A set of criteria that can be used to filter a list of `SkyTabContentHarness` instances. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type +export interface SkyTabContentHarnessFilters extends SkyHarnessFilters { + /** + * Finds tabs whose id matches given value. + * @internal + */ + tabId: string; +} diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-content-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-content-harness.ts new file mode 100644 index 0000000000..b58defb38f --- /dev/null +++ b/libs/components/tabs/testing/src/modules/tabs/tab-content-harness.ts @@ -0,0 +1,55 @@ +import { HarnessPredicate } from '@angular/cdk/testing'; +import { SkyQueryableComponentHarness } from '@skyux/core/testing'; + +import { SkyTabContentHarnessFilters } from './tab-content-harness-filters'; + +/** + * Harness for interacting with a tab component in tests. + */ +export class SkyTabContentHarness extends SkyQueryableComponentHarness { + /** + * @internal + */ + public static hostSelector = 'sky-tab'; + + #getTab = this.locatorFor('.sky-tab'); + + /** + * Gets a `HarnessPredicate` that can be used to search for a + * `SkyTabContentHarness` that meets certain criteria. + * @internal + */ + public static with( + filters: SkyTabContentHarnessFilters, + ): HarnessPredicate { + return new HarnessPredicate(SkyTabContentHarness, filters).addOption( + 'tabId', + filters.tabId, + async (harness, tabId) => { + const harnessId = await harness.getTabId(); + return await HarnessPredicate.stringMatches(harnessId, tabId); + }, + ); + } + + /** + * Gets the tab's layout. + */ + public async getLayout(): Promise { + return (await (await this.host()).getAttribute('layout')) || 'none'; + } + + /** + * @internal + */ + public async getTabId(): Promise { + return await (await this.#getTab()).getAttribute('id'); + } + + /** + * Whether the tab content is visible. + */ + public async isVisible(): Promise { + return !(await (await this.#getTab()).getProperty('hidden')); + } +} From 22d6cbfbf9499a6cf1a2f4891053b1202fbd995c Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Fri, 31 Jan 2025 10:29:05 -0500 Subject: [PATCH 15/18] component harness --- .../record-page-content-component.spec.ts | 4 +-- .../src/modules/tabs/tab-button-harness.ts | 2 +- .../src/modules/tabs/tabset-harness.spec.ts | 36 ++++++++++++------- .../src/modules/tabs/tabset-harness.ts | 12 +++++-- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts index f90e73f0b7..96460e92c6 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts @@ -29,11 +29,11 @@ describe('Record page content', () => { }); }); - it('should get the overview tab harness', async () => { + it("should get the overview tab's content harness", async () => { const { recordPageHarness } = await setupTest(); const overviewTabHarness = await ( - await recordPageHarness.getTabHarness('Overview') + await recordPageHarness.getTabContentHarness('Overview') ).queryHarness(RecordPageOverviewTabHarness); await expectAsync(overviewTabHarness.isHarness()).toBeResolvedTo(true); diff --git a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts index fda653f99d..eaa37eb6c8 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tab-button-harness.ts @@ -63,7 +63,7 @@ export class SkyTabButtonHarness extends SkyComponentHarness { /** * Gets the `SkyTabContentHarness` controlled by this tab button. */ - public async getTabHarness(): Promise { + public async getTabContentHarness(): Promise { return await this.documentRootLocatorFactory().locatorFor( SkyTabContentHarness.with({ tabId: await this.getTabId() }), )(); diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts index 9f6e628a90..19a78f8ea3 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.spec.ts @@ -169,24 +169,36 @@ describe('Tab harness', () => { await expectAsync(tabsetHarness.getMode()).toBeResolvedTo('dropdown'); }); - it('should get the tab harness from tab heading', async () => { + it('should get the tab content harness from tab heading', async () => { const { tabsetHarness } = await setupTest(); - let tabHarness = await tabsetHarness.getTabHarness('Tab 1'); - await expectAsync(tabHarness.isVisible()).toBeResolvedTo(true); - tabHarness = await tabsetHarness.getTabHarness('Tab 2'); - await expectAsync(tabHarness.isVisible()).toBeResolvedTo(false); + let tabContentHarness = await tabsetHarness.getTabContentHarness('Tab 1'); + await expectAsync(tabContentHarness.isVisible()).toBeResolvedTo(true); + tabContentHarness = await tabsetHarness.getTabContentHarness('Tab 2'); + await expectAsync(tabContentHarness.isVisible()).toBeResolvedTo(false); }); it('should get the tab layout in pages', async () => { const { tabsetHarness } = await setupTest({ dataSkyId: 'other-tabset' }); - const tabHarness = await tabsetHarness.getTabHarness('Tab 1'); - await expectAsync(tabHarness.getLayout()).toBeResolvedTo('blocks'); + const tabContentHarness = await tabsetHarness.getTabContentHarness('Tab 1'); + await expectAsync(tabContentHarness.getLayout()).toBeResolvedTo('blocks'); }); it('should get the default tab layout', async () => { const { tabsetHarness } = await setupTest(); - const tabHarness = await tabsetHarness.getTabHarness('Tab 1'); - await expectAsync(tabHarness.getLayout()).toBeResolvedTo('none'); + const tabContentHarness = await tabsetHarness.getTabContentHarness('Tab 1'); + await expectAsync(tabContentHarness.getLayout()).toBeResolvedTo('none'); + }); + + it('should click a tab', async () => { + const { tabsetHarness } = await setupTest(); + await expectAsync( + (await tabsetHarness.getActiveTabButton())?.getTabHeading(), + ).toBeResolvedTo('Tab 1'); + + await tabsetHarness.clickTabButton('Tab 2'); + await expectAsync( + (await tabsetHarness.getActiveTabButton())?.getTabHeading(), + ).toBeResolvedTo('Tab 2'); }); describe('tab button harness', () => { @@ -229,10 +241,10 @@ describe('Tab harness', () => { await expectAsync(tabButtonHarness.isDisabled()).toBeResolvedTo(false); }); - it('should get a tab harness', async () => { + it('should get a tab content harness', async () => { const { tabButtonHarness } = await setupTabButtonTest('Tab 1'); - const tabHarness = await tabButtonHarness.getTabHarness(); - await expectAsync(tabHarness.isVisible()).toBeResolvedTo(true); + const tabContentHarness = await tabButtonHarness.getTabContentHarness(); + await expectAsync(tabContentHarness.isVisible()).toBeResolvedTo(true); }); it('should throw an error if trying to click dropdown when not in dropdown mode', async () => { diff --git a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts index beb9a88c16..07700aff07 100644 --- a/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts +++ b/libs/components/tabs/testing/src/modules/tabs/tabset-harness.ts @@ -76,6 +76,14 @@ export class SkyTabsetHarness extends SkyComponentHarness { return await openTabButton.click(); } + /** + * Clicks a tab button with a `tabHeading` matching the input. + */ + public async clickTabButton(tabHeading: string): Promise { + const tabButton = await this.getTabButtonHarness(tabHeading); + return await tabButton.click(); + } + /** * Gets the active tab button harness. */ @@ -145,9 +153,9 @@ export class SkyTabsetHarness extends SkyComponentHarness { } /** - * Gets a tab harness for the tab with the given `tabHeading`. + * Gets a tab content harness for the tab with the given `tabHeading`. */ - public async getTabHarness( + public async getTabContentHarness( tabHeading: string, ): Promise { const tabButton = await this.getTabButtonHarness(tabHeading); From b1f8d08a82ecb746feeba82bd20500603b8ca69e Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 3 Feb 2025 10:09:04 -0500 Subject: [PATCH 16/18] code example rework --- .../record-page-content-component.spec.ts | 6 ++++-- .../record-page-overview-tab-harness.ts | 10 ++++++++++ .../record-page-overview-tab.component.ts | 9 --------- 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab-harness.ts diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts index 96460e92c6..bb5bf71456 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-content-component.spec.ts @@ -5,7 +5,7 @@ import { provideRouter } from '@angular/router'; import { SkyTabsetHarness } from '@skyux/tabs/testing'; import { RecordPageContentComponent } from './record-page-content.component'; -import { RecordPageOverviewTabHarness } from './record-page-overview-tab.component'; +import { RecordPageOverviewTabHarness } from './record-page-overview-tab-harness'; describe('Record page content', () => { async function setupTest(): Promise<{ @@ -36,6 +36,8 @@ describe('Record page content', () => { await recordPageHarness.getTabContentHarness('Overview') ).queryHarness(RecordPageOverviewTabHarness); - await expectAsync(overviewTabHarness.isHarness()).toBeResolvedTo(true); + const overviewBoxes = await overviewTabHarness.getBoxes(); + + expect(overviewBoxes.length).toBe(3); }); }); diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab-harness.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab-harness.ts new file mode 100644 index 0000000000..73acb592cd --- /dev/null +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab-harness.ts @@ -0,0 +1,10 @@ +import { ComponentHarness } from '@angular/cdk/testing'; +import { SkyBoxHarness } from '@skyux/layout/testing'; + +export class RecordPageOverviewTabHarness extends ComponentHarness { + public static hostSelector = 'app-record-page-overview-tab'; + + public async getBoxes(): Promise { + return await this.locatorForAll(SkyBoxHarness)(); + } +} diff --git a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts index c28c757040..8b214083cd 100644 --- a/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts +++ b/apps/code-examples/src/app/code-examples/pages/page/record-page-tabs-layout-demo/record-page-overview-tab.component.ts @@ -1,4 +1,3 @@ -import { ComponentHarness } from '@angular/cdk/testing'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { SkyIconModule } from '@skyux/icon'; @@ -100,11 +99,3 @@ export class RecordPageOverviewTabComponent { }, ]; } - -export class RecordPageOverviewTabHarness extends ComponentHarness { - public static hostSelector = 'app-record-page-overview-tab'; - - public async isHarness(): Promise { - return await Promise.resolve(true); - } -} From 4a9c69803ed59694fccda6e08b634b05f181c7ca Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 3 Feb 2025 10:30:53 -0500 Subject: [PATCH 17/18] add extra code example tests --- .../dynamic-add-close/demo.component.html | 6 ++- .../dynamic-add-close/demo.component.spec.ts | 50 +++++++++++++++++++ .../tabs/dynamic-add-close/demo.component.ts | 4 +- .../tabs/tabs/dynamic/demo.component.html | 2 +- .../tabs/tabs/dynamic/demo.component.spec.ts | 39 +++++++++++++++ .../tabs/tabs/static/demo.component.html | 2 +- .../tabs/tabs/static/demo.component.spec.ts | 39 +++++++++++++++ 7 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts create mode 100644 apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.spec.ts create mode 100644 apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.spec.ts diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.html b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.html index 4c9bcdd98a..1966ce4f3c 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.html +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.html @@ -1,4 +1,8 @@ - + @for (tab of tabArray; track tab; let i = $index) { {{ tab.tabContent }} diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts new file mode 100644 index 0000000000..747fcc6253 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts @@ -0,0 +1,50 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { SkyTabsetHarness } from '@skyux/tabs/testing'; + +import { DemoComponent } from './demo.component'; + +describe('Static tabs demo with add and close', () => { + async function setupTest(options: { dataSkyId?: string }): Promise<{ + harness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(DemoComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + + const harness = await loader.getHarness( + SkyTabsetHarness.with({ dataSkyId: options.dataSkyId }), + ); + + return { harness, fixture }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [DemoComponent] }); + }); + + fit('should set up tabs', async () => { + const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); + + await harness.clickNewTabButton(); + const tabButtonHarnesses = await harness.getTabButtonHarnesses(); + expect(tabButtonHarnesses.length).toBe(4); + + const activeTab = await harness.getActiveTabButton(); + await expectAsync(activeTab?.getTabHeading()).toBeResolvedTo('Tab 1'); + }); + + it('should hide Tab 3 if it is closed', async () => { + const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); + + const tab3Harness = await harness.getTabButtonHarness('Tab 3'); + await tab3Harness.clickRemoveButton(); + + const tabButtons = await harness.getTabButtonHarnesses(); + expect(tabButtons.length).toBe(2); + }); +}); diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.ts index 4677a5ed8a..cb13e25130 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.ts @@ -25,7 +25,7 @@ export class DemoComponent { #tabCounter = 3; - protected onNewTabClick(): void { + public onNewTabClick(): void { this.#tabCounter++; this.tabArray.push({ @@ -34,7 +34,7 @@ export class DemoComponent { }); } - protected onCloseClick(arrayIndex: number): void { + public onCloseClick(arrayIndex: number): void { this.tabArray.splice(arrayIndex, 1); } } diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.html b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.html index eabad39c03..a8f5ce1ecb 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.html +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.html @@ -1,4 +1,4 @@ - + @for (tab of tabArray; track tab) { {{ tab.tabContent }} diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.spec.ts new file mode 100644 index 0000000000..16d4e39469 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic/demo.component.spec.ts @@ -0,0 +1,39 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { SkyTabsetHarness } from '@skyux/tabs/testing'; + +import { DemoComponent } from './demo.component'; + +describe('Static tabs demo with add and close', () => { + async function setupTest(options: { dataSkyId?: string }): Promise<{ + harness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(DemoComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + + const harness = await loader.getHarness( + SkyTabsetHarness.with({ dataSkyId: options.dataSkyId }), + ); + + return { harness, fixture }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [DemoComponent] }); + }); + + it('should set up tabs', async () => { + const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); + + const tabButtonHarnesses = await harness.getTabButtonHarnesses(); + expect(tabButtonHarnesses.length).toBe(3); + + const activeTab = await harness.getActiveTabButton(); + await expectAsync(activeTab?.getTabHeading()).toBeResolvedTo('Tab 1'); + }); +}); diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.html b/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.html index 9bf4513924..bc2aafaeeb 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.html +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.html @@ -1,4 +1,4 @@ - + Content for Tab 1 Content for Tab 2 Content for Tab 3 diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.spec.ts new file mode 100644 index 0000000000..16d4e39469 --- /dev/null +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/static/demo.component.spec.ts @@ -0,0 +1,39 @@ +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; +import { SkyTabsetHarness } from '@skyux/tabs/testing'; + +import { DemoComponent } from './demo.component'; + +describe('Static tabs demo with add and close', () => { + async function setupTest(options: { dataSkyId?: string }): Promise<{ + harness: SkyTabsetHarness; + fixture: ComponentFixture; + }> { + await TestBed.configureTestingModule({ + providers: [provideRouter([])], + }).compileComponents(); + const fixture = TestBed.createComponent(DemoComponent); + const loader = TestbedHarnessEnvironment.loader(fixture); + + const harness = await loader.getHarness( + SkyTabsetHarness.with({ dataSkyId: options.dataSkyId }), + ); + + return { harness, fixture }; + } + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [DemoComponent] }); + }); + + it('should set up tabs', async () => { + const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); + + const tabButtonHarnesses = await harness.getTabButtonHarnesses(); + expect(tabButtonHarnesses.length).toBe(3); + + const activeTab = await harness.getActiveTabButton(); + await expectAsync(activeTab?.getTabHeading()).toBeResolvedTo('Tab 1'); + }); +}); From 837717f86e3f3f7efb04dbf3fc84da34169dcac2 Mon Sep 17 00:00:00 2001 From: Sandhya Raja Sabeson Date: Mon, 3 Feb 2025 10:31:02 -0500 Subject: [PATCH 18/18] fit --- .../tabs/tabs/dynamic-add-close/demo.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts index 747fcc6253..76c999850a 100644 --- a/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts +++ b/apps/code-examples/src/app/code-examples/tabs/tabs/dynamic-add-close/demo.component.spec.ts @@ -27,7 +27,7 @@ describe('Static tabs demo with add and close', () => { TestBed.configureTestingModule({ imports: [DemoComponent] }); }); - fit('should set up tabs', async () => { + it('should set up tabs', async () => { const { harness } = await setupTest({ dataSkyId: 'tab-demo' }); await harness.clickNewTabButton();