Copilot commented on code in PR #6363:
URL: https://github.com/apache/texera/pull/6363#discussion_r3565420640
##########
frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts:
##########
@@ -968,5 +971,265 @@ describe("WorkflowEditorComponent", () => {
expect(getStroke(mockScanPredicate.operatorID)).toBe("red");
});
});
+
+ /**
+ * Covers the JointJS paper event handlers wired in ngAfterViewInit. Each
test
+ * drives the real paper by triggering the callback event the handler
subscribes
+ * to (element:delete, element:*-port, element:magnet:pointerclick,
cell:pointerdown,
+ * cell:pointerdblclick, link:mouseenter/leave, center-event) and asserts
the
+ * resulting graph / router / paper state. Mouse-wheel pan/zoom and
clipboard
+ * copy/cut/paste are intentionally excluded — those need real-browser DOM.
+ */
+ describe("joint paper event handlers", () => {
+ // A predicate whose type exists in the stub metadata but with dynamic
ports
+ // enabled, so the add/remove-port handlers' addPort calls are accepted.
+ const dynamicPortPredicate: OperatorPredicate = {
+ ...mockMultiInputOutputPredicate,
+ operatorID: "dynamic-port-op",
+ inputPorts: [{ portID: "input-0" }],
+ outputPorts: [{ portID: "output-0" }],
+ dynamicInputPorts: true,
+ dynamicOutputPorts: true,
+ };
+
+ it("deletes the operator when its element:delete button fires", () => {
+ const texeraGraph = workflowActionService.getTexeraGraph();
+ workflowActionService.addOperator(mockScanPredicate, mockPoint);
+ const view =
component.paper.findViewByModel(mockScanPredicate.operatorID);
+
+ // The `.delete-button` fires `element:delete` (cell view, DOM event,
x, y);
+ // fromJointPaperEvent only emits the arg array when several args are
passed.
+ (component.paper as any).trigger("element:delete", view, new
Event("click"), 0, 0);
+
+
expect(texeraGraph.hasOperator(mockScanPredicate.operatorID)).toBe(false);
+ });
+
+ it("adds then removes an input port on the matching element port
events", () => {
+ const texeraGraph = workflowActionService.getTexeraGraph();
+ const opID = dynamicPortPredicate.operatorID;
+ workflowActionService.addOperator(dynamicPortPredicate, mockPoint);
+ const view = component.paper.findViewByModel(opID);
+ expect(texeraGraph.getOperator(opID).inputPorts.length).toEqual(1);
+
+ // The port buttons fire `element:*-port` (cell view, DOM event, x, y);
+ // fromJointPaperEvent only emits the arg array when several args are
passed.
+ (component.paper as any).trigger("element:add-input-port", view, new
Event("click"), 0, 0);
+ expect(texeraGraph.getOperator(opID).inputPorts.length).toEqual(2);
+
+ (component.paper as any).trigger("element:remove-input-port", view,
new Event("click"), 0, 0);
+ expect(texeraGraph.getOperator(opID).inputPorts.length).toEqual(1);
+ });
+
+ it("adds then removes an output port on the matching element port
events", () => {
+ const texeraGraph = workflowActionService.getTexeraGraph();
+ const opID = dynamicPortPredicate.operatorID;
+ workflowActionService.addOperator(dynamicPortPredicate, mockPoint);
+ const view = component.paper.findViewByModel(opID);
+ expect(texeraGraph.getOperator(opID).outputPorts.length).toEqual(1);
+
+ // The port buttons fire `element:*-port` (cell view, DOM event, x, y);
+ // fromJointPaperEvent only emits the arg array when several args are
passed.
+ (component.paper as any).trigger("element:add-output-port", view, new
Event("click"), 0, 0);
+ expect(texeraGraph.getOperator(opID).outputPorts.length).toEqual(2);
+
+ (component.paper as any).trigger("element:remove-output-port", view,
new Event("click"), 0, 0);
+ expect(texeraGraph.getOperator(opID).outputPorts.length).toEqual(1);
+ });
+
+ it("highlights the clicked port when a port magnet is clicked", () => {
+ const wrapper = workflowActionService.getJointGraphWrapper();
+ workflowActionService.addOperator(mockScanPredicate, mockPoint);
+ const view =
component.paper.findViewByModel(mockScanPredicate.operatorID);
+ const magnet = { getAttribute: (name: string) => (name === "port" ?
"output-0" : null) };
+
+ (component.paper as any).trigger("element:magnet:pointerclick", view,
{ shiftKey: false }, magnet);
+
+ expect(wrapper.getCurrentHighlightedPortIDs()).toContainEqual({
+ operatorID: mockScanPredicate.operatorID,
+ portID: "output-0",
+ });
+ });
+
+ it("supports shift-click multiselect, toggle-off, and blank-area
unhighlight", () => {
+ const wrapper = workflowActionService.getJointGraphWrapper();
+ workflowActionService.addOperatorsAndLinks(
+ [
+ { op: mockScanPredicate, pos: mockPoint },
+ { op: mockResultPredicate, pos: mockPoint },
+ ],
+ []
+ );
+
wrapper.unhighlightOperators(...wrapper.getCurrentHighlightedOperatorIDs());
+ const viewA =
component.paper.findViewByModel(mockScanPredicate.operatorID);
+ const viewB =
component.paper.findViewByModel(mockResultPredicate.operatorID);
+
+ // plain click highlights only operator A
+ (component.paper as any).trigger("cell:pointerdown", viewA, {
shiftKey: false });
+
expect(wrapper.getCurrentHighlightedOperatorIDs()).toEqual([mockScanPredicate.operatorID]);
+
+ // shift-click adds operator B to the selection
+ (component.paper as any).trigger("cell:pointerdown", viewB, {
shiftKey: true });
+ expect([...wrapper.getCurrentHighlightedOperatorIDs()].sort()).toEqual(
+ [mockScanPredicate.operatorID, mockResultPredicate.operatorID].sort()
+ );
+
+ // shift-clicking an already-highlighted operator toggles it off
+ (component.paper as any).trigger("cell:pointerdown", viewB, {
shiftKey: true });
+
expect(wrapper.getCurrentHighlightedOperatorIDs()).toEqual([mockScanPredicate.operatorID]);
+
+ // clicking the blank canvas unhighlights everything
+ (component.paper as any).trigger("blank:pointerdown");
+ expect(wrapper.getCurrentHighlightedOperatorIDs()).toEqual([]);
Review Comment:
Triggering `blank:pointerdown` also starts the paper pan logic
(`handlePaperPan`) which subscribes to `document.mousemove` until a
`document.mouseup` occurs. In this test no mouseup is fired, so the mousemove
listener can leak into subsequent tests/files and cause unexpected
`paper.translate(...)` calls. End the pan gesture by dispatching a `mouseup`
after the trigger.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]