UNPKG

@dbg-riskit/angular-testing

Version:

1,304 lines (1,279 loc) 60.1 kB
import '@dbg-riskit/angular-polyfill'; import 'zone.js/testing'; import { getTestBed, tick, discardPeriodicTasks, TestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import * as i0 from '@angular/core'; import { EventEmitter, Injectable, Component, Directive, Input, Inject, NgModule } from '@angular/core'; import { MatMenuTrigger, MatMenuItem } from '@angular/material/menu'; import { By } from '@angular/platform-browser'; import * as i1 from '@dbg-riskit/angular-file'; import { CSVFileDownloadDirective, FileDownloadDirective, FileModule } from '@dbg-riskit/angular-file'; import * as fileSaver from 'file-saver'; import * as i1$2 from '@dbg-riskit/angular-view'; import { RISK_INITIAL_LOAD_SELECTOR, RISK_NO_DATA_SELECTOR, LayoutComponent, NoopAnimationMessageComponent, RISK_GOOD_SELECTOR, RISK_ERROR_SELECTOR, RISK_INFO_SELECTOR, RISK_MESSAGE_SELECTOR, RISK_WARN_SELECTOR, RISK_UPDATE_FAILED_SELECTOR, CommonViewModule, NoopAnimationsCommonViewModule } from '@dbg-riskit/angular-view'; export { LayoutComponent, NoopAnimationMessageComponent, NoopAnimationsCommonViewModule } from '@dbg-riskit/angular-view'; import { throwError, of, timer, EMPTY, BehaviorSubject } from 'rxjs'; import { switchMap, defaultIfEmpty, map } from 'rxjs/operators'; import { MatCard } from '@angular/material/card'; import { MatButton, MatAnchor } from '@angular/material/button'; import { MatButtonToggle } from '@angular/material/button-toggle'; import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { secureRandom, globalScope } from '@dbg-riskit/common'; import * as i1$1 from '@dbg-riskit/angular-datatable'; import { PagingComponent, DataTableRowDetailExpanderComponent, HIGHLIGHTER_CLASS, DataTableComponent, HighlighterDirective, DataTableModule } from '@dbg-riskit/angular-datatable'; import { MatSidenavContainer, MatSidenav } from '@angular/material/sidenav'; import { MatToolbar } from '@angular/material/toolbar'; import { Router, NavigationEnd, UrlSegmentGroup, UrlSegment, ActivatedRoute, RouterModule } from '@angular/router'; import * as i1$3 from '@dbg-riskit/angular-auth'; import { AuthRoutingFlowService, AUTH_CONFIG, AuthService } from '@dbg-riskit/angular-auth'; import { AUTH_PROVIDER } from '@dbg-riskit/angular-common'; // Has to be first in this order const COMPILE_TIMEOUT_INTERVAL = Math.pow(2, 31) - 1; function initTestEnvironment() { Error.stackTraceLimit = 10; jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; // TODO: Quick fix for memory leaks window.addEventListener = () => { return; }; window.document.addEventListener = () => { return; }; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: false } }); } /** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */ const BUTTON_CLICK_EVENTS = { left: { button: 0 }, right: { button: 2 } }; /** Simulate element click. Defaults to mouse left-button click event. */ function click(el, eventObj = BUTTON_CLICK_EVENTS.left) { if (el instanceof HTMLElement) { el.click(); } else { el.triggerEventHandler('click', eventObj); } } function setNgModelValue(element, value, realAsync = false) { if (!(element.nativeElement instanceof HTMLInputElement)) { throw new Error('Not an instance of HTMLInputElement'); } const input = element.nativeElement; input.value = value; dispatchEvent(input, 'input'); // tell Angular if (!realAsync) { tick(); } } function setNgModelSelectValue(element, selectedIndex, realAsync = false) { if (!(element.nativeElement instanceof HTMLSelectElement)) { throw new Error('Not an instance of HTMLInputElement'); } const input = element.nativeElement; input.selectedIndex = selectedIndex; dispatchEvent(input, 'change'); // tell Angular if (!realAsync) { tick(); } } function dispatchEvent(element, eventName) { if (element instanceof HTMLElement) { element.dispatchEvent(newEvent(eventName)); } else if (element instanceof Window) { element.dispatchEvent(newEvent(eventName)); } else { element.nativeElement.dispatchEvent(newEvent(eventName)); } } /** * Create custom DOM event the old fashioned way * * https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent * Although officially deprecated, some browsers (phantom) don't accept the preferred "new Event(eventName)" */ function newEvent(eventName, bubbles = false, cancelable = false) { const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent' evt.initCustomEvent(eventName, bubbles, cancelable, null); return evt; } const FAKE_HTTP_ASYNC_TIMEOUT = 1000; class HttpServiceStub { constructor() { this.value = []; this.error = []; this.unauthorized = new EventEmitter(); } returnValue(value) { this.value.push(value); } popReturnValue() { return this.value.pop(); } shiftReturnValue() { return this.value.shift(); } throwError(value) { this.error.push(value); } get(request) { if (this.error.length) { const error = this.error.shift(); return throwError(error); } const value = this.value.shift(); return of(value); } post(request) { return this.get(request); } } HttpServiceStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpServiceStub, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); HttpServiceStub.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpServiceStub }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpServiceStub, decorators: [{ type: Injectable }] }); class HttpAsyncServiceStub extends HttpServiceStub { get(request, auth = true) { return timer(FAKE_HTTP_ASYNC_TIMEOUT).pipe(switchMap(() => super.get(request))); } post(request) { return this.get(request); } } HttpAsyncServiceStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpAsyncServiceStub, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); HttpAsyncServiceStub.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpAsyncServiceStub }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HttpAsyncServiceStub, decorators: [{ type: Injectable }] }); class MessageComponentDef { constructor(debugElement) { this.debugElement = debugElement; if (debugElement == null) { throw new Error('Debug element not found!'); } } get text() { return this.debugElement.query(By.directive(MatCard)).nativeElement.textContent.replace(/\n\s*/g, ' ') .replace(/\r\s*/g, ' ').trim(); } } class Page { constructor(fixture) { this.fixture = fixture; this._timeOffset = 0; this.debugElement = fixture.debugElement; this.component = this.debugElement.componentInstance; } detectChanges(millis = 0) { this.fixture.detectChanges(); tick(millis); this._timeOffset += millis; } advanceAndDetectChanges(millis = 0) { tick(millis); this._timeOffset += millis; this.detectChanges(); } advanceHTTP() { this.advanceAndDetectChanges(FAKE_HTTP_ASYNC_TIMEOUT); } advanceAndDetectChangesUsingOffset(millis) { this.advanceAndDetectChanges(millis - this._timeOffset); this.resetTimeOffset(); } resetTimeOffset() { this._timeOffset = 0; } destroy() { this.fixture.destroy(); try { // Move a lot into fututre ;) tick(60 * 60 * 1000); discardPeriodicTasks(); } catch (ignore) { // Nothing to do... } } } class PageWithLoading extends Page { constructor(fixture) { super(fixture); } get initialLoadComponent() { const element = this.debugElement.query(By.css(RISK_INITIAL_LOAD_SELECTOR)); if (element) { return new MessageComponentDef(element); } return null; } get noDataComponent() { const element = this.debugElement.query(By.css(RISK_NO_DATA_SELECTOR)); if (element) { return new MessageComponentDef(element); } return null; } } class CSVDownloadMenuPage extends Page { constructor(fixture) { super(fixture); } get downloadWindowsLink() { // Open the menu first click(this.debugElement.query(By.directive(MatMenuTrigger))); this.detectChanges(500); return new DownloadLink(this.debugElement.queryAll(By.directive(MatMenuItem))[0], this); } get downloadUnixLink() { // Open the menu first click(this.debugElement.query(By.directive(MatMenuTrigger))); this.detectChanges(500); return new DownloadLink(this.debugElement.queryAll(By.directive(MatMenuItem))[1], this); } } class DownloadLink { constructor(element, page) { this.element = element; this.page = page; } click() { this.setupBlobConstructorSpy(); this.setupSaveBlobSpy(); click(this.element); this.page.detectChanges(); } get blobSpy() { this.setupBlobConstructorSpy(); return this._blobSpy; } setupBlobConstructorSpy() { if (!this._blobSpy) { let downloadDirective; try { downloadDirective = this.element.injector.get(CSVFileDownloadDirective); } catch (_) { downloadDirective = this.element.injector.get(FileDownloadDirective); } this._blobSpy = spyOn(downloadDirective, 'createBlob').and.callThrough(); } } get saveSpy() { this.setupSaveBlobSpy(); return this._saveBlobSpy; } setupSaveBlobSpy() { if (!this._saveBlobSpy) { this._saveBlobSpy = spyOn(fileSaver, 'saveAs'); } } } class DownloadTestComponent { } DownloadTestComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: DownloadTestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); DownloadTestComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: DownloadTestComponent, selector: "ng-component", ngImport: i0, template: ` <a [risk-download]="data" [risk-download-content-type]="contentType" [risk-download-filename]="filename">Download</a> `, isInline: true, directives: [{ type: i1.FileDownloadDirective, selector: "[risk-download]", inputs: ["risk-download", "risk-download-content-type", "risk-download-filename"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: DownloadTestComponent, decorators: [{ type: Component, args: [{ template: ` <a [risk-download]="data" [risk-download-content-type]="contentType" [risk-download-filename]="filename">Download</a> ` }] }] }); class DownloadTestComponentPage extends Page { constructor(fixture) { super(fixture); } get downloadLink() { return new DownloadLink(this.debugElement.query(By.directive(FileDownloadDirective)), this); } } class DataTableDefinition { constructor(debugElement, page) { this.debugElement = debugElement; this.page = page; } get component() { return this.debugElement.componentInstance; } get data() { return this.component.plainData; } get element() { return this.debugElement.query(By.css('.risk-data-table-wrapper > table')); } get header() { return new TableHeader(this.debugElement.query((de) => de.references.mainHeader), this.page); } get sorting() { return new TableSorting(this, this.page); } get body() { return new TableBody(this.debugElement.query((de) => de.references.mainBody), this.page); } get footer() { return new TableFooter(this.debugElement.query((de) => de.references.mainFooter)); } get recordsCount() { return new RecordsCount(this.debugElement.query(By.css('.risk-data-table-page-count'))); } get pager() { return new Pager(this.debugElement.query(By.directive(PagingComponent)), this.page); } } // <editor-fold defaultstate="collapsed" desc="Table header"> class TableHeader { constructor(element, page) { this.element = element; this.page = page; } get rows() { return this.element.queryAll(By.css('tr')).map((element) => { return new TableHeaderRow(element, this.page); }); } get cells() { return this.element.queryAll(By.css('th')).map((element) => { return new TableHeaderCell(element, this.page); }); } } class TableHeaderRow { constructor(element, page) { this.element = element; this.page = page; } get cells() { return this.element.queryAll(By.css('th')).map((element) => { return new TableHeaderCell(element, this.page); }); } } class TableHeaderCell { constructor(element, page) { this.element = element; this.page = page; } get sortingHandle() { const handle = this.element.query(By.directive(MatButton)); if (handle) { return new SortingHandle(this.page, handle); } return null; } get tooltip() { const handle = this.element.query(By.directive(MatTooltip)); if (handle) { return handle.injector.get(MatTooltip).message; } return null; } get title() { const textNode = this.element.childNodes.find((node) => node.nativeNode.nodeType === Node.TEXT_NODE); if (textNode != null) { return textNode .nativeNode.textContent.trim(); } return ''; } get colspan() { return this.element.nativeElement.colspan; } get rowspan() { return this.element.nativeElement.rowspan; } } // <editor-fold defaultstate="collapsed" desc="Sorting"> class TableSorting { constructor(table, page) { this.table = table; this.page = page; } get handles() { const handles = this.table.debugElement.query((de) => de.references.mainHeader) .queryAll(By.directive(MatButton)); if (!handles) { return []; } return handles.map((handle) => { return new SortingHandle(this.page, handle); }); } get detailRowHandles() { const handles = this.table.debugElement.query(By.css('.risk-data-table-detail')).query(By.css('thead')) .queryAll(By.directive(MatButton)); if (!handles) { return null; } return handles.map((handle) => { return new SortingHandle(this.page, handle); }); } get currentOrdering() { return this.table.component.ordering; } checkSorting(firstNRows = this.table.component.rows.length, criterium) { // WARN: call data once as it calls .map on all table rows const data = this.table.data; let ordering; if (criterium) { ordering = [criterium].concat(this.table.component._defaultOrdering); } else { ordering = this.currentOrdering; } for (let i = 1; i < Math.min(data.length, firstNRows); i++) { ordering.some((criteria) => { //noinspection EqualityComparisonWithCoercionJS const valueA = criteria.get(data[i - 1]); const valueB = criteria.get(data[i]); if (valueA == null && valueB == null) { return false; } expect(valueA).not.toBeNull(); expect(valueA).not.toBeUndefined(); if (valueB != null) { if (criteria.descending) { expect(valueA >= valueB) .toBeTruthy('Expect: ' + valueA + ' >= ' + valueB); } else { expect(valueA <= valueB) .toBeTruthy('Expect: ' + valueA + ' <= ' + valueB); } } return valueA !== valueB; }); } } } class SortingHandle { constructor(page, handle) { this.page = page; this.handle = handle; } click() { click(this.handle); this.page.detectChanges(); } } // </editor-fold> // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Table body"> class TableBody { constructor(element, page) { this.element = element; this.page = page; } get rows() { return this.element.queryAll((de) => de.references.masterRow).map((element) => { return new TableBodyRow(element, this.page); }); } get cells() { let cells = []; this.element.queryAll((de) => de.references.masterRow).forEach((row) => { cells = cells.concat(row.queryAll(By.css('td')).map((cell) => { return new TableBodyCell(cell); })); }); return cells; } } class TableBodyRow { constructor(element, page) { this.element = element; this.page = page; } expandRow() { click(this.element); this.page.detectChanges(); } get expander() { return new RowExpander(this.element.query(By.directive(DataTableRowDetailExpanderComponent)).query(By.directive(MatAnchor))); } get cells() { return this.element.queryAll(By.css('td')).map((element) => { return new TableBodyCell(element); }); } get rowDetail() { const parent = this.element.parent; if (parent != null) { const next = parent.children[parent.children.indexOf(this.element) + 1]; if (next && !next.references.masterRow) { return new TableBodyDetail(next, this.page); } } return null; } get highlighted() { return this.element.nativeElement.classList.contains(HIGHLIGHTER_CLASS); } } class RowExpander { constructor(element) { this.element = element; } get icon() { return this.element.query(By.directive(MatIcon)).nativeElement.textContent.trim(); } get opened() { return this.icon === 'expand_less'; } get closed() { return this.icon === 'expand_more'; } } class TableBodyCell { constructor(element) { this.element = element; } get colspan() { return this.element.nativeElement.colspan; } get rowspan() { return this.element.nativeElement.rowspan; } } // <editor-fold defaultstate="collapsed" desc="Row detail"> class TableBodyDetail { constructor(element, page) { this.element = element; this.page = page; } header() { return new TableHeader(this.element.query(By.css('thead')), this.page); } get body() { return new TableBodyDetailBody(this.element.query(By.css('tbody'))); } get highlighted() { return this.element.nativeElement.classList.contains(HIGHLIGHTER_CLASS); } get colspan() { return this.element.children[0].nativeElement.colspan; } } class TableBodyDetailBody { constructor(element) { this.element = element; } get rows() { return this.element.queryAll(By.css('tr')).map((element) => { return new TableBodyDetailRow(element); }); } get cells() { let cells = []; this.element.queryAll(By.css('tr')).forEach((row) => { cells = cells.concat(row.queryAll(By.css('td')).map((cell) => { return new TableBodyCell(cell); })); }); return cells; } } class TableBodyDetailRow { constructor(element) { this.element = element; } get cells() { return this.element.queryAll(By.css('td')).map((element) => { return new TableBodyCell(element); }); } } // </editor-fold> // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Table footer"> class TableFooter { constructor(element) { this.element = element; } get rows() { return this.element.queryAll(By.css('tr')).map((element) => { return new TableFooterRow(element); }); } get cells() { let cells = []; this.element.queryAll(By.css('tr')).forEach((row) => { cells = cells.concat(row.queryAll(By.css('th')).map((cell) => { return new TableBodyCell(cell); })); }); return cells; } } class TableFooterRow { constructor(element) { this.element = element; } get cells() { return this.element.queryAll(By.css('th')).map((element) => { return new TableBodyCell(element); }); } } // </editor-fold> class RecordsCount { constructor(element) { this.element = element; } get message() { return this.element.nativeElement.textContent; } } class Pager { constructor(element, page) { this.element = element; this.page = page; } get pageButtons() { return this.element.queryAll(By.directive(MatButtonToggle)); } expectLeadingButtonsDisabled() { for (let i = 0; i < 2; i++) { expect(this.pageButtons[i].classes['mat-button-toggle-disabled']) .toBe(true, 'First two are disabled.'); } } expectLeadingButtonsNotDisabled() { for (let i = 0; i < 2; i++) { expect(this.pageButtons[i].classes['mat-button-toggle-disabled']) .not.toBe(true, 'First two are not disabled.'); } } expectTrailingButtonsDisabled() { for (let i = this.pageButtons.length - 1; i > this.pageButtons.length - 3; i--) { expect(this.pageButtons[i].classes['mat-button-toggle-disabled']) .toBe(true, 'Last two are disabled.'); } } expectTrailingButtonsNotDisabled() { for (let i = this.pageButtons.length - 1; i > this.pageButtons.length - 3; i--) { expect(this.pageButtons[i].classes['mat-button-toggle-disabled']) .not.toBe(true, 'Last two are not disabled.'); } } expectButtonNumbers(numbers) { for (let i = 0; i < numbers.length; i++) { expect(this.pageButtons[i + 2].query(By.css('.mat-button-toggle-label-content')) .nativeElement.textContent.trim()) .toEqual(numbers[i] + '', 'Button numbers are correct'); } } expectButtonActive(index) { expect(this.pageButtons[index].classes['mat-button-toggle-checked']) .toBe(true, 'Button is active.'); } click(index) { click(this.pageButtons[index].query(By.css('.mat-button-toggle-label-content')).nativeElement); this.page.detectChanges(); this.page.advanceAndDetectChanges(); } } function chceckSorting(page, criteria) { page.dataTable.sorting.checkSorting(150); page.dataTable.sorting.handles.forEach((handle, index) => { // Tigger sort based on a handle handle.click(); page.detectChanges(); // Check the sorting page.dataTable.sorting.checkSorting(150, { get: criteria[index] }); // Tigger sort based on a handle handle.click(); page.detectChanges(); // Check the sorting page.dataTable.sorting.checkSorting(150, { get: criteria[index], descending: true }); }); } class DataTableDefinitionHosted extends Page { constructor(fixture) { super(fixture); } get dataTable() { return new DataTableDefinition(this.debugElement.query(By.directive(DataTableComponent)), this); } } class TestDataTableHostComponent { constructor() { this.data = []; for (let i = 0; i < 500; i++) { this.data.push({ value1: Math.floor(secureRandom() * 20) + ' - value 1', value2: Math.floor(secureRandom() * 20) + ' - value 2', value3: Math.floor(secureRandom() * 20) + ' - value 3' }); } this.footer = this.data[0]; } get defaultOrdering() { return [ { get: (record) => { return record.value3; }, descending: true }, (record) => { return record.value2; } ]; } get valueGetter() { return (record) => { return record.value1; }; } } TestDataTableHostComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestDataTableHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); TestDataTableHostComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: TestDataTableHostComponent, selector: "ng-component", ngImport: i0, template: ` <risk-data-table [data]="data" [footer]="footer" [pageSize]="20" [defaultOrdering]="defaultOrdering" [striped]="true"> <risk-data-table-column title="Test Column 1" [sortingKey]="valueGetter"> <ng-template let-record="row" risk-data-table-cell> {{record.value1}} </ng-template> </risk-data-table-column> <risk-data-table-column> <ng-template risk-data-table-cell let-record="row" let-expanded="expanded"> <risk-data-table-detail-expander [expanded]="expanded"></risk-data-table-detail-expander> </ng-template> <ng-template risk-data-table-footer-cell let-footer="footer"> {{footer.value1}} </ng-template> </risk-data-table-column> <!-- Sub detail --> <risk-data-table-detail-row> <risk-data-table-column-group> <risk-data-table-column title="Test Detail Column 1" [sortingKey]="valueGetter"> <ng-template risk-data-table-cell let-record="row"> {{record.value1}} </ng-template> </risk-data-table-column> </risk-data-table-column-group> <risk-data-table-column-group> <risk-data-table-column title="Test Detail Column 2"> <ng-template risk-data-table-cell let-record="row"> {{record.value2}} </ng-template> </risk-data-table-column> <risk-data-table-column title="Test Detail Column 3"> <ng-template risk-data-table-cell let-record="row"> {{record.value3}} </ng-template> </risk-data-table-column> </risk-data-table-column-group> <risk-data-table-column-group></risk-data-table-column-group> </risk-data-table-detail-row> </risk-data-table>`, isInline: true, components: [{ type: i1$1.DataTableComponent, selector: "risk-data-table", inputs: ["footer", "pageSize", "striped", "showFooter", "allowEmpty", "trackByRowKey", "highlighting", "stickyHeader", "stickyHeaderOffsetTopPx", "data", "defaultOrdering"], exportAs: ["dataTable"] }, { type: i1$1.DataTableRowDetailExpanderComponent, selector: "risk-data-table-detail-expander", inputs: ["expanded"] }], directives: [{ type: i1$1.ɵDataTableColumnDirective, selector: "risk-data-table-column", inputs: ["title", "sortingKey", "tooltip", "contentAlign", "headerAlign", "footerAlign", "class"] }, { type: i1$1.ɵDataTableColumnCellDirective, selector: "[risk-data-table-cell]" }, { type: i1$1.ɵDataTableColumnFooterDirective, selector: "[risk-data-table-footer-cell]" }, { type: i1$1.ɵDataTableRowDetailDirective, selector: "risk-data-table-detail-row" }, { type: i1$1.ɵDataTableColumnGroupDirective, selector: "risk-data-table-column-group" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestDataTableHostComponent, decorators: [{ type: Component, args: [{ template: ` <risk-data-table [data]="data" [footer]="footer" [pageSize]="20" [defaultOrdering]="defaultOrdering" [striped]="true"> <risk-data-table-column title="Test Column 1" [sortingKey]="valueGetter"> <ng-template let-record="row" risk-data-table-cell> {{record.value1}} </ng-template> </risk-data-table-column> <risk-data-table-column> <ng-template risk-data-table-cell let-record="row" let-expanded="expanded"> <risk-data-table-detail-expander [expanded]="expanded"></risk-data-table-detail-expander> </ng-template> <ng-template risk-data-table-footer-cell let-footer="footer"> {{footer.value1}} </ng-template> </risk-data-table-column> <!-- Sub detail --> <risk-data-table-detail-row> <risk-data-table-column-group> <risk-data-table-column title="Test Detail Column 1" [sortingKey]="valueGetter"> <ng-template risk-data-table-cell let-record="row"> {{record.value1}} </ng-template> </risk-data-table-column> </risk-data-table-column-group> <risk-data-table-column-group> <risk-data-table-column title="Test Detail Column 2"> <ng-template risk-data-table-cell let-record="row"> {{record.value2}} </ng-template> </risk-data-table-column> <risk-data-table-column title="Test Detail Column 3"> <ng-template risk-data-table-cell let-record="row"> {{record.value3}} </ng-template> </risk-data-table-column> </risk-data-table-column-group> <risk-data-table-column-group></risk-data-table-column-group> </risk-data-table-detail-row> </risk-data-table>` }] }], ctorParameters: function () { return []; } }); class HighLighterDirectiveTestComponent { trackBy(index, row) { return row.rowData; } } HighLighterDirectiveTestComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HighLighterDirectiveTestComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); HighLighterDirectiveTestComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: HighLighterDirectiveTestComponent, selector: "ng-component", ngImport: i0, template: ` <div [risk-data-table-highlighter]="trackBy" [risk-data-table-highlighter-context]="context"></div>`, isInline: true, directives: [{ type: i1$1.HighlighterDirective, selector: "[risk-data-table-highlighter]", inputs: ["risk-data-table-highlighter", "risk-data-table-highlighter-context"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: HighLighterDirectiveTestComponent, decorators: [{ type: Component, args: [{ template: ` <div [risk-data-table-highlighter]="trackBy" [risk-data-table-highlighter-context]="context"></div>` }] }] }); class HighLighterDirectivePage extends Page { constructor(fixture) { super(fixture); } get highlightedElement() { return this.debugElement.query(By.directive(HighlighterDirective)); } get classList() { return this.highlightedElement.nativeElement.classList; } get highlighter() { return this.highlightedElement.injector.get(HighlighterDirective); } } // @dynamic class ByUtil { static and(...predicates) { return (val) => { return predicates.every((predicate) => predicate(val)); }; } static or(...predicates) { return (val) => { return predicates.some((predicate) => predicate(val)); }; } static not(predicate) { return (val) => { return !predicate(val); }; } } class LayoutComponentDefinition { constructor(debugElement, page) { this.debugElement = debugElement; this.page = page; } get component() { return this.debugElement.componentInstance; } get headToolbar() { return this.debugElement.query(ByUtil.and(By.directive(MatToolbar), By.css('.mat-elevation-z2'))); } get logo() { return this.headToolbar.query(By.css('.risk-layout-logo')); } get menu() { return this.headToolbar.queryAll(ByUtil.or(By.css('[menu-horizontal]'), By.css('risk-layout-horizontal'))); } get sideNavContainer() { return this.debugElement.query(By.directive(MatSidenavContainer)); } get sideNav() { return this.sideNavContainer.query(By.directive(MatSidenav)); } openSideNav() { this.sideNav.componentInstance.open(); this.page.advanceAndDetectChanges(); } closeSideNav() { this.sideNav.componentInstance.close(); this.page.advanceAndDetectChanges(1); } get sideNavMenu() { return this.sideNav.queryAll(ByUtil.or(By.css('[menu-vertical]'), By.css('risk-layout-vertical'))); } get content() { return this.sideNavContainer.query(By.css('.risk-layout-content')); } } class TestLayoutComponentHostPage extends Page { get layoutComponent() { return new LayoutComponentDefinition(this.debugElement.query(By.directive(LayoutComponent)), this); } } class TestLayoutHostComponent { } TestLayoutHostComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestLayoutHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); TestLayoutHostComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: TestLayoutHostComponent, selector: "ng-component", ngImport: i0, template: ` <risk-layout> <!-- menu-horizontal --> <risk-layout-horizontal> HorizontalMenu </risk-layout-horizontal> <!-- menu-horizontal --> <!-- menu-vertical --> <risk-layout-vertical> Vertical menu </risk-layout-vertical> <span>Content</span> </risk-layout> `, isInline: true, components: [{ type: i1$2.LayoutComponent, selector: "risk-layout", inputs: ["smallScreenMenuVisible", "smallScreenWidth", "footerVisible", "toolbarBackgroundColor", "backgroundColor"] }], directives: [{ type: i1$2.HorizontalLayoutDirective, selector: "risk-layout-horizontal" }, { type: i1$2.VerticalLayoutDirective, selector: "risk-layout-vertical" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestLayoutHostComponent, decorators: [{ type: Component, args: [{ template: ` <risk-layout> <!-- menu-horizontal --> <risk-layout-horizontal> HorizontalMenu </risk-layout-horizontal> <!-- menu-horizontal --> <!-- menu-vertical --> <risk-layout-vertical> Vertical menu </risk-layout-vertical> <span>Content</span> </risk-layout> ` }] }] }); class RouterLinkStubDirective { constructor(injector) { this.navigatedTo = null; this._urlTree = null; this.routerStub = injector.get(Router, null); } ngOnChanges() { if (this.linkParams && this.routerStub) { this._urlTree = this.routerStub.getURLTree(this.linkParams); } } onClick() { this.navigatedTo = this.linkParams; if (this.routerStub) { if (Array.isArray(this.navigatedTo)) { this.routerStub.navigate(this.navigatedTo); } else { this.routerStub.navigateByUrl(this.navigatedTo); } } } get urlTree() { return this._urlTree; } } RouterLinkStubDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: RouterLinkStubDirective, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive }); RouterLinkStubDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.6", type: RouterLinkStubDirective, selector: "[routerLink]", inputs: { linkParams: ["routerLink", "linkParams"] }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: RouterLinkStubDirective, decorators: [{ type: Directive, args: [{ /* eslint-disable @angular-eslint/directive-selector */ selector: '[routerLink]', /* eslint-enable */ host: { '(click)': 'onClick()' } }] }], ctorParameters: function () { return [{ type: i0.Injector }]; }, propDecorators: { linkParams: [{ type: Input, args: ['routerLink'] }] } }); class LinkDefinition { constructor(page, link) { this.page = page; this.link = link; } get stub() { return this.link.injector.get(RouterLinkStubDirective); } get text() { return this.link.nativeElement.textContent.trim(); } click() { click(this.link.nativeElement); this.page.advanceAndDetectChanges(); } } class LinkOnlyPage extends Page { constructor(fixture) { super(fixture); } get link() { return new LinkDefinition(this, this.debugElement.query(By.directive(RouterLinkStubDirective))); } } class LoginMenuPage extends Page { get menuTrigger() { return this.debugElement.query(By.directive(MatMenuTrigger)); } clickMenuTrigger() { click(this.menuTrigger); this.waitForMenu(); } waitForMenu() { this.detectChanges(500); } get loginLink() { return new LinkDefinition(this, this.debugElement.query(ByUtil.and(By.directive(MatMenuItem), (value) => value.nativeElement.textContent.trim().endsWith('Login')))); } get logoutLink() { return new LinkDefinition(this, this.debugElement.query(ByUtil.and(By.directive(MatMenuItem), (value) => value.nativeElement.textContent.trim().endsWith('Logout')))); } } class LoginPage extends Page { constructor(fixture) { super(fixture); } get formElement() { return this.debugElement.query(By.css('form')); } get usernameElement() { return this.formElement.query(By.css('input[name=username]')); } set username(username) { setNgModelValue(this.usernameElement, username); } get passwordElement() { return this.formElement.query(By.css('input[name=password]')); } set password(password) { setNgModelValue(this.passwordElement, password); } get loginButtonElement() { return this.formElement.query(By.directive(MatButton)); } get successMessage() { const debugElement = this.debugElement.query(ByUtil.and(By.directive(NoopAnimationMessageComponent), By.css(RISK_GOOD_SELECTOR))); if (!debugElement) { return null; } return new MessageComponentDef(debugElement); } get errorMessage() { const debugElement = this.debugElement.query(ByUtil.or(ByUtil.and(By.directive(NoopAnimationMessageComponent), By.css(RISK_ERROR_SELECTOR)), By.css('h3'))); if (!debugElement) { return null; } return new MessageComponentDef(debugElement); } clickLogin() { click(this.loginButtonElement.nativeElement); tick(); this.detectChanges(); } } class TestMessageHostComponent { constructor() { this.message = 'custom message'; } } TestMessageHostComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestMessageHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); TestMessageHostComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: TestMessageHostComponent, selector: "ng-component", ngImport: i0, template: ` <risk-error [message]="message"></risk-error> <risk-good [message]="message"></risk-good> <risk-info [message]="message"></risk-info> <risk-message [message]="message"></risk-message> <risk-warn [message]="message"></risk-warn> <risk-initial-load [message]="message"></risk-initial-load> <risk-update-failed [message]="message"></risk-update-failed> <risk-no-data [message]="message"></risk-no-data> `, isInline: true, components: [{ type: i1$2.MessageComponent, selector: "risk-error, risk-good, risk-info, risk-message, risk-warn, risk-initial-load, risk-no-data, risk-update-failed", inputs: ["message"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: TestMessageHostComponent, decorators: [{ type: Component, args: [{ template: ` <risk-error [message]="message"></risk-error> <risk-good [message]="message"></risk-good> <risk-info [message]="message"></risk-info> <risk-message [message]="message"></risk-message> <risk-warn [message]="message"></risk-warn> <risk-initial-load [message]="message"></risk-initial-load> <risk-update-failed [message]="message"></risk-update-failed> <risk-no-data [message]="message"></risk-no-data> ` }] }] }); class MessageHostedPage extends Page { constructor(fixture) { super(fixture); } get error() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_ERROR_SELECTOR))); } get good() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_GOOD_SELECTOR))); } get info() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_INFO_SELECTOR))); } get message() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_MESSAGE_SELECTOR))); } get warn() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_WARN_SELECTOR))); } get initialLoad() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_INITIAL_LOAD_SELECTOR))); } get noData() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_NO_DATA_SELECTOR))); } get updateFailed() { return new MessageComponentDef(this.debugElement.query(By.css(RISK_UPDATE_FAILED_SELECTOR))); } } const storage = { authRequestedPath: null }; class AuthRoutingFlowServiceStub extends AuthRoutingFlowService { constructor(authServiceStub, authConfig) { super(null, null, { loggedIn: of(null) }, storage, authConfig, null); this.authServiceStub = authServiceStub; // cleanup storage.authRequestedPath = null; } logout(state) { return this.authServiceStub.logout().pipe(defaultIfEmpty(0), map(() => true)); } login(username, password) { return this.authServiceStub.directLogin(username, password); } loginViaService() { return this.authServiceStub.loginViaAuthService(); } } AuthRoutingFlowServiceStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthRoutingFlowServiceStub, deps: [{ token: AUTH_PROVIDER }, { token: AUTH_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); AuthRoutingFlowServiceStub.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthRoutingFlowServiceStub }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthRoutingFlowServiceStub, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1$3.AuthService, decorators: [{ type: Inject, args: [AUTH_PROVIDER] }] }, { type: undefined, decorators: [{ type: Inject, args: [AUTH_CONFIG] }] }]; } }); const WELL_KNOWN = { endpoints: { auth: '/auth', token: '/token', logout: '/logout' }, issuer: 'risk-auth' }; class WellKnownServiceStub { get wellKnown() { return of(WELL_KNOWN); } } WellKnownServiceStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: WellKnownServiceStub, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); WellKnownServiceStub.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: WellKnownServiceStub }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: WellKnownServiceStub, decorators: [{ type: Injectable }] }); class AuthServiceStub extends AuthService { constructor() { super({}, new WellKnownServiceStub(), null, null, null); } get loggedIn() { return of(!!this.user); } get userProfile() { return of({ name: this.user }); } loginViaAuthService() { return of(true); } checkLocationForLoginData() { return of(true); } directLogin(username, password) { this.user = username; this.emitLoginStatusChange(true); return of(true); } logout() { this.emitLoginStatusChange(false); delete this.user; return EMPTY; } } AuthServiceStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthServiceStub, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); AuthServiceStub.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthServiceStub }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: AuthServiceStub, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); class LoginMenuStubComponent { constructor() { this.orientation = 'row'; } } LoginMenuStubComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: LoginMenuStubComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); LoginMenuStubComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.6", type: LoginMenuStubComponent, selector: "login-menu, risk-login-menu", inputs: { orientation: "orientation" }, ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: LoginMenuStubComponent, decorators: [{ type: Component, args: [{ selector: 'login-menu, risk-login-menu', template: '' }] }], propDecorators: { orientation: [{ type: Input }] } }); class ActivatedRouteStub { constructor() { // Test parameters this._testParams = {}; // ActivatedRoute.params is Observable this.subject = new BehaviorSubject(this.testParams); this.params = this.subject.asObservable(); } get testParams() { return this._testParams; } set testParams(params) { this._testParams = params; this.subject.next(params); } // ActivatedRoute.snapshot.params get snapshot() { return { params: this.testParams }; } } ActivatedRouteStub.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.6", ngImport: i0, type: ActivatedRouteStub, deps: [], target: i0.ɵɵFactoryTarget.Inj