Skip to content

Commit

Permalink
chore(workbench): migrate end-to-end tests to TypeScript strict mode
Browse files Browse the repository at this point in the history
closes #246
  • Loading branch information
danielwiehl committed Sep 10, 2022
1 parent 43d7d51 commit 8cd4221
Show file tree
Hide file tree
Showing 18 changed files with 57 additions and 56 deletions.
16 changes: 8 additions & 8 deletions projects/scion/e2e-testing/src/app.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {Locator, Page} from '@playwright/test';

export class AppPO {

private _workbenchStartupQueryParams: URLSearchParams;
private _workbenchStartupQueryParams!: URLSearchParams;

constructor(public readonly page: Page) {
}
Expand Down Expand Up @@ -80,7 +80,7 @@ export class AppPO {
}

public async getViewId(): Promise<string> {
return viewTabLocator.getAttribute('data-viewid');
return (await viewTabLocator.getAttribute('data-viewid'))!;
}

public async activate(): Promise<void> {
Expand Down Expand Up @@ -161,7 +161,7 @@ export class AppPO {
}

public async getViewId(): Promise<string> {
return viewLocator.getAttribute('data-viewid');
return (await viewLocator.getAttribute('data-viewid'))!;
}

public waitUntilPresent(): Promise<void> {
Expand All @@ -188,7 +188,7 @@ export class AppPO {
}

public async getPartId(): Promise<string> {
return partLocator.getAttribute('data-partid');
return (await partLocator.getAttribute('data-partid'))!;
}

public locator(selector: string): Locator {
Expand Down Expand Up @@ -220,7 +220,7 @@ export class AppPO {
const viewReferences = [];

for (let i = 0; i < await viewTabsLocator.count(); i++) {
viewReferences.push(await viewTabsLocator.nth(i).getAttribute('data-viewid'));
viewReferences.push((await viewTabsLocator.nth(i).getAttribute('data-viewid'))!);
}

return viewReferences;
Expand Down Expand Up @@ -354,7 +354,7 @@ export class AppPO {
return notificationLocator.locator('header.e2e-title').innerText();
}

public async getSeverity(): Promise<'info' | 'warn' | 'error'> {
public async getSeverity(): Promise<'info' | 'warn' | 'error' | null> {
const cssClasses = await getCssClasses(notificationLocator);
if (cssClasses.includes('e2e-severity-info')) {
return 'info';
Expand All @@ -368,7 +368,7 @@ export class AppPO {
return null;
}

public async getDuration(): Promise<'short' | 'medium' | 'long' | 'infinite'> {
public async getDuration(): Promise<'short' | 'medium' | 'long' | 'infinite' | null> {
const cssClasses = await getCssClasses(notificationLocator);
if (cssClasses.includes('e2e-duration-short')) {
return 'short';
Expand Down Expand Up @@ -457,7 +457,7 @@ export class AppPO {
for (let i = 0; i < count; i++) {
const action = await actionsLocator.nth(i);
const cssClasses = await getCssClasses(action);
const actionKey = cssClasses.find(candidate => candidate.startsWith('e2e-action-key-'));
const actionKey = cssClasses.find(candidate => candidate.startsWith('e2e-action-key-'))!;
actions[actionKey.substring('e2e-action-key-'.length)] = await action.innerText();
}

Expand Down
2 changes: 1 addition & 1 deletion projects/scion/e2e-testing/src/helper/browser-dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {firstValueFrom, timer} from 'rxjs';
export function installDialogAutoAcceptHandler(page: Page, options?: {confirmDelay?: number}): BrowserDialogs {
const browserDialogCollector: BrowserDialogs = new BrowserDialogs();
page.on('dialog', async dialog => {
if (options.confirmDelay) {
if (options?.confirmDelay) {
await firstValueFrom(timer(options.confirmDelay));
}

Expand Down
4 changes: 2 additions & 2 deletions projects/scion/e2e-testing/src/helper/console-logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ export class ConsoleLogs {
this._messages = [];
}
return messages
.filter(message => options.severity === undefined || message.type() === options.severity)
.filter(message => options?.severity === undefined || message.type() === options.severity)
.map(message => message.text())
.filter(message => options.filter === undefined || message.match(options.filter));
.filter(message => options?.filter === undefined || message.match(options.filter));
}
}

Expand Down
5 changes: 2 additions & 3 deletions projects/scion/e2e-testing/src/helper/testing.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ export async function isCssClassPresent(element: Locator, cssClass: string): Pro
* Returns CSS classes on given element.
*/
export async function getCssClasses(element: Locator): Promise<string[]> {
const classAttr: string = await element.getAttribute('class');
return classAttr.split(/\s+/);
return (await element.getAttribute('class'))?.split(/\s+/) || [];
}

/**
Expand Down Expand Up @@ -59,7 +58,7 @@ export async function isPresent(element: Locator): Promise<boolean> {
* This function returns the bounding box if it hasn't changed for 100ms.
*/
export async function waitUntilBoundingBoxStable(element: Locator): Promise<DOMRect> {
const isStable = (first, second): boolean => first.x === second.x && first.y === second.y && first.width === second.width && first.height === second.height;
const isStable = (first: DOMRect, second: DOMRect): boolean => first.x === second.x && first.y === second.y && first.width === second.width && first.height === second.height;
return waitUntilStable(async () => fromRect(await element.boundingBox()), {isStable});
}

Expand Down
12 changes: 6 additions & 6 deletions projects/scion/e2e-testing/src/inspect-message-box.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class InspectMessageBoxPO {
await assertElementVisible(this._locator);

const rawContent = await this.getInput();
const map = {};
const dictionary: Record<string, any> = {};

// Sample Map content:
// {"$implicit" => undefined}
Expand All @@ -60,13 +60,13 @@ export class InspectMessageBoxPO {
// {"ɵTIMESTAMP" => 1611329911731}
const mapEntryRegex = /{"(?<key>.+)" => (?<value>.+)}/g;

let match: RegExpExecArray;
let match: RegExpExecArray | null;
while (match = mapEntryRegex.exec(rawContent)) {
const key = match.groups['key'];
const value = match.groups['value'];
map[key] = value === 'undefined' ? undefined : JSON.parse(value);
const key = match.groups!['key'];
const value = match.groups!['value'];
dictionary[key] = value === 'undefined' ? undefined : JSON.parse(value);
}
return map;
return dictionary;
}

public async enterTitle(title: string): Promise<void> {
Expand Down
12 changes: 6 additions & 6 deletions projects/scion/e2e-testing/src/inspect-notification.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class InspectNotificationPO {
await assertElementVisible(this._locator);

const rawContent = await this.getInput();
const map = {};
const dictionary: Record<string, any> = {};

// Sample Map content:
// {"$implicit" => undefined}
Expand All @@ -59,13 +59,13 @@ export class InspectNotificationPO {
// {"ɵTIMESTAMP" => 1611329911731}
const mapEntryRegex = /{"(?<key>.+)" => (?<value>.+)}/g;

let match: RegExpExecArray;
let match: RegExpExecArray | null;
while (match = mapEntryRegex.exec(rawContent)) {
const key = match.groups['key'];
const value = match.groups['value'];
map[key] = value === 'undefined' ? undefined : JSON.parse(value);
const key = match.groups!['key'];
const value = match.groups!['value'];
dictionary[key] = value === 'undefined' ? undefined : JSON.parse(value);
}
return map;
return dictionary;
}

public async enterTitle(title: string): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions projects/scion/e2e-testing/src/text-message.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export class TextMessagePO {
const text = await this._locator.innerText();

await this._locator.dblclick();
const selection: string = await this._page.evaluate(() => window.getSelection().toString());
const selection: string | undefined = await this._page.evaluate(() => window.getSelection()?.toString());

return selection && selection.length && text.includes(selection);
return selection?.length && text.includes(selection) || false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {ElementSelectors} from '../../helper/element-selectors';
export class NotificationOpenerPagePO {

private readonly _locator: Locator;
private _cssClasses: string[];
private _cssClasses = new Array<string>();

constructor(private _appPO: AppPO, public viewId: string) {
this._locator = _appPO.page.frameLocator(ElementSelectors.routerOutlet(viewId)).locator('app-notification-opener-page');
Expand Down Expand Up @@ -75,7 +75,7 @@ export class NotificationOpenerPagePO {
public async clickShow(): Promise<void> {
await assertElementVisible(this._locator);

if (!this._cssClasses || !this._cssClasses.length) {
if (!this._cssClasses.length) {
throw Error('Missing required CSS class to wait for the notification to display.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/

import {assertElementVisible} from '../../helper/testing.util';
import {assertElementVisible, fromRect} from '../../helper/testing.util';
import {AppPO, PopupPO} from '../../app.po';
import {PopupSize} from '@scion/workbench';
import {Params} from '@angular/router';
Expand Down Expand Up @@ -143,7 +143,7 @@ export class PopupPagePO {

public async getSize(): Promise<Size> {
await assertElementVisible(this._locator);
const {width, height} = await this._locator.boundingBox();
const {width, height} = fromRect(await this._locator.boundingBox());
return {width, height};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class RegisterWorkbenchIntentionPagePO {
await this._locator.locator('select.e2e-type').selectOption(type);
}

public async enterQualifier(qualifier: Qualifier): Promise<void> {
public async enterQualifier(qualifier: Qualifier | undefined): Promise<void> {
await assertElementVisible(this._locator);
const paramsEnterPO = new SciParamsEnterPO(this._locator.locator('sci-params-enter.e2e-qualifier'));
await paramsEnterPO.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/

import {assertElementVisible, isPresent} from '../../helper/testing.util';
import {assertElementVisible, fromRect, isPresent} from '../../helper/testing.util';
import {AppPO, ViewPO, ViewTabPO} from '../../app.po';
import {Params} from '@angular/router';
import {WorkbenchViewCapability} from '@scion/workbench-client';
Expand Down Expand Up @@ -177,7 +177,7 @@ export class ViewPagePO {
}

public async getSize(): Promise<Size> {
const {width, height} = await this.locator.boundingBox();
const {width, height} = fromRect(await this.locator.boundingBox());
return {width, height};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ test.describe('Popup Router', () => {
await expect(await popupPageApp1aPO.popupPO.isVisible()).toBe(true);

// expect the popup of this app to display
await expect((await popupPageApp1aPO.getPopupCapability()).metadata.appSymbolicName).toEqual('workbench-client-testing-app1');
await expect((await popupPageApp1aPO.getPopupCapability()).metadata!.appSymbolicName).toEqual('workbench-client-testing-app1');

// open the second popup for app-1
const popupOpenerApp1bPagePO = await microfrontendNavigator.openInNewTab(PopupOpenerPagePO, 'app1');
Expand All @@ -206,7 +206,7 @@ test.describe('Popup Router', () => {
await expect(await popupPageApp1bPO.popupPO.isVisible()).toBe(true);

// expect the popup of this app to display
await expect((await popupPageApp1bPO.getPopupCapability()).metadata.appSymbolicName).toEqual('workbench-client-testing-app1');
await expect((await popupPageApp1bPO.getPopupCapability()).metadata!.appSymbolicName).toEqual('workbench-client-testing-app1');

// open the popup for app-2
const popupOpenerApp2PagePO = await microfrontendNavigator.openInNewTab(PopupOpenerPagePO, 'app2');
Expand All @@ -219,7 +219,7 @@ test.describe('Popup Router', () => {
await expect(await popupPageApp2PO.popupPO.isVisible()).toBe(true);

// expect the popup of this app to display
await expect((await popupPageApp2PO.getPopupCapability()).metadata.appSymbolicName).toEqual('workbench-client-testing-app2');
await expect((await popupPageApp2PO.getPopupCapability()).metadata!.appSymbolicName).toEqual('workbench-client-testing-app2');
});

test('should throw when the requested popup has no microfrontend path declared', async ({page, appPO, microfrontendNavigator}) => {
Expand Down Expand Up @@ -317,7 +317,7 @@ test.describe('Popup Router', () => {
await expect(await popupPagePO.popupPO.isVisible()).toBe(true);

// expect the popup of this app to display
await expect((await popupPagePO.getPopupCapability()).metadata.appSymbolicName).toEqual('workbench-client-testing-app1');
await expect((await popupPagePO.getPopupCapability()).metadata!.appSymbolicName).toEqual('workbench-client-testing-app1');
});

test('should not throw if another app provides an equivalent public popup capability if not declared an intention', async ({appPO, microfrontendNavigator}) => {
Expand Down Expand Up @@ -354,7 +354,7 @@ test.describe('Popup Router', () => {
await expect(await popupPagePO.popupPO.isVisible()).toBe(true);

// expect the popup of this app to display
await expect((await popupPagePO.getPopupCapability()).metadata.appSymbolicName).toEqual('workbench-client-testing-app1');
await expect((await popupPagePO.getPopupCapability()).metadata!.appSymbolicName).toEqual('workbench-client-testing-app1');
});

test('should log warning if another app provides an equivalent public popup capability', async ({appPO, microfrontendNavigator, consoleLogs}) => {
Expand Down
12 changes: 6 additions & 6 deletions projects/scion/e2e-testing/src/workbench/message-box.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ test.describe('Workbench Message Box', () => {
test('should allow opening a message box in any view', async ({appPO, workbenchNavigator}) => {
await appPO.navigateTo({microfrontendSupport: false});

const viewTab1PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab2PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab3PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab1PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;
const viewTab2PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;
const viewTab3PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;

// open the message box in view 2
const msgboxOpenerPagePO = await workbenchNavigator.openInNewTab(MessageBoxOpenerPagePO);
Expand Down Expand Up @@ -262,9 +262,9 @@ test.describe('Workbench Message Box', () => {
// FIXME: this test will run as soon as https://github.com/SchweizerischeBundesbahnen/scion-workbench/issues/344 is fixed
await appPO.navigateTo({microfrontendSupport: false});

const viewTab1PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab2PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab3PO = (await appPO.openNewViewTab()).viewPO.viewTabPO;
const viewTab1PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;
const viewTab2PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;
const viewTab3PO = (await appPO.openNewViewTab()).viewPO!.viewTabPO;

// open the message box in view 2
const msgboxOpenerPagePO = await workbenchNavigator.openInNewTab(MessageBoxOpenerPagePO);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {Locator} from '@playwright/test';
export class NotificationOpenerPagePO {

private readonly _locator: Locator;
private _cssClasses: string[];
private _cssClasses = new Array<string>();

constructor(private _appPO: AppPO, public viewId: string) {
this._locator = this._appPO.findView({viewId: viewId}).locator('app-notification-opener-page');
Expand Down Expand Up @@ -74,7 +74,7 @@ export class NotificationOpenerPagePO {
public async clickShow(): Promise<void> {
await assertElementVisible(this._locator);

if (!this._cssClasses || !this._cssClasses.length) {
if (!this._cssClasses.length) {
throw Error('Missing required CSS class to wait for the notification to display.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/

import {assertElementVisible, isPresent} from '../../helper/testing.util';
import {assertElementVisible, fromRect, isPresent} from '../../helper/testing.util';
import {AppPO, PopupPO} from '../../app.po';
import {PopupSize} from '@scion/workbench';
import {SciAccordionPO} from '../../components.internal/accordion.po';
Expand Down Expand Up @@ -99,7 +99,7 @@ export class PopupPagePO {

public async getSize(): Promise<Size> {
await assertElementVisible(this._locator);
const {width, height} = await this._locator.boundingBox();
const {width, height} = fromRect(await this._locator.boundingBox());
return {width, height};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,20 @@ export class ViewPagePO {
await this._locator.locator('button.e2e-close').click();
}

public async addViewAction(viewpartAction: ViewpartAction | null, options?: {append?: boolean}): Promise<void> {
public async addViewAction(viewpartAction: ViewpartAction, options?: {append?: boolean}): Promise<void> {
await assertElementVisible(this._locator);

const accordionPO = new SciAccordionPO(this._locator.locator('sci-accordion.e2e-viewpart-actions'));
await accordionPO.expand();
try {
const inputLocator = this._locator.locator('input.e2e-viewpart-actions');
if (options?.append ?? true) {
const presentActions: ViewpartAction[] = coerceArray(JSON.parse(await inputLocator.inputValue() || null));
await inputLocator.fill(JSON.stringify(presentActions.concat(viewpartAction || [])));
const input = await inputLocator.inputValue() || null;
const presentActions: ViewpartAction[] = coerceArray(input ? JSON.parse(input) : null);
await inputLocator.fill(JSON.stringify(presentActions.concat(viewpartAction)));
}
else {
await inputLocator.fill(JSON.stringify([].concat(viewpartAction || [])));
await inputLocator.fill(JSON.stringify(new Array<ViewpartAction>().concat(viewpartAction)));
}
}
finally {
Expand Down
4 changes: 2 additions & 2 deletions projects/scion/e2e-testing/src/workbench/popup.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ test.describe('Workbench Popup', () => {
const popupOpenerPagePO = await workbenchNavigator.openInNewTab(PopupOpenerPagePO);
await popupOpenerPagePO.enterCssClass('testee');
await popupOpenerPagePO.enterCloseStrategy({closeOnFocusLost: false});
await popupOpenerPagePO.enterContextualViewId(startPagePO.viewId);
await popupOpenerPagePO.enterContextualViewId(startPagePO.viewId!);
await popupOpenerPagePO.selectAnchor('coordinate');
await popupOpenerPagePO.clickOpen();

Expand All @@ -408,7 +408,7 @@ test.describe('Workbench Popup', () => {
await expect(await popupPO.isVisible()).toBe(false);

// activate the view to which the popup is bound to
await startPagePO.viewTabPO.activate();
await startPagePO.viewTabPO!.activate();
await expect(await popupPO.isPresent()).toBe(true);
await expect(await popupPO.isVisible()).toBe(true);

Expand Down
1 change: 1 addition & 0 deletions projects/scion/e2e-testing/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"experimentalDecorators": true,
"moduleResolution": "node",
"target": "es2020",
"strict": true,
"types": [
"node"
],
Expand Down

0 comments on commit 8cd4221

Please sign in to comment.