diff --git a/change/@ni-nimble-angular-191b642d-e86c-429e-abca-60e140900a1e.json b/change/@ni-nimble-angular-191b642d-e86c-429e-abca-60e140900a1e.json new file mode 100644 index 0000000000..40d94f5b71 --- /dev/null +++ b/change/@ni-nimble-angular-191b642d-e86c-429e-abca-60e140900a1e.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Export mapping column page object; extend the table page object in Angular to have an async function to wait for data to render when using the `data$` property of the table directive", + "packageName": "@ni/nimble-angular", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@ni-nimble-components-465d704e-4a86-45c9-b5a6-4ccdfe6951b1.json b/change/@ni-nimble-components-465d704e-4a86-45c9-b5a6-4ccdfe6951b1.json new file mode 100644 index 0000000000..809cfe33c2 --- /dev/null +++ b/change/@ni-nimble-components-465d704e-4a86-45c9-b5a6-4ccdfe6951b1.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add function to the table page object for getting the text content of a column header", + "packageName": "@ni/nimble-components", + "email": "20542556+mollykreis@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/angular-workspace/nimble-angular/table-column/mapping/testing/ng-package.json b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/ng-package.json new file mode 100644 index 0000000000..39cd55ac3e --- /dev/null +++ b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../../../../../../node_modules/ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public-api.ts" + } +} diff --git a/packages/angular-workspace/nimble-angular/table-column/mapping/testing/public-api.ts b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/public-api.ts new file mode 100644 index 0000000000..5a4d1b192e --- /dev/null +++ b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/public-api.ts @@ -0,0 +1 @@ +export * from './table-column-mapping.pageobject'; diff --git a/packages/angular-workspace/nimble-angular/table-column/mapping/testing/table-column-mapping.pageobject.ts b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/table-column-mapping.pageobject.ts new file mode 100644 index 0000000000..319034910a --- /dev/null +++ b/packages/angular-workspace/nimble-angular/table-column/mapping/testing/table-column-mapping.pageobject.ts @@ -0,0 +1,3 @@ +import { TableColumnMappingPageObject } from '@ni/nimble-components/dist/esm/table-column/mapping/testing/table-column-mapping.pageobject'; + +export { TableColumnMappingPageObject }; diff --git a/packages/angular-workspace/nimble-angular/table/testing/table.pageobject.ts b/packages/angular-workspace/nimble-angular/table/testing/table.pageobject.ts index aca7614be5..43dc8b2c59 100644 --- a/packages/angular-workspace/nimble-angular/table/testing/table.pageobject.ts +++ b/packages/angular-workspace/nimble-angular/table/testing/table.pageobject.ts @@ -1,3 +1,35 @@ -import { TablePageObject } from '@ni/nimble-components/dist/esm/table/testing/table.pageobject'; +import { TablePageObject as NimbleComponentsTablePageObject } from '@ni/nimble-components/dist/esm/table/testing/table.pageobject'; +import { waitForUpdatesAsync } from '@ni/nimble-angular'; +import type { Table, TableRecord } from '@ni/nimble-angular/table'; -export { TablePageObject }; \ No newline at end of file +/** + * The page object for the `nimble-table` component to provide consistent ways of querying + * and interacting with the component during tests. + * + * This Angular version of the page object extends the nimble-components version to add the ability + * to wait for data updates to be applied to the table since the timing isn't easily observable + * when using the `data$` property. + */ +export class TablePageObject extends NimbleComponentsTablePageObject { + private mostRecentSetDataPromise?: Promise; + + public constructor(tableElement: Table) { + super(tableElement); + + // Cache the most recent promise returned from calls to setData() on the nimble table + // so that we can appropriately wait for them to complete to know when the Angular + // data$ Observable has been applied to the table. + const originalSetDataFn = tableElement.setData.bind(tableElement); + tableElement.setData = async (...args): Promise => { + this.mostRecentSetDataPromise = originalSetDataFn(...args); + return this.mostRecentSetDataPromise; + }; + } + + public async waitForDataUpdatesToRender(): Promise { + if (this.mostRecentSetDataPromise) { + await this.mostRecentSetDataPromise; + } + await waitForUpdatesAsync(); + } +} diff --git a/packages/angular-workspace/nimble-angular/table/testing/tests/table.pageobject.spec.ts b/packages/angular-workspace/nimble-angular/table/testing/tests/table.pageobject.spec.ts new file mode 100644 index 0000000000..28471e92af --- /dev/null +++ b/packages/angular-workspace/nimble-angular/table/testing/tests/table.pageobject.spec.ts @@ -0,0 +1,84 @@ +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Subject } from 'rxjs'; +import { NimbleTableModule, Table, TableRecord } from '@ni/nimble-angular/table'; +import { NimbleTableColumnTextModule } from '@ni/nimble-angular/table-column/text'; +import { TablePageObject } from '../table.pageobject'; + +describe('Table page object', () => { + describe('data updates', () => { + interface SimpleRecord extends TableRecord { + field1: string; + field2: string; + } + + @Component({ + template: ` + + Column 1 + Column 2 + + ` + }) + class TestHostComponent { + @ViewChild('table', { read: ElementRef }) public tableElement: ElementRef>; + public dataSubject = new Subject(); + public data$ = this.dataSubject.asObservable(); + } + + let fixture: ComponentFixture; + let pageObject: TablePageObject; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestHostComponent], + imports: [ + NimbleTableModule, + NimbleTableColumnTextModule + ] + }); + fixture = TestBed.createComponent(TestHostComponent); + fixture.detectChanges(); + + pageObject = new TablePageObject(fixture.componentInstance.tableElement.nativeElement); + }); + + it('can await rendering to be done after emitting a new value to data$ observable', async () => { + expect(pageObject.getRenderedRowCount()).toBe(0); + + const data: SimpleRecord[] = [{ + field1: 'foo', + field2: 'bar' + }]; + fixture.componentInstance.dataSubject.next(data); + expect(pageObject.getRenderedRowCount()).toBe(0); + + await pageObject.waitForDataUpdatesToRender(); + expect(pageObject.getRenderedRowCount()).toBe(1); + }); + + it('can await multiple data updates', async () => { + let data: SimpleRecord[] = [{ + field1: 'foo', + field2: 'bar' + }]; + fixture.componentInstance.dataSubject.next(data); + + await pageObject.waitForDataUpdatesToRender(); + expect(pageObject.getRenderedRowCount()).toBe(1); + expect(pageObject.getRenderedCellTextContent(0, 0)).toBe('foo'); + expect(pageObject.getRenderedCellTextContent(0, 1)).toBe('bar'); + + data = [{ + field1: 'hello', + field2: 'world' + }]; + fixture.componentInstance.dataSubject.next(data); + + await pageObject.waitForDataUpdatesToRender(); + expect(pageObject.getRenderedRowCount()).toBe(1); + expect(pageObject.getRenderedCellTextContent(0, 0)).toBe('hello'); + expect(pageObject.getRenderedCellTextContent(0, 1)).toBe('world'); + }); + }); +}); diff --git a/packages/nimble-components/src/table/testing/table.pageobject.ts b/packages/nimble-components/src/table/testing/table.pageobject.ts index e3a9b1ddd6..c45ee61167 100644 --- a/packages/nimble-components/src/table/testing/table.pageobject.ts +++ b/packages/nimble-components/src/table/testing/table.pageobject.ts @@ -80,6 +80,14 @@ export class TablePageObject { ); } + public getHeaderTextContent(columnIndex: number): string { + return ( + this.getHeaderContent( + columnIndex + )?.firstChild?.textContent?.trim() ?? '' + ); + } + public dispatchEventToHeader( columnIndex: number, event: Event diff --git a/packages/nimble-components/src/table/tests/table.spec.ts b/packages/nimble-components/src/table/tests/table.spec.ts index 037e39798e..6d7562d418 100644 --- a/packages/nimble-components/src/table/tests/table.spec.ts +++ b/packages/nimble-components/src/table/tests/table.spec.ts @@ -195,14 +195,12 @@ describe('Table', () => { await element.setData(simpleTableData); await waitForUpdatesAsync(); - let headerContent = pageObject.getHeaderContent(0)!.firstChild; - expect(headerContent?.textContent).toEqual('stringData'); + expect(pageObject.getHeaderTextContent(0)).toEqual('stringData'); element.columns[0]!.textContent = 'foo'; await waitForUpdatesAsync(); - headerContent = pageObject.getHeaderContent(0)!.firstChild; - expect(headerContent?.textContent).toEqual('foo'); + expect(pageObject.getHeaderTextContent(0)).toEqual('foo'); }); it('sets title when header text is ellipsized', async () => {