Skip to content

Commit

Permalink
Add additonal e2e tests
Browse files Browse the repository at this point in the history
Add e2e test for following scenarios:
- Add/Edit/Delete relationship
- Add/Edit/delete entiy from Explorer [FORM]
- Add/Edit/Delte relationship from Explorer [FORM]

- Extend and refactor Pageobjects
- Adjust test workspace
  • Loading branch information
tortmayr committed Nov 15, 2024
1 parent 68f86b8 commit 5cfdb94
Show file tree
Hide file tree
Showing 21 changed files with 476 additions and 80 deletions.
19 changes: 1 addition & 18 deletions e2e-tests/src/page-objects/cm-composite-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TheiaMonacoEditor } from '@theia/playwright/lib/theia-monaco-editor';
import { join } from 'path';
import { CMApp } from './cm-app';
import { IntegratedEditor, IntegratedTextEditor } from './cm-integrated-editor';
import { IntegratedFormEditor } from './form/integrated-form-editor';
import { IntegratedSystemDiagramEditor } from './system-diagram/integrated-system-diagram-editor';

export type CompositeEditorName = keyof IntegratedEditorType;
Expand Down Expand Up @@ -105,24 +106,6 @@ export class IntegratedCodeEditor extends IntegratedTextEditor {
}
}

export class IntegratedFormEditor extends IntegratedEditor {
constructor(filePath: string, parent: CMCompositeEditor, tabSelector: string) {
super(
{
tabSelector,
viewSelector: normalizeId(
`#form-editor-opener:file://${urlEncodePath(join(parent.app.workspace.escapedPath, OSUtil.fileSeparator, filePath))}`
)
},
parent
);
}

async hasError(errorMessage: string): Promise<boolean> {
return hasViewError(this.page, this.viewSelector, errorMessage);
}
}

