@dbg-riskit/angular-testing
Version:
1 lines • 107 kB
Source Map (JSON)
{"version":3,"file":"dbg-riskit-angular-testing.mjs","sources":["../../../../pkg/dbg-riskit/angular-testing/src/lib/environment.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/events.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/http.service.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/message.def.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/page.base.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/download.menu.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/data.table.definition.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/highlighter.directive.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/by.util.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/layout.component.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/router/router.link.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/link.definition.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/link.only.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/login.menu.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/login.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/definitions/message.page.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/auth/auth.routing.flow.service.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/auth/well.known.service.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/auth/auth.service.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/login.menu.stub.component.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/router/activated.route.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/router/router.outlet.stub.component.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/router/router.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/stubs/router/router.module.stub.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/utils.ts","../../../../pkg/dbg-riskit/angular-testing/src/lib/testing.module.ts","../../../../pkg/dbg-riskit/angular-testing/src/public_api.ts","../../../../pkg/dbg-riskit/angular-testing/src/dbg-riskit-angular-testing.ts"],"sourcesContent":["// Has to be first in this order\nimport '@dbg-riskit/angular-polyfill';\nimport 'zone.js/testing';\n\n// Other modules follow\nimport {getTestBed} from '@angular/core/testing';\nimport {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';\n\nexport const COMPILE_TIMEOUT_INTERVAL = Math.pow(2, 31) - 1;\n\nexport function initTestEnvironment() {\n Error.stackTraceLimit = 10;\n\n jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;\n\n // TODO: Quick fix for memory leaks\n window.addEventListener = () => {\n return;\n };\n window.document.addEventListener = () => {\n return;\n };\n\n // First, initialize the Angular testing environment.\n getTestBed().initTestEnvironment(\n BrowserDynamicTestingModule,\n platformBrowserDynamicTesting(), {\n teardown: {destroyAfterEach: false}\n }\n );\n}\n","import {DebugElement} from '@angular/core';\n\nimport {tick} from '@angular/core/testing';\n\n/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */\nexport const BUTTON_CLICK_EVENTS = {\n left : {button: 0},\n right: {button: 2}\n};\n\n/** Simulate element click. Defaults to mouse left-button click event. */\nexport function click(el: DebugElement | HTMLElement, eventObj: any = BUTTON_CLICK_EVENTS.left): void {\n if (el instanceof HTMLElement) {\n el.click();\n } else {\n el.triggerEventHandler('click', eventObj);\n }\n}\n\nexport function setNgModelValue(element: DebugElement, value: string, realAsync = false): void {\n if (!(element.nativeElement instanceof HTMLInputElement)) {\n throw new Error('Not an instance of HTMLInputElement');\n }\n const input: HTMLInputElement = element.nativeElement;\n input.value = value;\n\n dispatchEvent(input, 'input'); // tell Angular\n if (!realAsync) {\n tick();\n }\n}\n\nexport function setNgModelSelectValue(element: DebugElement, selectedIndex: number, realAsync = false): void {\n if (!(element.nativeElement instanceof HTMLSelectElement)) {\n throw new Error('Not an instance of HTMLInputElement');\n }\n const input: HTMLSelectElement = element.nativeElement;\n input.selectedIndex = selectedIndex;\n\n dispatchEvent(input, 'change'); // tell Angular\n if (!realAsync) {\n tick();\n }\n}\n\nexport function dispatchEvent(element: DebugElement | HTMLElement | Window, eventName: string): void {\n if (element instanceof HTMLElement) {\n element.dispatchEvent(newEvent(eventName));\n } else if (element instanceof Window) {\n element.dispatchEvent(newEvent(eventName));\n } else {\n element.nativeElement.dispatchEvent(newEvent(eventName));\n }\n}\n\n/**\n * Create custom DOM event the old fashioned way\n *\n * https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent\n * Although officially deprecated, some browsers (phantom) don't accept the preferred \"new Event(eventName)\"\n */\nexport function newEvent(eventName: string, bubbles = false, cancelable = false): CustomEvent {\n const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'\n evt.initCustomEvent(eventName, bubbles, cancelable, null);\n return evt;\n}\n","import {EventEmitter, Injectable} from '@angular/core';\nimport {Request, RequestWithData} from '@dbg-riskit/angular-common';\nimport {ErrorMessage} from '@dbg-riskit/common';\nimport {Observable, of, throwError as _throwError, timer} from 'rxjs';\nimport {switchMap} from 'rxjs/operators';\n\nexport const FAKE_HTTP_ASYNC_TIMEOUT = 1000;\n\n@Injectable()\nexport class HttpServiceStub<T> {\n\n private value: T[] = [];\n private error: ErrorMessage[] = [];\n\n public unauthorized: EventEmitter<ErrorMessage> = new EventEmitter();\n\n public returnValue(value: T) {\n this.value.push(value);\n }\n\n public popReturnValue(): T | undefined {\n return this.value.pop();\n }\n\n public shiftReturnValue(): T | undefined {\n return this.value.shift();\n }\n\n public throwError(value: ErrorMessage) {\n this.error.push(value);\n }\n\n public get(request: Request<T>): Observable<T | undefined> {\n if (this.error.length) {\n const error = this.error.shift();\n return _throwError(error);\n }\n const value: T | undefined = this.value.shift();\n return of(value);\n }\n\n public post(request: RequestWithData<T>): Observable<T | undefined> {\n return this.get(request);\n }\n}\n\n@Injectable()\nexport class HttpAsyncServiceStub<T> extends HttpServiceStub<T> {\n\n public get(request: Request<T>, auth = true): Observable<T | undefined> {\n return timer(FAKE_HTTP_ASYNC_TIMEOUT).pipe(\n switchMap(() => super.get(request))\n );\n }\n\n public post(request: RequestWithData<T>): Observable<T | undefined> {\n return this.get(request);\n }\n}\n","import {DebugElement} from '@angular/core';\nimport {MatCard} from '@angular/material/card';\nimport {By} from '@angular/platform-browser';\n\nexport class MessageComponentDef {\n\n public constructor(public debugElement: DebugElement) {\n if (debugElement == null) {\n throw new Error('Debug element not found!');\n }\n }\n\n public get text(): string {\n return this.debugElement.query(By.directive(MatCard)).nativeElement.textContent.replace(/\\n\\s*/g, ' ')\n .replace(/\\r\\s*/g, ' ').trim();\n }\n}\n","import {DebugElement} from '@angular/core';\nimport {ComponentFixture, discardPeriodicTasks, tick} from '@angular/core/testing';\nimport {By} from '@angular/platform-browser';\nimport {RISK_INITIAL_LOAD_SELECTOR, RISK_NO_DATA_SELECTOR} from '@dbg-riskit/angular-view';\nimport {FAKE_HTTP_ASYNC_TIMEOUT} from '../stubs/http.service.stub';\nimport {MessageComponentDef} from './message.def';\n\nexport class Page<T> {\n\n public debugElement: DebugElement;\n public component: T;\n private _timeOffset = 0;\n\n public constructor(protected fixture: ComponentFixture<T>) {\n this.debugElement = fixture.debugElement;\n this.component = this.debugElement.componentInstance;\n }\n\n public detectChanges(millis = 0): void {\n this.fixture.detectChanges();\n tick(millis);\n this._timeOffset += millis;\n }\n\n public advanceAndDetectChanges(millis = 0): void {\n tick(millis);\n this._timeOffset += millis;\n this.detectChanges();\n }\n\n public advanceHTTP(): void {\n this.advanceAndDetectChanges(FAKE_HTTP_ASYNC_TIMEOUT);\n }\n\n public advanceAndDetectChangesUsingOffset(millis: number): void {\n this.advanceAndDetectChanges(millis - this._timeOffset);\n this.resetTimeOffset();\n }\n\n public resetTimeOffset(): void {\n this._timeOffset = 0;\n }\n\n public destroy() {\n this.fixture.destroy();\n try {\n // Move a lot into fututre ;)\n tick(60 * 60 * 1000);\n discardPeriodicTasks();\n } catch (ignore) {\n // Nothing to do...\n }\n }\n}\n\nexport class PageWithLoading<T> extends Page<T> {\n\n public constructor(fixture: ComponentFixture<T>) {\n super(fixture);\n }\n\n public get initialLoadComponent(): MessageComponentDef | null {\n const element = this.debugElement.query(By.css(RISK_INITIAL_LOAD_SELECTOR));\n if (element) {\n return new MessageComponentDef(element);\n }\n return null;\n }\n\n public get noDataComponent(): MessageComponentDef | null {\n const element = this.debugElement.query(By.css(RISK_NO_DATA_SELECTOR));\n if (element) {\n return new MessageComponentDef(element);\n }\n return null;\n }\n}\n","import {Component, DebugElement} from '@angular/core';\nimport {ComponentFixture} from '@angular/core/testing';\nimport {MatMenuItem, MatMenuTrigger} from '@angular/material/menu';\nimport {By} from '@angular/platform-browser';\nimport {\n AbstractFileDownloadDirective,\n CSVDownloadMenuComponent,\n CSVFileDownloadDirective,\n FileDownloadDirective\n} from '@dbg-riskit/angular-file';\nimport * as fileSaver from 'file-saver';\nimport {Observable} from 'rxjs';\nimport {click} from '../events';\nimport {Page} from './page.base';\nimport Spy = jasmine.Spy;\n\nexport class CSVDownloadMenuPage extends Page<CSVDownloadMenuComponent> {\n\n public constructor(fixture: ComponentFixture<CSVDownloadMenuComponent>) {\n super(fixture);\n }\n\n public get downloadWindowsLink(): DownloadLink {\n // Open the menu first\n click(this.debugElement.query(By.directive(MatMenuTrigger)));\n this.detectChanges(500);\n\n return new DownloadLink(this.debugElement.queryAll(By.directive(MatMenuItem))[0], this);\n }\n\n public get downloadUnixLink(): DownloadLink {\n // Open the menu first\n click(this.debugElement.query(By.directive(MatMenuTrigger)));\n this.detectChanges(500);\n\n return new DownloadLink(this.debugElement.queryAll(By.directive(MatMenuItem))[1], this);\n }\n}\n\nexport class DownloadLink {\n private _blobSpy?: jasmine.Spy;\n private _saveBlobSpy?: jasmine.Spy;\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public click(): void {\n this.setupBlobConstructorSpy();\n this.setupSaveBlobSpy();\n click(this.element);\n this.page.detectChanges();\n }\n\n public get blobSpy(): Spy {\n this.setupBlobConstructorSpy();\n return this._blobSpy!;\n }\n\n private setupBlobConstructorSpy() {\n if (!this._blobSpy) {\n let downloadDirective: AbstractFileDownloadDirective<unknown>;\n try {\n downloadDirective = this.element.injector.get(CSVFileDownloadDirective);\n } catch (_) {\n downloadDirective = this.element.injector.get(FileDownloadDirective);\n }\n this._blobSpy = spyOn(downloadDirective, 'createBlob').and.callThrough();\n }\n }\n\n public get saveSpy(): Spy {\n this.setupSaveBlobSpy();\n return this._saveBlobSpy!;\n }\n\n private setupSaveBlobSpy() {\n if (!this._saveBlobSpy) {\n this._saveBlobSpy = spyOn(fileSaver, 'saveAs');\n }\n }\n}\n\n@Component({\n template: `\n <a [risk-download]=\"data\"\n [risk-download-content-type]=\"contentType\"\n [risk-download-filename]=\"filename\">Download</a>\n `\n})\nexport class DownloadTestComponent {\n public data: any | Observable<any>;\n\n public contentType?: string;\n\n public filename?: string;\n}\n\nexport class DownloadTestComponentPage extends Page<DownloadTestComponent> {\n\n public constructor(fixture: ComponentFixture<DownloadTestComponent>) {\n super(fixture);\n }\n\n public get downloadLink(): DownloadLink {\n return new DownloadLink(this.debugElement.query(By.directive(FileDownloadDirective)), this);\n }\n}\n","import {Component, DebugElement, DebugNode} from '@angular/core';\nimport {ComponentFixture} from '@angular/core/testing';\nimport {MatAnchor, MatButton} from '@angular/material/button';\nimport {MatButtonToggle} from '@angular/material/button-toggle';\nimport {MatIcon} from '@angular/material/icon';\nimport {MatTooltip} from '@angular/material/tooltip';\nimport {By} from '@angular/platform-browser';\nimport {ValueGetter, secureRandom} from '@dbg-riskit/common';\nimport {\n DataTableComponent,\n DataTableRowDetailExpanderComponent,\n HIGHLIGHTER_CLASS,\n OrderingCriteria,\n PagingComponent\n} from '@dbg-riskit/angular-datatable';\nimport {click} from '../events';\nimport {Page} from './page.base';\n\nexport class DataTableDefinition {\n\n public constructor(public debugElement: DebugElement,\n private page: { detectChanges: () => void, advanceAndDetectChanges: () => void }) {\n }\n\n public get component(): DataTableComponent<unknown, unknown> {\n return this.debugElement.componentInstance;\n }\n\n public get data(): any[] {\n return this.component.plainData;\n }\n\n public get element(): DebugElement {\n return this.debugElement.query(By.css('.risk-data-table-wrapper > table'));\n }\n\n public get header(): TableHeader {\n return new TableHeader(this.debugElement.query((de) => de.references.mainHeader), this.page);\n }\n\n public get sorting(): TableSorting {\n return new TableSorting(this, this.page);\n }\n\n public get body(): TableBody {\n return new TableBody(this.debugElement.query((de) => de.references.mainBody), this.page);\n }\n\n public get footer(): TableFooter {\n return new TableFooter(this.debugElement.query((de) => de.references.mainFooter));\n }\n\n public get recordsCount(): RecordsCount {\n return new RecordsCount(this.debugElement.query(By.css('.risk-data-table-page-count')));\n }\n\n public get pager(): Pager {\n return new Pager(this.debugElement.query(By.directive(PagingComponent)), this.page);\n }\n}\n\n// <editor-fold defaultstate=\"collapsed\" desc=\"Table header\">\n\nexport class TableHeader {\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public get rows(): TableHeaderRow[] {\n return this.element.queryAll(By.css('tr')).map((element: DebugElement) => {\n return new TableHeaderRow(element, this.page);\n });\n }\n\n public get cells(): TableHeaderCell[] {\n return this.element.queryAll(By.css('th')).map((element: DebugElement) => {\n return new TableHeaderCell(element, this.page);\n });\n }\n\n}\n\nexport class TableHeaderRow {\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public get cells(): TableHeaderCell[] {\n return this.element.queryAll(By.css('th')).map((element: DebugElement) => {\n return new TableHeaderCell(element, this.page);\n });\n }\n}\n\nexport class TableHeaderCell {\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public get sortingHandle(): SortingHandle | null {\n const handle = this.element.query(By.directive(MatButton));\n if (handle) {\n return new SortingHandle(this.page, handle);\n }\n return null;\n }\n\n public get tooltip(): string | null {\n const handle = this.element.query(By.directive(MatTooltip));\n if (handle) {\n return handle.injector.get(MatTooltip).message;\n }\n return null;\n }\n\n public get title(): string {\n const textNode = this.element.childNodes.find((node: DebugNode) => node.nativeNode.nodeType === Node.TEXT_NODE);\n if (textNode != null) {\n return textNode\n .nativeNode.textContent.trim();\n }\n return '';\n }\n\n public get colspan(): number {\n return this.element.nativeElement.colspan;\n }\n\n public get rowspan(): number {\n return this.element.nativeElement.rowspan;\n }\n\n}\n\n// <editor-fold defaultstate=\"collapsed\" desc=\"Sorting\">\n\nexport class TableSorting {\n\n public constructor(private table: DataTableDefinition, private page: { detectChanges: () => void }) {\n }\n\n public get handles(): SortingHandle[] {\n const handles = this.table.debugElement.query((de) => de.references.mainHeader)\n .queryAll(By.directive(MatButton));\n if (!handles) {\n return [];\n }\n return handles.map((handle: DebugElement) => {\n return new SortingHandle(this.page, handle);\n });\n }\n\n public get detailRowHandles(): SortingHandle[] | null {\n const handles = this.table.debugElement.query(By.css('.risk-data-table-detail')).query(By.css('thead'))\n .queryAll(By.directive(MatButton));\n if (!handles) {\n return null;\n }\n return handles.map((handle: DebugElement) => {\n return new SortingHandle(this.page, handle);\n });\n }\n\n public get currentOrdering(): Array<OrderingCriteria<any>> {\n return (this.table.component as any).ordering;\n }\n\n public checkSorting(firstNRows: number = this.table.component.rows.length,\n criterium?: OrderingCriteria<any>): void {\n // WARN: call data once as it calls .map on all table rows\n const data = this.table.data;\n\n let ordering: Array<OrderingCriteria<any>>;\n if (criterium) {\n ordering = [criterium].concat((this.table.component as any)._defaultOrdering);\n } else {\n ordering = this.currentOrdering;\n }\n for (let i = 1; i < Math.min(data.length, firstNRows); i++) {\n ordering.some((criteria: OrderingCriteria<any>) => {\n //noinspection EqualityComparisonWithCoercionJS\n const valueA: any = criteria.get(data[i - 1]);\n const valueB: any = criteria.get(data[i]);\n if (valueA == null && valueB == null) {\n return false;\n }\n expect(valueA).not.toBeNull();\n expect(valueA).not.toBeUndefined();\n if (valueB != null) {\n if (criteria.descending) {\n expect(valueA >= valueB)\n .toBeTruthy('Expect: ' + valueA + ' >= '\n + valueB);\n } else {\n expect(valueA <= valueB)\n .toBeTruthy('Expect: ' + valueA + ' <= '\n + valueB);\n }\n }\n return valueA !== valueB;\n });\n }\n }\n}\n\nexport class SortingHandle {\n\n public constructor(private page: { detectChanges: () => void }, private handle: DebugElement) {\n }\n\n public click() {\n click(this.handle);\n this.page.detectChanges();\n }\n}\n\n// </editor-fold>\n\n// </editor-fold>\n\n// <editor-fold defaultstate=\"collapsed\" desc=\"Table body\">\n\nexport class TableBody {\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public get rows(): TableBodyRow[] {\n return this.element.queryAll((de) => de.references.masterRow).map((element: DebugElement) => {\n return new TableBodyRow(element, this.page);\n });\n }\n\n public get cells(): TableBodyCell[] {\n let cells: TableBodyCell[] = [];\n this.element.queryAll((de) => de.references.masterRow).forEach((row: DebugElement) => {\n cells = cells.concat(row.queryAll(By.css('td')).map((cell: DebugElement) => {\n return new TableBodyCell(cell);\n }));\n });\n return cells;\n }\n}\n\nexport class TableBodyRow {\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public expandRow(): void {\n click(this.element);\n this.page.detectChanges();\n }\n\n public get expander(): RowExpander {\n return new RowExpander(\n this.element.query(By.directive(DataTableRowDetailExpanderComponent)).query(By.directive(MatAnchor)));\n }\n\n public get cells(): TableBodyCell[] {\n return this.element.queryAll(By.css('td')).map((element: DebugElement) => {\n return new TableBodyCell(element);\n });\n }\n\n public get rowDetail(): TableBodyDetail | null {\n const parent = this.element.parent;\n if (parent != null) {\n const next = parent.children[parent.children.indexOf(this.element) + 1];\n if (next && !next.references.masterRow) {\n return new TableBodyDetail(next, this.page);\n }\n }\n return null;\n }\n\n public get highlighted(): boolean {\n return this.element.nativeElement.classList.contains(HIGHLIGHTER_CLASS);\n }\n}\n\nexport class RowExpander {\n public constructor(public element: DebugElement) {\n }\n\n public get icon(): string {\n return this.element.query(By.directive(MatIcon)).nativeElement.textContent.trim();\n }\n\n public get opened(): boolean {\n return this.icon === 'expand_less';\n }\n\n public get closed(): boolean {\n return this.icon === 'expand_more';\n }\n}\n\nexport class TableBodyCell {\n\n public constructor(public element: DebugElement) {\n }\n\n public get colspan(): number {\n return this.element.nativeElement.colspan;\n }\n\n public get rowspan(): number {\n return this.element.nativeElement.rowspan;\n }\n}\n\n// <editor-fold defaultstate=\"collapsed\" desc=\"Row detail\">\n\nexport class TableBodyDetail {\n\n public constructor(public element: DebugElement, private page: { detectChanges: () => void }) {\n }\n\n public header(): TableHeader {\n return new TableHeader(this.element.query(By.css('thead')), this.page);\n }\n\n public get body(): TableBodyDetailBody {\n return new TableBodyDetailBody(this.element.query(By.css('tbody')));\n }\n\n public get highlighted(): boolean {\n return this.element.nativeElement.classList.contains(HIGHLIGHTER_CLASS);\n }\n\n public get colspan(): number {\n return this.element.children[0].nativeElement.colspan;\n }\n}\n\nexport class TableBodyDetailBody {\n\n public constructor(public element: DebugElement) {\n }\n\n public get rows(): TableBodyDetailRow[] {\n return this.element.queryAll(By.css('tr')).map((element: DebugElement) => {\n return new TableBodyDetailRow(element);\n });\n }\n\n public get cells(): TableBodyCell[] {\n let cells: TableBodyCell[] = [];\n this.element.queryAll(By.css('tr')).forEach((row: DebugElement) => {\n cells = cells.concat(row.queryAll(By.css('td')).map((cell: DebugElement) => {\n return new TableBodyCell(cell);\n }));\n });\n return cells;\n }\n}\n\nexport class TableBodyDetailRow {\n\n public constructor(public element: DebugElement) {\n }\n\n public get cells(): TableBodyCell[] {\n return this.element.queryAll(By.css('td')).map((element: DebugElement) => {\n return new TableBodyCell(element);\n });\n }\n}\n\n// </editor-fold>\n\n// </editor-fold>\n\n// <editor-fold defaultstate=\"collapsed\" desc=\"Table footer\">\n\nexport class TableFooter {\n\n public constructor(public element: DebugElement) {\n }\n\n public get rows(): TableFooterRow[] {\n return this.element.queryAll(By.css('tr')).map((element: DebugElement) => {\n return new TableFooterRow(element);\n });\n }\n\n public get cells(): TableBodyCell[] {\n let cells: TableBodyCell[] = [];\n this.element.queryAll(By.css('tr')).forEach((row: DebugElement) => {\n cells = cells.concat(row.queryAll(By.css('th')).map((cell: DebugElement) => {\n return new TableBodyCell(cell);\n }));\n });\n return cells;\n }\n}\n\nexport class TableFooterRow {\n\n public constructor(public element: DebugElement) {\n }\n\n public get cells(): TableBodyCell[] {\n return this.element.queryAll(By.css('th')).map((element: DebugElement) => {\n return new TableBodyCell(element);\n });\n }\n}\n\n// </editor-fold>\n\nexport class RecordsCount {\n\n public constructor(public element: DebugElement) {\n }\n\n public get message(): string {\n return this.element.nativeElement.textContent;\n }\n}\n\nexport class Pager {\n\n public constructor(public element: DebugElement,\n private page: { detectChanges: () => void, advanceAndDetectChanges: () => void }) {\n }\n\n public get pageButtons(): DebugElement[] {\n return this.element.queryAll(By.directive(MatButtonToggle));\n }\n\n public expectLeadingButtonsDisabled() {\n for (let i = 0; i < 2; i++) {\n expect(this.pageButtons[i].classes['mat-button-toggle-disabled'])\n .toBe(true, 'First two are disabled.');\n }\n }\n\n public expectLeadingButtonsNotDisabled() {\n for (let i = 0; i < 2; i++) {\n expect(this.pageButtons[i].classes['mat-button-toggle-disabled'])\n .not.toBe(true, 'First two are not disabled.');\n }\n }\n\n public expectTrailingButtonsDisabled() {\n for (let i = this.pageButtons.length - 1; i > this.pageButtons.length - 3; i--) {\n expect(this.pageButtons[i].classes['mat-button-toggle-disabled'])\n .toBe(true, 'Last two are disabled.');\n }\n }\n\n public expectTrailingButtonsNotDisabled() {\n for (let i = this.pageButtons.length - 1; i > this.pageButtons.length - 3; i--) {\n expect(this.pageButtons[i].classes['mat-button-toggle-disabled'])\n .not.toBe(true, 'Last two are not disabled.');\n }\n }\n\n public expectButtonNumbers(numbers: number[]) {\n for (let i = 0; i < numbers.length; i++) {\n expect(this.pageButtons[i + 2].query(By.css('.mat-button-toggle-label-content'))\n .nativeElement.textContent.trim())\n .toEqual(numbers[i] + '', 'Button numbers are correct');\n }\n }\n\n public expectButtonActive(index: number) {\n expect(this.pageButtons[index].classes['mat-button-toggle-checked'])\n .toBe(true, 'Button is active.');\n }\n\n public click(index: number) {\n click(this.pageButtons[index].query(By.css('.mat-button-toggle-label-content')).nativeElement);\n this.page.detectChanges();\n this.page.advanceAndDetectChanges();\n }\n}\n\nexport function chceckSorting(page: { detectChanges: () => void, dataTable: DataTableDefinition },\n criteria: Array<ValueGetter<any>>) {\n page.dataTable.sorting.checkSorting(150);\n\n page.dataTable.sorting.handles.forEach((handle: SortingHandle, index: number) => {\n // Tigger sort based on a handle\n handle.click();\n page.detectChanges();\n\n // Check the sorting\n page.dataTable.sorting.checkSorting(150, {\n get: criteria[index]\n });\n\n // Tigger sort based on a handle\n handle.click();\n page.detectChanges();\n\n // Check the sorting\n page.dataTable.sorting.checkSorting(150, {\n get : criteria[index],\n descending: true\n });\n });\n}\n\nexport class DataTableDefinitionHosted extends Page<TestDataTableHostComponent> {\n\n public constructor(fixture: ComponentFixture<TestDataTableHostComponent>) {\n super(fixture);\n }\n\n public get dataTable(): DataTableDefinition {\n return new DataTableDefinition(this.debugElement.query(By.directive(DataTableComponent)), this);\n }\n}\n\n@Component({\n template: `\n <risk-data-table [data]=\"data\"\n [footer]=\"footer\"\n [pageSize]=\"20\"\n [defaultOrdering]=\"defaultOrdering\"\n [striped]=\"true\">\n <risk-data-table-column title=\"Test Column 1\"\n [sortingKey]=\"valueGetter\">\n <ng-template let-record=\"row\" risk-data-table-cell>\n {{record.value1}}\n </ng-template>\n </risk-data-table-column>\n <risk-data-table-column>\n <ng-template risk-data-table-cell let-record=\"row\" let-expanded=\"expanded\">\n <risk-data-table-detail-expander [expanded]=\"expanded\"></risk-data-table-detail-expander>\n </ng-template>\n <ng-template risk-data-table-footer-cell let-footer=\"footer\">\n {{footer.value1}}\n </ng-template>\n </risk-data-table-column>\n <!-- Sub detail -->\n <risk-data-table-detail-row>\n <risk-data-table-column-group>\n <risk-data-table-column title=\"Test Detail Column 1\"\n [sortingKey]=\"valueGetter\">\n <ng-template risk-data-table-cell let-record=\"row\">\n {{record.value1}}\n </ng-template>\n </risk-data-table-column>\n </risk-data-table-column-group>\n <risk-data-table-column-group>\n <risk-data-table-column title=\"Test Detail Column 2\">\n <ng-template risk-data-table-cell let-record=\"row\">\n {{record.value2}}\n </ng-template>\n </risk-data-table-column>\n <risk-data-table-column title=\"Test Detail Column 3\">\n <ng-template risk-data-table-cell let-record=\"row\">\n {{record.value3}}\n </ng-template>\n </risk-data-table-column>\n </risk-data-table-column-group>\n <risk-data-table-column-group></risk-data-table-column-group>\n </risk-data-table-detail-row>\n </risk-data-table>`\n})\nexport class TestDataTableHostComponent {\n\n public data: any[];\n\n public footer: any;\n\n public constructor() {\n this.data = [];\n for (let i = 0; i < 500; i++) {\n this.data.push({\n value1: Math.floor(secureRandom() * 20) + ' - value 1',\n value2: Math.floor(secureRandom() * 20) + ' - value 2',\n value3: Math.floor(secureRandom() * 20) + ' - value 3'\n });\n }\n this.footer = this.data[0];\n }\n\n public get defaultOrdering(): Array<OrderingCriteria<any> | ValueGetter<any>> {\n return [\n {\n get : (record: any) => {\n return record.value3;\n },\n descending: true\n },\n (record: any) => {\n return record.value2;\n }\n ];\n }\n\n public get valueGetter(): (record: any) => any {\n return (record: any) => {\n return record.value1;\n };\n }\n}\n","import {Component, DebugElement} from '@angular/core';\nimport {ComponentFixture} from '@angular/core/testing';\nimport {By} from '@angular/platform-browser';\nimport {HighlighterDirective, Row} from '@dbg-riskit/angular-datatable';\nimport {Page} from './page.base';\n\n@Component({\n template: `\n <div [risk-data-table-highlighter]=\"trackBy\" [risk-data-table-highlighter-context]=\"context\"></div>`\n})\nexport class HighLighterDirectiveTestComponent {\n\n public context?: { row: any, storage?: any, index: number, enabled: boolean };\n\n public trackBy(index: number, row: Row<any>): any {\n return row.rowData;\n }\n}\n\nexport class HighLighterDirectivePage extends Page<HighLighterDirectiveTestComponent> {\n\n public constructor(fixture: ComponentFixture<HighLighterDirectiveTestComponent>) {\n super(fixture);\n }\n\n public get highlightedElement(): DebugElement {\n return this.debugElement.query(By.directive(HighlighterDirective));\n }\n\n public get classList(): DOMTokenList {\n return this.highlightedElement.nativeElement.classList;\n }\n\n public get highlighter(): HighlighterDirective<unknown> {\n return this.highlightedElement.injector.get(HighlighterDirective);\n }\n}\n","import {Predicate} from '@angular/core';\n\n// @dynamic\nexport class ByUtil {\n\n public static and<T>(...predicates: Array<Predicate<T>>): Predicate<T> {\n return (val: T) => {\n return predicates.every((predicate: Predicate<T>) => predicate(val));\n };\n }\n\n public static or<T>(...predicates: Array<Predicate<T>>): Predicate<T> {\n return (val: T) => {\n return predicates.some((predicate: Predicate<T>) => predicate(val));\n };\n }\n\n public static not<T>(predicate: Predicate<T>): Predicate<T> {\n return (val: T) => {\n return !predicate(val);\n };\n }\n}\n","import {Component, DebugElement} from '@angular/core';\nimport {MatSidenav, MatSidenavContainer} from '@angular/material/sidenav';\nimport {MatToolbar} from '@angular/material/toolbar';\nimport {By} from '@angular/platform-browser';\nimport {LayoutComponent} from '@dbg-riskit/angular-view';\nimport {ByUtil} from '../by.util';\nimport {Page} from './page.base';\n\nexport class LayoutComponentDefinition {\n\n public constructor(public debugElement: DebugElement,\n private page: { advanceAndDetectChanges: (milis?: number) => void }) {\n }\n\n public get component(): LayoutComponent {\n return this.debugElement.componentInstance;\n }\n\n public get headToolbar(): DebugElement {\n return this.debugElement.query(ByUtil.and(By.directive(MatToolbar), By.css('.mat-elevation-z2')));\n }\n\n public get logo(): DebugElement {\n return this.headToolbar.query(By.css('.risk-layout-logo'));\n }\n\n public get menu(): DebugElement[] {\n return this.headToolbar.queryAll(ByUtil.or(\n By.css('[menu-horizontal]'),\n By.css('risk-layout-horizontal')));\n }\n\n public get sideNavContainer(): DebugElement {\n return this.debugElement.query(By.directive(MatSidenavContainer));\n }\n\n public get sideNav(): DebugElement {\n return this.sideNavContainer.query(By.directive(MatSidenav));\n }\n\n public openSideNav(): void {\n (this.sideNav.componentInstance as MatSidenav).open();\n this.page.advanceAndDetectChanges();\n }\n\n public closeSideNav(): void {\n (this.sideNav.componentInstance as MatSidenav).close();\n this.page.advanceAndDetectChanges(1);\n }\n\n public get sideNavMenu(): DebugElement[] {\n return this.sideNav.queryAll(ByUtil.or(\n By.css('[menu-vertical]'),\n By.css('risk-layout-vertical')));\n }\n\n public get content(): DebugElement {\n return this.sideNavContainer.query(By.css('.risk-layout-content'));\n }\n\n}\n\nexport class TestLayoutComponentHostPage extends Page<TestLayoutHostComponent> {\n\n public get layoutComponent(): LayoutComponentDefinition {\n return new LayoutComponentDefinition(this.debugElement.query(By.directive(LayoutComponent)), this);\n }\n}\n\n@Component({\n template: `\n <risk-layout>\n <!-- menu-horizontal -->\n <risk-layout-horizontal>\n HorizontalMenu\n </risk-layout-horizontal>\n <!-- menu-horizontal -->\n\n <!-- menu-vertical -->\n <risk-layout-vertical>\n Vertical menu\n </risk-layout-vertical>\n\n <span>Content</span>\n </risk-layout>\n `\n})\nexport class TestLayoutHostComponent {\n\n}\n","import {Directive, Injector, Input, OnChanges} from '@angular/core';\nimport {Router, UrlTree} from '@angular/router';\n\nimport {RouterStub} from './router.stub';\n\n@Directive({\n /* eslint-disable @angular-eslint/directive-selector */\n selector: '[routerLink]',\n /* eslint-enable */\n host : {\n '(click)': 'onClick()'\n }\n})\nexport class RouterLinkStubDirective implements OnChanges {\n\n @Input('routerLink')\n public linkParams: any;\n\n public navigatedTo: any = null;\n private _urlTree: UrlTree | null = null;\n\n private routerStub: RouterStub;\n\n public constructor(injector: Injector) {\n this.routerStub = injector.get(Router, null) as any;\n }\n\n public ngOnChanges(): void {\n if (this.linkParams && this.routerStub) {\n this._urlTree = this.routerStub.getURLTree(this.linkParams);\n }\n }\n\n public onClick(): void {\n this.navigatedTo = this.linkParams;\n if (this.routerStub) {\n if (Array.isArray(this.navigatedTo)) {\n this.routerStub.navigate(this.navigatedTo);\n } else {\n this.routerStub.navigateByUrl(this.navigatedTo);\n }\n }\n }\n\n public get urlTree(): UrlTree | null {\n return this._urlTree;\n }\n}\n","import {DebugElement} from '@angular/core';\n\nimport {click} from '../events';\nimport {RouterLinkStubDirective} from '../stubs/router/router.link.stub';\nimport {Page} from './page.base';\n\nexport class LinkDefinition {\n\n public constructor(private page: Page<any>, public link: DebugElement) {\n }\n\n public get stub(): RouterLinkStubDirective {\n return this.link.injector.get(RouterLinkStubDirective);\n }\n\n public get text(): string {\n return this.link.nativeElement.textContent.trim();\n }\n\n public click() {\n click(this.link.nativeElement);\n this.page.advanceAndDetectChanges();\n }\n}\n","import {ComponentFixture} from '@angular/core/testing';\nimport {By} from '@angular/platform-browser';\nimport {RouterLinkStubDirective} from '../stubs/router/router.link.stub';\nimport {LinkDefinition} from './link.definition';\nimport {Page} from './page.base';\n\nexport class LinkOnlyPage<T> extends Page<T> {\n\n public constructor(fixture: ComponentFixture<T>) {\n super(fixture);\n }\n\n public get link(): LinkDefinition {\n return new LinkDefinition(this, this.debugElement.query(By.directive(RouterLinkStubDirective)));\n }\n}\n","import {DebugElement} from '@angular/core';\nimport {MatMenuItem, MatMenuTrigger} from '@angular/material/menu';\nimport {By} from '@angular/platform-browser';\nimport {LoginMenuComponent} from '@dbg-riskit/angular-login';\nimport {ByUtil} from '../by.util';\nimport {click} from '../events';\nimport {LinkDefinition} from './link.definition';\nimport {Page} from './page.base';\n\nexport class LoginMenuPage extends Page<LoginMenuComponent> {\n\n public get menuTrigger(): DebugElement {\n return this.debugElement.query(By.directive(MatMenuTrigger));\n }\n\n public clickMenuTrigger(): void {\n click(this.menuTrigger);\n this.waitForMenu();\n }\n\n public waitForMenu(): void {\n this.detectChanges(500);\n }\n\n public get loginLink(): LinkDefinition {\n return new LinkDefinition(this, this.debugElement.query(\n ByUtil.and(\n By.directive(MatMenuItem),\n (value: DebugElement) => value.nativeElement.textContent.trim().endsWith('Login'))));\n }\n\n public get logoutLink(): LinkDefinition {\n return new LinkDefinition(this, this.debugElement.query(\n ByUtil.and(\n By.directive(MatMenuItem),\n (value: DebugElement) => value.nativeElement.textContent.trim().endsWith('Logout'))));\n }\n}\n","import {DebugElement} from '@angular/core';\nimport {ComponentFixture, tick} from '@angular/core/testing';\nimport {MatButton} from '@angular/material/button';\nimport {By} from '@angular/platform-browser';\nimport {LoginComponent} from '@dbg-riskit/angular-login';\nimport {NoopAnimationMessageComponent, RISK_ERROR_SELECTOR, RISK_GOOD_SELECTOR} from '@dbg-riskit/angular-view';\nimport {ByUtil} from '../by.util';\nimport {click, setNgModelValue} from '../events';\nimport {MessageComponentDef} from './message.def';\nimport {Page} from './page.base';\n\nexport class LoginPage extends Page<LoginComponent> {\n\n public constructor(fixture: ComponentFixture<LoginComponent>) {\n super(fixture);\n }\n\n public get formElement(): DebugElement {\n return this.debugElement.query(By.css('form'));\n }\n\n public get usernameElement(): DebugElement {\n return this.formElement.query(By.css('input[name=username]'));\n }\n\n public set username(username: string) {\n setNgModelValue(this.usernameElement, username);\n }\n\n public get passwordElement(): DebugElement {\n return this.formElement.query(By.css('input[name=password]'));\n }\n\n public set password(password: string) {\n setNgModelValue(this.passwordElement, password);\n }\n\n public get loginButtonElement(): DebugElement {\n return this.formElement.query(By.directive(MatButton));\n }\n\n public get successMessage(): MessageComponentDef | null {\n const debugElement = this.debugElement.query(\n ByUtil.and(\n By.directive(NoopAnimationMessageComponent),\n By.css(RISK_GOOD_SELECTOR)));\n if (!debugElement) {\n return null;\n }\n return new MessageComponentDef(debugElement);\n }\n\n public get errorMessage(): MessageComponentDef | null {\n const debugElement = this.debugElement.query(\n ByUtil.or(\n ByUtil.and(\n By.directive(NoopAnimationMessageComponent),\n By.css(RISK_ERROR_SELECTOR)),\n By.css('h3')));\n if (!debugElement) {\n return null;\n }\n return new MessageComponentDef(debugElement);\n }\n\n public clickLogin() {\n click(this.loginButtonElement.nativeElement);\n tick();\n this.detectChanges();\n }\n}\n","import {Component} from '@angular/core';\nimport {ComponentFixture} from '@angular/core/testing';\nimport {By} from '@angular/platform-browser';\nimport {\n RISK_ERROR_SELECTOR,\n RISK_GOOD_SELECTOR,\n RISK_INFO_SELECTOR,\n RISK_INITIAL_LOAD_SELECTOR,\n RISK_MESSAGE_SELECTOR,\n RISK_NO_DATA_SELECTOR,\n RISK_UPDATE_FAILED_SELECTOR,\n RISK_WARN_SELECTOR\n} from '@dbg-riskit/angular-view';\nimport {MessageComponentDef} from './message.def';\nimport {Page} from './page.base';\n\n@Component({\n template: `\n <risk-error [message]=\"message\"></risk-error>\n <risk-good [message]=\"message\"></risk-good>\n <risk-info [message]=\"message\"></risk-info>\n <risk-message [message]=\"message\"></risk-message>\n <risk-warn [message]=\"message\"></risk-warn>\n <risk-initial-load [message]=\"message\"></risk-initial-load>\n <risk-update-failed [message]=\"message\"></risk-update-failed>\n <risk-no-data [message]=\"message\"></risk-no-data>\n `\n})\nexport class TestMessageHostComponent {\n public message = 'custom message';\n}\n\nexport class MessageHostedPage extends Page<TestMessageHostComponent> {\n\n public constructor(fixture: ComponentFixture<TestMessageHostComponent>) {\n super(fixture);\n }\n\n public get error(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_ERROR_SELECTOR)));\n }\n\n public get good(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_GOOD_SELECTOR)));\n }\n\n public get info(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_INFO_SELECTOR)));\n }\n\n public get message(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_MESSAGE_SELECTOR)));\n }\n\n public get warn(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_WARN_SELECTOR)));\n }\n\n public get initialLoad(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_INITIAL_LOAD_SELECTOR)));\n }\n\n public get noData(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_NO_DATA_SELECTOR)));\n }\n\n public get updateFailed(): MessageComponentDef {\n return new MessageComponentDef(this.debugElement.query(By.css(RISK_UPDATE_FAILED_SELECTOR)));\n }\n}\n","import {Inject, Injectable} from '@angular/core';\nimport {RouterStateSnapshot} from '@angular/router';\n\nimport {AUTH_CONFIG, AuthConfig, AuthRoutingFlowService, AuthService} from '@dbg-riskit/angular-auth';\nimport {AUTH_PROVIDER} from '@dbg-riskit/angular-common';\n\nimport {Observable, of} from 'rxjs';\nimport {defaultIfEmpty, map} from 'rxjs/operators';\n\nexport const storage: { authRequestedPath: string | null; }\n = {authRequestedPath: null};\n\n@Injectable()\nexport class AuthRoutingFlowServiceStub extends AuthRoutingFlowService {\n\n public constructor(@Inject(AUTH_PROVIDER) private authServiceStub: AuthService,\n @Inject(AUTH_CONFIG) authConfig: AuthConfig) {\n super(null as any, null as any, {loggedIn: of(null)} as any, storage as any, authConfig, null as any);\n // cleanup\n storage.authRequestedPath = null;\n }\n\n public logout(state?: RouterStateSnapshot): Observable<boolean> {\n return this.authServiceStub.logout().pipe(\n defaultIfEmpty(0),\n map(() => true));\n }\n\n public login(username?: string, password?: string): Observable<boolean> {\n return this.authServiceStub.directLogin(username as any, password as any);\n }\n\n public loginViaService(): Observable<boolean> {\n return this.authServiceStub.loginViaAuthService();\n }\n}\n","import {Injectable} from '@angular/core';\n\nimport {WellKnown} from '@dbg-riskit/angular-auth';\n\nimport {Observable, of} from 'rxjs';\n\nexport const WELL_KNOWN: WellKnown = {\n endpoints: {\n auth : '/auth',\n token : '/token',\n logout: '/logout'\n },\n issuer : 'risk-auth'\n};\n\n@Injectable()\nexport class WellKnownServiceStub {\n public get wellKnown(): Observable<WellKnown> {\n return of(WELL_KNOWN);\n }\n\n}\n","import {Injectable} from '@angular/core';\n\nimport {AuthService} from '@dbg-riskit/angular-auth';\nimport {UserInfo} from '@dbg-riskit/common';\n\nimport {EMPTY, Observable, of} from 'rxjs';\nimport {WellKnownServiceStub} from './well.known.service.stub';\n\n@Injectable()\nexport class AuthServiceStub extends AuthService {\n\n public constructor() {\n super({} as any, new WellKnownServiceStub() as any, null as any, null as any, null as any);\n }\n\n private user?: string;\n\n public get loggedIn(): Observable<boolean> {\n return of(!!this.user);\n }\n\n public get userProfile(): Observable<UserInfo> {\n return of({\n name: this.user\n });\n }\n\n public loginViaAuthService(): Observable<boolean> {\n return of(true);\n }\n\n public checkLocationForLoginData(): Observable<boolean> {\n return of(true);\n }\n\n public directLogin(username: string, password: string): Observable<boolean> {\n this.user = username;\n this.emitLoginStatusChange(tru