Skip to content

Commit

Permalink
kie-issues#946: Action plan - Exploratory phase of the strategy for i…
Browse files Browse the repository at this point in the history
…mplementing the E2E test suite for the new DMN Editor - Part 3 (#2211)

Co-authored-by: Jozef Marko <[email protected]>
  • Loading branch information
ljmotta and jomarko authored Apr 11, 2024
1 parent c72aba4 commit 8a8d331
Show file tree
Hide file tree
Showing 109 changed files with 2,340 additions and 143 deletions.
9 changes: 6 additions & 3 deletions packages/dmn-editor/src/DmnEditor.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
outline: none;
}
.kie-dmn-editor--node.dimmed,
.kie-dmn-editor--node-shape.dimmed {
.kie-dmn-editor--node-shape.dimmed,
.kie-dmn-editor--input-data-node.dimmed {
opacity: 0.3;
pointer-events: none;
}
Expand Down Expand Up @@ -577,10 +578,12 @@ the cursor is inside it. By making it adimensional, that never happens. */
.kie-dmn-editor--data-type-node-panel {
position: absolute;
top: -46px;
padding-bottom: 10px;
padding-bottom: 14px;
display: flex;
align-items: end;
zoom: 0.8;

/* zoom is not supported by Playwright library */
transform: scale(0.8);
}
.kie-dmn-editor--data-type-node-panel .kie-dmn-editor--data-type-jump-to-definition {
padding-left: 4px;
Expand Down
7 changes: 7 additions & 0 deletions packages/dmn-editor/src/DmnEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,17 @@ export type DmnEditorProps = {
* If undefined, the relative paths will be displayed.
*/
onRequestToResolvePath?: OnRequestToResolvePath;
/**
* Notifies the caller when the DMN Editor performs a new edit after the debounce time.
*/
onModelDebounceStateChanged?: (changed: boolean) => void;
};

export const DmnEditorInternal = ({
model,
originalVersion,
onModelChange,
onModelDebounceStateChanged,
forwardRef,
}: DmnEditorProps & { forwardRef?: React.Ref<DmnEditorRef> }) => {
const boxedExpressionEditorActiveDrgElementId = useDmnEditorStore((s) => s.boxedExpressionEditor.activeDrgElementId);
Expand Down Expand Up @@ -254,6 +259,7 @@ export const DmnEditorInternal = ({
if (isDiagramEditingInProgress) {
return;
}
onModelDebounceStateChanged?.(false);

const timeout = setTimeout(() => {
// Ignore changes made outside... If the controller of the component
Expand All @@ -262,6 +268,7 @@ export const DmnEditorInternal = ({
return;
}

onModelDebounceStateChanged?.(true);
console.debug("DMN EDITOR: Model changed!");
onModelChange?.(dmn.model);
}, ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS);
Expand Down
2 changes: 1 addition & 1 deletion packages/dmn-editor/src/diagram/Diagram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const PAN_ON_DRAG = [1, 2];

const FIT_VIEW_OPTIONS: RF.FitViewOptions = { maxZoom: 1, minZoom: 0.1, duration: 400 };

const DEFAULT_VIEWPORT = { x: 100, y: 0, zoom: 1 };
const DEFAULT_VIEWPORT = { x: 100, y: 100, zoom: 1 };

const DELETE_NODE_KEY_CODES = ["Backspace", "Delete"];

Expand Down
1 change: 1 addition & 0 deletions packages/dmn-editor/src/diagram/edges/Waypoints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export function Waypoint({

return (
<circle
data-waypointindex={index}
ref={circleRef}
className={"kie-dmn-editor--diagram-edge-waypoint"}
cx={point["@_x"]}
Expand Down
4 changes: 2 additions & 2 deletions packages/dmn-editor/src/diagram/nodes/Nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,15 @@ export const InputDataNode = React.memo(
onDoubleClick={triggerEditing}
onKeyDown={triggerEditingIfEnter}
style={alternativeSvgStyle}
className={`kie-dmn-editor--input-data-node ${selectedAlternativeClass}`}
className={`kie-dmn-editor--input-data-node ${additionalClasses} ${selectedAlternativeClass}`}
ref={ref}
tabIndex={-1}
data-nodehref={id}
data-nodelabel={inputData["@_name"]}
>
{/* {`render count: ${renderCount.current}`}
<br /> */}
<div className={`kie-dmn-editor--node ${additionalClasses}`}>
<div className={"kie-dmn-editor--node"}>
<InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />

<OutgoingStuffNodePanel
Expand Down
4 changes: 0 additions & 4 deletions packages/dmn-editor/src/mutations/addConnectedNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ export function addConnectedNode({
"@_name": "New Knowledge Source",
"@_id": newDmnObjectId,
...requirements,
variable: {
...variableBase,
"@_name": "New Knowledge Source",
},
},
})
);
Expand Down
4 changes: 0 additions & 4 deletions packages/dmn-editor/src/mutations/addStandaloneNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ export function addStandaloneNode({
__$$element: "knowledgeSource",
"@_name": "New Knowledge Source",
"@_id": newNodeId,
variable: {
"@_name": "New Knowledge Source",
...variableBase,
},
},
})
);
Expand Down
68 changes: 44 additions & 24 deletions packages/dmn-editor/stories/dmnEditorStoriesWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@
*/

import * as React from "react";
import { useState, useRef, useMemo, useEffect } from "react";
import { useCallback, useState, useRef, useMemo, useEffect } from "react";
import { useArgs } from "@storybook/preview-api";
import { DmnEditor, DmnEditorProps, DmnEditorRef, EvaluationResults, ValidationMessages } from "../src/DmnEditor";
import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
import { DmnLatestModel, getMarshaller } from "@kie-tools/dmn-marshaller";
import { diff } from "deep-object-diff";
import { generateEmptyDmn15 } from "./misc/empty/Empty.stories";

export const evaluationResults: EvaluationResults = {};
export const validationMessages: ValidationMessages = {};

export function DmnEditorWrapper(props?: Partial<DmnEditorProps>) {
const [args, updateArgs] = useArgs<DmnEditorProps>();
export type StorybookDmnEditorProps = DmnEditorProps & { xml: string };

export function DmnEditorWrapper(props?: Partial<StorybookDmnEditorProps>) {
const [args, updateArgs] = useArgs<StorybookDmnEditorProps>();
const argsCopy = useRef(args);
const ref = useRef<DmnEditorRef>(null);
const [modelArgs, setModelArgs] = useState<DmnLatestModel>(args.model);
const model = useMemo(() => props?.model ?? modelArgs, [modelArgs, props?.model]);
const [modelChanged, setModelChange] = useState<boolean>(false);

const onModelChange = useMemo(
() => (props?.onModelChange ? props.onModelChange : setModelArgs),
Expand All @@ -41,7 +45,11 @@ export function DmnEditorWrapper(props?: Partial<DmnEditorProps>) {

useEffect(() => {
if (Object.keys(diff(argsCopy.current.model, model)).length !== 0) {
updateArgs({ ...argsCopy.current, model: model });
updateArgs({
...argsCopy.current,
model: model,
xml: getMarshaller(generateEmptyDmn15(), { upgradeTo: "latest" }).builder.build(model),
});
}
}, [updateArgs, model]);

Expand All @@ -56,25 +64,37 @@ export function DmnEditorWrapper(props?: Partial<DmnEditorProps>) {
onModelChange(args.model);
}, [args, model, onModelChange]);

const onModelDebounceStateChanged = useCallback((changed: boolean) => {
setModelChange(changed);
}, []);

return (
<div style={{ position: "absolute", width: "100%", height: "100%", top: "0px", left: "0px" }}>
<DmnEditor
ref={ref}
model={model}
originalVersion={props?.originalVersion ?? args.originalVersion}
onModelChange={onModelChange}
onRequestExternalModelByPath={props?.onRequestExternalModelByPath ?? args.onRequestExternalModelByPath}
onRequestExternalModelsAvailableToInclude={
props?.onRequestExternalModelsAvailableToInclude ?? args.onRequestExternalModelsAvailableToInclude
}
externalModelsByNamespace={props?.externalModelsByNamespace ?? args.externalModelsByNamespace}
externalContextName={props?.externalContextName ?? args.externalContextName}
externalContextDescription={props?.externalContextDescription ?? args.externalContextDescription}
validationMessages={props?.validationMessages ?? args.validationMessages}
evaluationResults={props?.evaluationResults ?? args.evaluationResults}
issueTrackerHref={props?.issueTrackerHref ?? args.issueTrackerHref}
onRequestToJumpToPath={props?.onRequestToJumpToPath ?? args.onRequestToJumpToPath}
/>
</div>
<>
{modelChanged && (
<div data-testid={"storybook--dmn-editor-model"} style={{ display: "none" }}>
{JSON.stringify(model)}
</div>
)}
<div style={{ position: "absolute", width: "100%", height: "100%", top: "0px", left: "0px" }}>
<DmnEditor
ref={ref}
model={model}
originalVersion={props?.originalVersion ?? args.originalVersion}
onModelChange={onModelChange}
onRequestExternalModelByPath={props?.onRequestExternalModelByPath ?? args.onRequestExternalModelByPath}
onRequestExternalModelsAvailableToInclude={
props?.onRequestExternalModelsAvailableToInclude ?? args.onRequestExternalModelsAvailableToInclude
}
externalModelsByNamespace={props?.externalModelsByNamespace ?? args.externalModelsByNamespace}
externalContextName={props?.externalContextName ?? args.externalContextName}
externalContextDescription={props?.externalContextDescription ?? args.externalContextDescription}
validationMessages={props?.validationMessages ?? args.validationMessages}
evaluationResults={props?.evaluationResults ?? args.evaluationResults}
issueTrackerHref={props?.issueTrackerHref ?? args.issueTrackerHref}
onRequestToJumpToPath={props?.onRequestToJumpToPath ?? args.onRequestToJumpToPath}
onModelDebounceStateChanged={onModelDebounceStateChanged}
/>
</div>
</>
);
}
3 changes: 2 additions & 1 deletion packages/dmn-editor/stories/misc/empty/Empty.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ import * as Empty from "./Empty.stories";

## Empty

When user starts with an empty diagram, a wizard for quick content initialization is displayed. The wizard enables to create simple diagram with one input and one output or a diagram with one decision table expression.
When user starts with an empty diagram, a wizard for quick content initialization is displayed.
The wizard enables to create simple diagram with one input and one output or a diagram with one decision table expression.
10 changes: 7 additions & 3 deletions packages/dmn-editor/stories/misc/empty/Empty.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { getMarshaller } from "@kie-tools/dmn-marshaller";
import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
import { DMN15_SPEC } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/Dmn15Spec";
import { DmnEditorWrapper } from "../../dmnEditorStoriesWrapper";
import { DmnEditorWrapper, StorybookDmnEditorProps } from "../../dmnEditorStoriesWrapper";
import { DmnEditor, DmnEditorProps } from "../../../src/DmnEditor";

export const generateEmptyDmn15 = () => `<?xml version="1.0" encoding="UTF-8"?>
Expand All @@ -41,18 +41,22 @@ const meta: Meta<DmnEditorProps> = {
};

export default meta;
type Story = StoryObj<DmnEditorProps>;
type Story = StoryObj<StorybookDmnEditorProps>;

const marshaller = getMarshaller(generateEmptyDmn15(), { upgradeTo: "latest" });
const model = marshaller.parser.parse();

export const Empty: Story = {
render: (args) => DmnEditorWrapper(),
args: {
model: getMarshaller(generateEmptyDmn15(), { upgradeTo: "latest" }).parser.parse(),
model: model,
originalVersion: "1.5",
evaluationResults: {},
externalContextDescription: "",
externalContextName: "Storybook - DMN Editor",
externalModelsByNamespace: {},
issueTrackerHref: "",
validationMessages: {},
xml: marshaller.builder.build(model),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { getMarshaller } from "@kie-tools/dmn-marshaller";
import { Empty } from "../../misc/empty/Empty.stories";
import { DmnEditor, DmnEditorProps } from "../../../src/DmnEditor";
import { StorybookDmnEditorProps } from "../../dmnEditorStoriesWrapper";

export const loanPreQualificationDmn = `<?xml version="1.0" encoding="UTF-8" ?>
<dmn:definitions xmlns:dmn="http://www.omg.org/spec/DMN/20180521/MODEL/"
Expand Down Expand Up @@ -783,12 +784,16 @@ const meta: Meta<DmnEditorProps> = {
};

export default meta;
type Story = StoryObj<DmnEditorProps>;
type Story = StoryObj<StorybookDmnEditorProps>;

const marshaller = getMarshaller(loanPreQualificationDmn, { upgradeTo: "latest" });
const model = marshaller.parser.parse();

export const LoanPreQualification: Story = {
...Empty.render,
args: {
...Empty.args,
model: getMarshaller(loanPreQualificationDmn, { upgradeTo: "latest" }).parser.parse(),
model: model,
xml: marshaller.builder.build(model),
},
};
9 changes: 7 additions & 2 deletions packages/dmn-editor/tests/e2e/__fixtures__/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import { Palette } from "./palette";
import { Nodes } from "./nodes";
import { Editor } from "./editor";
import { Edges } from "./edges";
import { JsonModel } from "./jsonModel";

type DmnEditorFixtures = {
diagram: Diagram;
edges: Edges;
editor: Editor;
jsonModel: JsonModel;
nodes: Nodes;
palette: Palette;
};
Expand All @@ -36,14 +38,17 @@ export const test = base.extend<DmnEditorFixtures>({
editor: async ({ page, baseURL }, use) => {
await use(new Editor(page, baseURL));
},
jsonModel: async ({ page, baseURL }, use) => {
await use(new JsonModel(page, baseURL));
},
diagram: async ({ page }, use) => {
await use(new Diagram(page));
},
nodes: async ({ page, diagram, browserName }, use) => {
await use(new Nodes(page, diagram, browserName));
},
edges: async ({ page, nodes }, use) => {
await use(new Edges(page, nodes));
edges: async ({ page, nodes, diagram }, use) => {
await use(new Edges(page, nodes, diagram));
},
palette: async ({ page, diagram, nodes }, use) => {
await use(new Palette(page, diagram, nodes));
Expand Down
15 changes: 15 additions & 0 deletions packages/dmn-editor/tests/e2e/__fixtures__/diagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,22 @@

import { Page } from "@playwright/test";

export const DEFAULT_DRD_NAME = "Default DRD";
export const UNNAMED_DRD_NAME = "Unnamed DRD";
const VIEWPORT_OFFSET_X = 100;
const VIEWPORT_OFFSET_Y = 100;

export class Diagram {
constructor(public page: Page) {}

public get() {
return this.page.getByTestId("kie-dmn-editor--diagram-container");
}

public async dblclick(position: { x: number; y: number }) {
return this.get().dblclick({ position: { x: position.x + VIEWPORT_OFFSET_X, y: position.y + VIEWPORT_OFFSET_Y } });
}

public async resetFocus() {
return this.get().click({ position: { x: 0, y: 0 } });
}
Expand All @@ -36,4 +45,10 @@ export class Diagram {
await this.page.mouse.move(args.endPosition.x, args.endPosition.y);
await this.page.mouse.up();
}

public async selectAlternativeInputDataShape() {
await this.get().getByTitle("Select or edit DRD").click();
await this.page.getByLabel("Tweak the shape of the input data node").getByText("Alternative").click();
await this.get().getByTitle("Select or edit DRD").click();
}
}
Loading

0 comments on commit 8a8d331

Please sign in to comment.