export class IntegratedMappingDiagramEditor extends IntegratedEditor {
constructor(filePath: string, parent: CMCompositeEditor, tabSelector: string) {
super(
Expand Down
6 changes: 3 additions & 3 deletions e2e-tests/src/page-objects/cm-explorer-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
* Copyright (c) 2023 CrossBreeze.
********************************************************************************/
import { TheiaApp, TheiaExplorerView } from '@theia/playwright';
import { TheiaTabBarToolbar } from './theia-tabbar-toolbar';
import { CMMTabBarToolbar } from './cm-tab-bar-toolbar';

export class CMExplorerView extends TheiaExplorerView {
public readonly tabBarToolbar: TheiaTabBarToolbar;
public readonly tabBarToolbar: CMMTabBarToolbar;

constructor(app: TheiaApp) {
super(app);
this.tabBarToolbar = new TheiaTabBarToolbar(this);
this.tabBarToolbar = new CMMTabBarToolbar(this);
}
}
9 changes: 9 additions & 0 deletions e2e-tests/src/page-objects/cm-integrated-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2024 CrossBreeze.
********************************************************************************/

import { waitForFunction } from '@eclipse-glsp/glsp-playwright';
import { TheiaEditor, TheiaTextEditor, TheiaViewData } from '@theia/playwright';
import { CMApp } from './cm-app';
import { CMCompositeEditor } from './cm-composite-editor';
Expand Down Expand Up @@ -66,6 +67,10 @@ export abstract class IntegratedEditor extends TheiaEditor {
override title(): Promise<string | undefined> {
return this.parent.title();
}

async waitForDirty(): Promise<void> {
await waitForFunction(async () => this.isDirty());
}
}

export abstract class IntegratedTextEditor extends TheiaTextEditor {
Expand Down Expand Up @@ -128,4 +133,8 @@ export abstract class IntegratedTextEditor extends TheiaTextEditor {
override title(): Promise<string | undefined> {
return this.parent.title();
}

async waitForDirty(): Promise<void> {
await waitForFunction(async () => this.isDirty());
}
}
53 changes: 53 additions & 0 deletions e2e-tests/src/page-objects/cm-properties-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/********************************************************************************
* Copyright (c) 2024 CrossBreeze.
********************************************************************************/
import { ElementHandle } from '@playwright/test';
import { TheiaApp, TheiaEditor, isElementVisible } from '@theia/playwright';
import { CMForm } from './form/cm-form';
import { EntityForm } from './form/entiy-form';
import { RelationshipForm } from './form/relationship-form';

const CMPropertiesViewData = {
tabSelector: '#shell-tab-property-view',
viewSelector: '#property-view',
viewName: 'Properties'
};

export abstract class CMPropertiesView<F extends CMForm> extends TheiaEditor {
protected modelRootSelector = '#model-property-view';

abstract form(): Promise<F>;

constructor(app: TheiaApp) {
super(CMPropertiesViewData, app);
}

protected async modelPropertyElement(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this.page.$(this.viewSelector + ' ' + this.modelRootSelector);
}

isModelPropertyElement(): Promise<boolean> {
return isElementVisible(this.modelPropertyElement());
}

override async isDirty(): Promise<boolean> {
const form = await this.form();
return form.isDirty();
}
}

export class EntityPropertiesView extends CMPropertiesView<EntityForm> {
async form(): Promise<EntityForm> {
const entityForm = new EntityForm(this, this.modelRootSelector);
await entityForm.waitForVisible();
return entityForm;
}
}

export class RelationshipPropertiesView extends CMPropertiesView<RelationshipForm> {
async form(): Promise<RelationshipForm> {
const relationshipForm = new RelationshipForm(this, this.modelRootSelector);
await relationshipForm.waitForVisible();
return relationshipForm;
}
}
7 changes: 7 additions & 0 deletions e2e-tests/src/page-objects/cm-tab-bar-toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/********************************************************************************
* Copyright (c) 2024 CrossBreeze.
********************************************************************************/

import { TheiaTabBarToolbar } from './theia-tabbar-toolbar';

export class CMMTabBarToolbar extends TheiaTabBarToolbar {}
31 changes: 1 addition & 30 deletions e2e-tests/src/page-objects/form/cm-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { waitForFunction } from '@eclipse-glsp/glsp-playwright';
import { ElementHandle, Locator } from '@playwright/test';
import { TheiaApp, TheiaEditor, TheiaPageObject, TheiaView, isElementVisible } from '@theia/playwright';
import { TheiaPageObject, TheiaView } from '@theia/playwright';
import { TheiaViewObject } from '../theia-view-object';

export const FormIcons = {
Expand Down Expand Up @@ -62,32 +62,3 @@ export abstract class FormSection extends TheiaPageObject {
this.locator = form.locator.locator(`div.MuiAccordion-root:has(h6:has-text("${sectionName}"))`);
}
}

const CMPropertiesViewData = {
tabSelector: '#shell-tab-property-view',
viewSelector: '#property-view',
viewName: 'Properties'
};

export abstract class CMPropertiesView<F extends CMForm> extends TheiaEditor {
protected modelRootSelector = '#model-property-view';

abstract form(): Promise<F>;

constructor(app: TheiaApp) {
super(CMPropertiesViewData, app);
}

protected async modelPropertyElement(): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
return this.page.$(this.viewSelector + ' ' + this.modelRootSelector);
}

isModelPropertyElement(): Promise<boolean> {
return isElementVisible(this.modelPropertyElement());
}

override async isDirty(): Promise<boolean> {
const form = await this.form();
return form.isDirty();
}
}
11 changes: 2 additions & 9 deletions e2e-tests/src/page-objects/form/entiy-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { defined } from '@eclipse-glsp/glsp-playwright';
import { Locator } from '@playwright/test';
import { TheiaPageObject } from '@theia/playwright';
import { TheiaView } from '@theia/playwright/lib/theia-view';
import { CMForm, CMPropertiesView, FormIcons, FormSection } from './cm-form';
import { CMForm, FormIcons, FormSection } from './cm-form';

export class EntityForm extends CMForm {
protected override iconClass = FormIcons.Entity;
Expand Down Expand Up @@ -103,6 +103,7 @@ export const EntityDatatype = {
Bool: 'Bool',
Text: 'Text'
} as const;

export type EntityDatatype = keyof typeof EntityDatatype;

export class EntityAttribute extends TheiaPageObject {
Expand Down Expand Up @@ -187,11 +188,3 @@ export class EntityAttribute extends TheiaPageObject {
await deleteButton.click();
}
}

export class EntityPropertiesView extends CMPropertiesView<EntityForm> {
async form(): Promise<EntityForm> {
const entityForm = new EntityForm(this, this.modelRootSelector);
await entityForm.waitForVisible();
return entityForm;
}
}
42 changes: 42 additions & 0 deletions e2e-tests/src/page-objects/form/integrated-form-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/********************************************************************************
* Copyright (c) 2024 CrossBreeze.
********************************************************************************/

import { OSUtil, normalizeId, urlEncodePath } from '@theia/playwright';
import { join } from 'path';
import { CMCompositeEditor, hasViewError } from '../cm-composite-editor';
import { IntegratedEditor } from '../cm-integrated-editor';
import { CMForm } from './cm-form';
import { EntityForm } from './entiy-form';
import { RelationshipForm } from './relationship-form';
export class IntegratedFormEditor extends IntegratedEditor {
constructor(filePath: string, parent: CMCompositeEditor, tabSelector: string) {
super(
{
tabSelector,
viewSelector: normalizeId(
`#form-editor-opener:file://${urlEncodePath(join(parent.app.workspace.escapedPath, OSUtil.fileSeparator, filePath))}`
)
},
parent
);
}

async hasError(errorMessage: string): Promise<boolean> {
return hasViewError(this.page, this.viewSelector, errorMessage);
}

async formFor(entity: 'entity'): Promise<EntityForm>;
async formFor(relationship: 'relationship'): Promise<RelationshipForm>;
async formFor(string: 'entity' | 'relationship'): Promise<CMForm> {
if (string === 'entity') {
const form = new EntityForm(this, '');
await form.waitForVisible();
return form;
} else {
const form = new RelationshipForm(this, '');
await form.waitForVisible();
return form;
}
}
}
41 changes: 41 additions & 0 deletions e2e-tests/src/page-objects/form/relationship-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/********************************************************************************
* Copyright (c) 2024 CrossBreeze.
********************************************************************************/

import { TheiaView } from '@theia/playwright';
import { CMForm, FormIcons, FormSection } from './cm-form';

export class RelationshipForm extends CMForm {
protected override iconClass = FormIcons.Relationship;

readonly generalSection: RelationshipGeneralSection;

constructor(view: TheiaView, relativeSelector: string) {
super(view, relativeSelector, 'Relationship');
this.generalSection = new RelationshipGeneralSection(this);
}
}

export class RelationshipGeneralSection extends FormSection {
constructor(form: RelationshipForm) {
super(form, 'General');
}

async getName(): Promise<string> {
return this.locator.getByLabel('Name').inputValue();
}

async setName(name: string): Promise<void> {
await this.locator.getByLabel('Name').fill(name);
return this.page.waitForTimeout(250);
}

async getDescription(): Promise<string> {
return this.locator.getByLabel('Description').inputValue();
}

async setDescription(description: string): Promise<void> {
await this.locator.getByLabel('Description').fill(description);
return this.page.waitForTimeout(250);
}
}
14 changes: 14 additions & 0 deletions e2e-tests/src/page-objects/system-diagram/diagram-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
********************************************************************************/
import {
ChildrenAccessor,
EdgeMetadata,
Mix,
ModelElementMetadata,
NodeMetadata,
PEdge,
PLabel,
PModelElement,
PNode,
Expand All @@ -19,6 +21,7 @@ import {
usePopupCapability,
useRenameableFlow,
useResizeHandleCapability,
useRoutingPointCapability,
useSelectableFlow
} from '@eclipse-glsp/glsp-playwright/';

Expand Down Expand Up @@ -74,3 +77,14 @@ export class Attribute extends PModelElement {
return defined(await this.locate().locator('.datatype').textContent());
}
}

const RelationshipMixin = Mix(PEdge)
.flow(useClickableFlow)
.flow(useSelectableFlow)
.flow(useDeletableFlow)
.capability(useRoutingPointCapability)
.build();
@EdgeMetadata({
type: 'edge:relationship'
})
export class Relationship extends RelationshipMixin {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { OSUtil, normalizeId, urlEncodePath } from '@theia/playwright';
import { join } from 'path';
import { CMCompositeEditor, hasViewError } from '../cm-composite-editor';
import { IntegratedEditor } from '../cm-integrated-editor';
import { EntityPropertiesView } from '../cm-properties-view';
import { CMTheiaIntegration } from '../cm-theia-integration';
import { EntityPropertiesView } from '../form/entiy-form';
import { Entity } from './diagram-elements';
import { SystemDiagram, WaitForModelUpdateOptions } from './system-diagram';
import { SystemTools } from './system-tool-box';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
systemDiagram:
id: CRM
name: "CRM"
description: "Shows the complete CRM"
nodes:
- id: EmptyEntityNode
entity: EmptyEntity
x: 396
y: 429
width: 10
height: 10
customProperties:
- name: Author
value: "CrossBreeze"
- name: ExampleDiagram
- id: OrderNode
entity: Order
x: 1034
y: 253
width: 163.921875
height: 136
- id: CustomerNode
entity: Customer
x: 693
y: 231
width: 157.5
height: 176
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
systemDiagram:
id: EMPTY
name: "EMPTY"
description: "Diagram with empty entity"
nodes:
- id: EmptyEntityNode
entity: EmptyEntity
x: 396
y: 429
width: 10
height: 10
customProperties:
- name: Author
value: "CrossBreeze"
- name: EmptyDiagram
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
relationship:
id: TestRelationship
parent: Customer
child: Order
type: "1:1"
Loading

0 comments on commit 5cfdb94

Please sign in to comment.