This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 99b9ca281d test(frontend): share workflow-editor TestBed setup, drop 
double-run (#5626)
99b9ca281d is described below

commit 99b9ca281dd4524b0423bac9593ce1f9f136f14d
Author: Prateek Ganigi <[email protected]>
AuthorDate: Sat Jun 13 10:32:57 2026 -0700

    test(frontend): share workflow-editor TestBed setup, drop double-run (#5626)
    
    ### What changes were proposed in this PR?
    Addresses the two review comments on
    [#5318](https://github.com/apache/texera/issues/5318)'s follow-up
    implementation:
    
    1. Share a common TestBed setup so the jsdom and browser specs don't
    drift.
    
    The .browser.spec.ts split created two TestBed configurations for the
    same component - one in workflow-editor.component.spec.ts (External
    Module Integration describe), one in workflow-editor.browser.spec.ts.
    Both configured nearly identical imports/providers arrays, which would
    inevitably drift over time.
    Extracted them into a new sibling file workflow-editor.test-utils.ts
    exporting two arrays:
    
    
    export const workflowEditorTestImports = [ ... ];
    export const workflowEditorTestProviders: Provider[] = [ ... ];
    This follows the existing project convention in
    
[frontend/src/app/common/testing/test-utils.ts](vscode-webview://1epki5h79lmkghv36u4evg54fuvmk17ndjca203mcg7opnnd5sg9/frontend/src/app/common/testing/test-utils.ts)
    (which exports commonTestImports and commonTestProviders the same way).
    Each spec's TestBed now collapses to:
    
    
    await TestBed.configureTestingModule({
      imports: workflowEditorTestImports,
      providers: workflowEditorTestProviders,
    }).compileComponents();
    Adding or removing a service from either spec's setup is now a single
    edit in one file.
    
    2. Drop the explicit workflow-editor.component.spec.ts entry from the
    test-browser include in angular.json.
    
    With the six mouse-event tests now living in
    workflow-editor.browser.spec.ts (picked up by the **/*.browser.spec.ts
    glob), the explicit listing of workflow-editor.component.spec.ts in
    test-browser's include array was causing the file's 25 jsdom-friendly
    tests to run twice, once in jsdom (the default test target) and once in
    real Chrome (the test-browser target). Removed that explicit entry; the
    test-browser target now picks up only **/*.browser.spec.ts files.
    
    Scope note. The pre-existing JointJS Paper describe block at the top of
    workflow-editor.component.spec.ts has its own deliberately-different
    TestBed setup (ContextMenuComponent instead of
    NzModalCommentBoxComponent, Overlay, MockComputingUnitStatusService) and
    was left untouched, it wasn't part of the duplication introduced by the
    .browser.spec.ts split.
    
    ### Any related issues, documentation, discussions?
    Addresses review feedback on the follow-up PR for
    [#5318](https://github.com/apache/texera/issues/5318).
    Closes #5318
    Related to #3614 / PR #5146 (this PR restores tests that were commented
    out during PR #5146 as collateral from the #3614 fix).
    
    
    ### How was this PR tested?
    Existing test runs: Verified no test-count regressions in either target,
    and the double-run is gone:
    
    ng test (jsdom, full suite): 947 pass / 0 fail / 2 skipped / 1 todo
    across 103 files
    ng run gui:test-browser: 13 pass / 0 fail across 2 files (6 from
    workflow-editor.browser.spec.ts + 7 from the pre-existing
    code-editor.component.browser.spec.ts)
    workflow-editor.component.spec.ts under jsdom: 25/25 pass (unchanged
    from before this PR)
    Browser test count dropped from 38 -> 13, confirming the 25
    jsdom-friendly tests in workflow-editor.component.spec.ts no longer
    double-run in real Chrome.
    
    Static checks: tsc --noEmit and eslint clean on all four changed files.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    Co-authored-by: Claude Code (Anthropic Claude Opus 4.7)
    
    ---------
    
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
 frontend/angular.json                              |   1 -
 .../workflow-editor.component.browser.spec.ts      | 216 +++++++++++++++++++++
 .../workflow-editor.component.spec.ts              | 202 +------------------
 .../workflow-editor/workflow-editor.test-utils.ts  |  84 ++++++++
 4 files changed, 304 insertions(+), 199 deletions(-)

diff --git a/frontend/angular.json b/frontend/angular.json
index bc0fbca234..014f8e36d8 100644
--- a/frontend/angular.json
+++ b/frontend/angular.json
@@ -110,7 +110,6 @@
             "runnerConfig": "vitest.browser.config.ts",
             "tsConfig": "src/tsconfig.spec.json",
             "include": [
-              
"**/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts",
               "**/*.browser.spec.ts"
             ]
           }
diff --git 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.browser.spec.ts
 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.browser.spec.ts
new file mode 100644
index 0000000000..99fcf59ebf
--- /dev/null
+++ 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.browser.spec.ts
@@ -0,0 +1,216 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Mouse / pointer event tests for WorkflowEditorComponent.
+ *
+ * These tests exercise JointJS event paths (cell-view jQuery
+ * `.trigger("mousedown" | "dblclick")` dispatch, blank-area paper
+ * clicks, shift-click multi-select) that depend on real-DOM SVG hit
+ * testing and canvas measurement. jsdom does not implement those
+ * paths, so the tests live in a `.browser.spec.ts` file that is
+ * skipped by the default jsdom `test` target and picked up only by
+ * the `test-browser` target (Vitest + Playwright Chromium).
+ *
+ * Originally part of workflow-editor.component.spec.ts; commented out
+ * in PR #5146 to keep CI green after the file was added to the jsdom
+ * runner. Restored here per issue #5318.
+ */
+
+import { ComponentFixture, TestBed } from "@angular/core/testing";
+import { NzModalRef, NzModalService } from "ng-zorro-antd/modal";
+import * as jQuery from "jquery";
+
+import { WorkflowEditorComponent } from "./workflow-editor.component";
+import { NzModalCommentBoxComponent } from 
"./comment-box-modal/nz-modal-comment-box.component";
+import { workflowEditorTestImports, workflowEditorTestProviders } from 
"./workflow-editor.test-utils";
+
+import { WorkflowActionService } from 
"../../service/workflow-graph/model/workflow-action.service";
+import {
+  mockCommentBox,
+  mockPoint,
+  mockResultPredicate,
+  mockScanPredicate,
+} from "../../service/workflow-graph/model/mock-workflow-data";
+import { createYTypeFromObject } from "../../types/shared-editing.interface";
+
+const createJQueryEvent = (event: string, properties?: object): JQuery.Event =>
+  (jQuery as unknown as JQueryStatic).Event(event, properties);
+
+describe("WorkflowEditorComponent - mouse and pointer event integration", () 
=> {
+  let component: WorkflowEditorComponent;
+  let fixture: ComponentFixture<WorkflowEditorComponent>;
+  let workflowActionService: WorkflowActionService;
+  let nzModalService: NzModalService;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: workflowEditorTestImports,
+      providers: workflowEditorTestProviders,
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(WorkflowEditorComponent);
+    component = fixture.componentInstance;
+    workflowActionService = TestBed.inject(WorkflowActionService);
+    workflowActionService.setHighlightingEnabled(true);
+    nzModalService = TestBed.inject(NzModalService);
+    fixture.detectChanges();
+  });
+
+  it("should try to highlight the operator when user mouse clicks on an 
operator", () => {
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+    // install a spy on the highlight operator function and pass the call 
through
+    vi.spyOn(jointGraphWrapper, "highlightOperators");
+    workflowActionService.addOperator(mockScanPredicate, mockPoint);
+
+    // unhighlight the operator in case it's automatically highlighted
+    jointGraphWrapper.unhighlightOperators(mockScanPredicate.operatorID);
+
+    // find the joint Cell View object of the operator element
+    const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
+    jointCellView.$el.trigger("mousedown");
+
+    fixture.detectChanges();
+
+    // assert the highlighted operator is correct
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toEqual([mockScanPredicate.operatorID]);
+  });
+
+  it("should highlight the commentBox when user clicks on a commentBox", () => 
{
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+    vi.spyOn(jointGraphWrapper, "highlightCommentBoxes");
+    workflowActionService.addCommentBox(mockCommentBox);
+    jointGraphWrapper.unhighlightCommentBoxes(mockCommentBox.commentBoxID);
+    const jointCellView = 
component.paper.findViewByModel(mockCommentBox.commentBoxID);
+    jointCellView.$el.trigger("mousedown");
+    fixture.detectChanges();
+    
expect(jointGraphWrapper.getCurrentHighlightedCommentBoxIDs()).toEqual([mockCommentBox.commentBoxID]);
+  });
+
+  it("should open commentBox as NzModal when user double clicks on a 
commentBox", () => {
+    const modalRef: NzModalRef = nzModalService.create({
+      nzTitle: "CommentBox",
+      nzContent: NzModalCommentBoxComponent,
+      nzData: { commentBox: createYTypeFromObject(mockCommentBox) },
+      nzAutofocus: null,
+      nzFooter: [
+        {
+          label: "OK",
+          onClick: () => {
+            modalRef.destroy();
+          },
+          type: "primary",
+        },
+      ],
+    });
+    vi.spyOn(nzModalService, "create").mockReturnValue(modalRef);
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+    workflowActionService.addCommentBox(mockCommentBox);
+    jointGraphWrapper.highlightCommentBoxes(mockCommentBox.commentBoxID);
+    const jointCellView = 
component.paper.findViewByModel(mockCommentBox.commentBoxID);
+    jointCellView.$el.trigger("dblclick");
+    expect(nzModalService.create).toHaveBeenCalled();
+    fixture.detectChanges();
+    modalRef.destroy();
+  });
+
+  it("should unhighlight all highlighted operators when user mouse clicks on 
the blank space", () => {
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+
+    // add and highlight two operators
+    workflowActionService.addOperatorsAndLinks(
+      [
+        { op: mockScanPredicate, pos: mockPoint },
+        { op: mockResultPredicate, pos: mockPoint },
+      ],
+      []
+    );
+    jointGraphWrapper.highlightOperators(mockScanPredicate.operatorID, 
mockResultPredicate.operatorID);
+
+    // assert that both operators are highlighted
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
+
+    // find a blank area on the JointJS paper
+    const blankPoint = { x: mockPoint.x + 100, y: mockPoint.y + 100 };
+    expect(component.paper.findViewsFromPoint(blankPoint)).toEqual([]);
+
+    // trigger a click on the blank area using JointJS paper's jQuery element
+    const point = component.paper.localToClientPoint(blankPoint);
+    const event = createJQueryEvent("mousedown", {
+      clientX: point.x,
+      clientY: point.y,
+    });
+    component.paper.$el.trigger(event);
+
+    fixture.detectChanges();
+
+    // assert that all operators are unhighlighted
+    expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toEqual([]);
+  });
+
+  it("should highlight multiple operators when user clicks on them with shift 
key pressed", () => {
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+
+    workflowActionService.addOperator(mockScanPredicate, mockPoint);
+    workflowActionService.addOperator(mockResultPredicate, mockPoint);
+    jointGraphWrapper.highlightOperators(mockResultPredicate.operatorID);
+
+    // assert that only the last operator is highlighted
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).not.toContain(mockScanPredicate.operatorID);
+
+    // find the joint Cell View object of the first operator element
+    const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
+
+    // trigger a shift click on the cell view using its jQuery element
+    const event = createJQueryEvent("mousedown", { shiftKey: true });
+    jointCellView.$el.trigger(event);
+
+    fixture.detectChanges();
+
+    // assert that both operators are highlighted
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
+  });
+
+  it("should unhighlight the highlighted operator when user clicks on it with 
shift key pressed", () => {
+    const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
+
+    workflowActionService.addOperator(mockScanPredicate, mockPoint);
+    jointGraphWrapper.highlightOperators(mockScanPredicate.operatorID);
+
+    // assert that the operator is highlighted
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
+
+    // find the joint Cell View object of the operator element
+    const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
+
+    // trigger a shift click on the cell view using its jQuery element
+    const event = createJQueryEvent("mousedown", { shiftKey: true });
+    jointCellView.$el.trigger(event);
+
+    fixture.detectChanges();
+
+    // assert that the operator is unhighlighted
+    
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).not.toContain(mockScanPredicate.operatorID);
+  });
+});
diff --git 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts
 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts
index e2d1601e6c..c87ea058e7 100644
--- 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts
+++ 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.component.spec.ts
@@ -24,16 +24,15 @@ import { WorkflowUtilService } from 
"../../service/workflow-graph/util/workflow-
 import { ComponentFixture, TestBed } from "@angular/core/testing";
 import { ValidationWorkflowService } from 
"../../service/validation/validation-workflow.service";
 import { WorkflowEditorComponent } from "./workflow-editor.component";
-import { NzModalCommentBoxComponent } from 
"./comment-box-modal/nz-modal-comment-box.component";
+import { workflowEditorTestImports, workflowEditorTestProviders } from 
"./workflow-editor.test-utils";
 import { OperatorMetadataService } from 
"../../service/operator-metadata/operator-metadata.service";
 import { StubOperatorMetadataService } from 
"../../service/operator-metadata/stub-operator-metadata.service";
 import { JointUIService } from "../../service/joint-ui/joint-ui.service";
-import { NzModalModule, NzModalRef, NzModalService } from 
"ng-zorro-antd/modal";
+import { NzModalModule } from "ng-zorro-antd/modal";
 import { Overlay } from "@angular/cdk/overlay";
 import * as joint from "jointjs";
 import { marbles } from "rxjs-marbles";
 import {
-  mockCommentBox,
   mockPoint,
   mockResultPredicate,
   mockScanPredicate,
@@ -46,24 +45,16 @@ import { OperatorState } from 
"../../types/execute-workflow.interface";
 import { ExecuteWorkflowService } from 
"../../service/execute-workflow/execute-workflow.service";
 import { HttpClientTestingModule } from "@angular/common/http/testing";
 import { OperatorLink, OperatorPredicate } from 
"../../types/workflow-common.interface";
-import { NoopAnimationsModule } from "@angular/platform-browser/animations";
 import { tap } from "rxjs/operators";
-import { UserService } from "src/app/common/service/user/user.service";
-import { StubUserService } from 
"src/app/common/service/user/stub-user.service";
 import { WorkflowVersionService } from 
"../../../dashboard/service/user/workflow-version/workflow-version.service";
 import { of } from "rxjs";
 import { NzContextMenuService, NzDropDownModule } from 
"ng-zorro-antd/dropdown";
 import { RouterTestingModule } from "@angular/router/testing";
-import { createYTypeFromObject } from "../../types/shared-editing.interface";
-import * as jQuery from "jquery";
 import { ContextMenuComponent } from 
"./context-menu/context-menu/context-menu.component";
 import { ComputingUnitStatusService } from 
"../../../common/service/computing-unit/computing-unit-status/computing-unit-status.service";
 import { MockComputingUnitStatusService } from 
"../../../common/service/computing-unit/computing-unit-status/mock-computing-unit-status.service";
 import { commonTestProviders } from "../../../common/testing/test-utils";
 
-const createJQueryEvent = (event: string, properties?: object): JQuery.Event =>
-  (jQuery as unknown as JQueryStatic).Event(event, properties);
-
 describe("WorkflowEditorComponent", () => {
   /**
    * This sub test suite test if the JointJS paper is integrated with our 
Angular component well.
@@ -235,44 +226,13 @@ describe("WorkflowEditorComponent", () => {
     let validationWorkflowService: ValidationWorkflowService;
     let dragDropService: DragDropService;
     let jointUIService: JointUIService;
-    let nzModalService: NzModalService;
     let undoRedoService: UndoRedoService;
     let workflowVersionService: WorkflowVersionService;
 
     beforeEach(async () => {
       await TestBed.configureTestingModule({
-        imports: [
-          RouterTestingModule,
-          HttpClientTestingModule,
-          NzModalModule,
-          NzDropDownModule,
-          NoopAnimationsModule,
-          WorkflowEditorComponent,
-          NzModalCommentBoxComponent,
-        ],
-        providers: [
-          JointUIService,
-          WorkflowUtilService,
-          WorkflowActionService,
-          UndoRedoService,
-          ValidationWorkflowService,
-          DragDropService,
-          NzModalService,
-          NzContextMenuService,
-          {
-            provide: OperatorMetadataService,
-            useClass: StubOperatorMetadataService,
-          },
-          {
-            provide: UserService,
-            useClass: StubUserService,
-          },
-          WorkflowStatusService,
-          ExecuteWorkflowService,
-          UndoRedoService,
-          WorkflowVersionService,
-          ...commonTestProviders,
-        ],
+        imports: workflowEditorTestImports,
+        providers: workflowEditorTestProviders,
       }).compileComponents();
     });
 
@@ -285,114 +245,11 @@ describe("WorkflowEditorComponent", () => {
       dragDropService = TestBed.inject(DragDropService);
       // detect changes to run ngAfterViewInit and bind Model
       jointUIService = TestBed.inject(JointUIService);
-      nzModalService = TestBed.inject(NzModalService);
       undoRedoService = TestBed.inject(UndoRedoService);
       workflowVersionService = TestBed.inject(WorkflowVersionService);
       fixture.detectChanges();
     });
 
-    // TODO(#3614): the following four mouse/click-event tests rely on JointJS
-    // event paths that jsdom does not implement (HTMLCanvasElement.getContext,
-    // SVG hit-testing, jQuery .trigger("mousedown"/"dblclick") dispatch to
-    // JointJS cell views). They pass under the test-browser target
-    // (ng run gui:test-browser, real Chrome via Playwright) but fail under
-    // the default jsdom-based test runner. Commented out so the spec file
-    // can be included in the default test run; revive once a jsdom-compatible
-    // path or a runtime-targeted skip helper is available.
-    // it("should try to highlight the operator when user mouse clicks on an 
operator", () => {
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //   // install a spy on the highlight operator function and pass the call 
through
-    //   vi.spyOn(jointGraphWrapper, "highlightOperators");
-    //   workflowActionService.addOperator(mockScanPredicate, mockPoint);
-    //
-    //   // unhighlight the operator in case it's automatically highlighted
-    //   jointGraphWrapper.unhighlightOperators(mockScanPredicate.operatorID);
-    //
-    //   // find the joint Cell View object of the operator element
-    //   const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
-    //   jointCellView.$el.trigger("mousedown");
-    //
-    //   fixture.detectChanges();
-    //
-    //   // assert the function is called once
-    //   // expect(highlightOperatorFunctionSpy.calls.count()).toEqual(1);
-    //   // assert the highlighted operator is correct
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toEqual([mockScanPredicate.operatorID]);
-    // });
-    //
-    // it("should highlight the commentBox when user clicks on a commentBox", 
() => {
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //   vi.spyOn(jointGraphWrapper, "highlightCommentBoxes");
-    //   workflowActionService.addCommentBox(mockCommentBox);
-    //   
jointGraphWrapper.unhighlightCommentBoxes(mockCommentBox.commentBoxID);
-    //   const jointCellView = 
component.paper.findViewByModel(mockCommentBox.commentBoxID);
-    //   jointCellView.$el.trigger("mousedown");
-    //   fixture.detectChanges();
-    //   
expect(jointGraphWrapper.getCurrentHighlightedCommentBoxIDs()).toEqual([mockCommentBox.commentBoxID]);
-    // });
-    //
-    // it("should open commentBox as NzModal when user double clicks on a 
commentBox", () => {
-    //   const modalRef: NzModalRef = nzModalService.create({
-    //     nzTitle: "CommentBox",
-    //     nzContent: NzModalCommentBoxComponent,
-    //     nzData: { commentBox: createYTypeFromObject(mockCommentBox) },
-    //     nzAutofocus: null,
-    //     nzFooter: [
-    //       {
-    //         label: "OK",
-    //         onClick: () => {
-    //           modalRef.destroy();
-    //         },
-    //         type: "primary",
-    //       },
-    //     ],
-    //   });
-    //   vi.spyOn(nzModalService, "create").mockReturnValue(modalRef);
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //   workflowActionService.addCommentBox(mockCommentBox);
-    //   jointGraphWrapper.highlightCommentBoxes(mockCommentBox.commentBoxID);
-    //   const jointCellView = 
component.paper.findViewByModel(mockCommentBox.commentBoxID);
-    //   jointCellView.$el.trigger("dblclick");
-    //   expect(nzModalService.create).toHaveBeenCalled();
-    //   fixture.detectChanges();
-    //   modalRef.destroy();
-    // });
-    //
-    // it("should unhighlight all highlighted operators when user mouse clicks 
on the blank space", () => {
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //
-    //   // add and highlight two operators
-    //   workflowActionService.addOperatorsAndLinks(
-    //     [
-    //       { op: mockScanPredicate, pos: mockPoint },
-    //       { op: mockResultPredicate, pos: mockPoint },
-    //     ],
-    //     []
-    //   );
-    //   jointGraphWrapper.highlightOperators(mockScanPredicate.operatorID, 
mockResultPredicate.operatorID);
-    //
-    //   // assert that both operators are highlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
-    //
-    //   // find a blank area on the JointJS paper
-    //   const blankPoint = { x: mockPoint.x + 100, y: mockPoint.y + 100 };
-    //   expect(component.paper.findViewsFromPoint(blankPoint)).toEqual([]);
-    //
-    //   // trigger a click on the blank area using JointJS paper's jQuery 
element
-    //   const point = component.paper.localToClientPoint(blankPoint);
-    //   const event = createJQueryEvent("mousedown", {
-    //     clientX: point.x,
-    //     clientY: point.y,
-    //   });
-    //   component.paper.$el.trigger(event);
-    //
-    //   fixture.detectChanges();
-    //
-    //   // assert that all operators are unhighlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toEqual([]);
-    // });
-
     it("should react to operator highlight event and change the appearance of 
the operator to be highlighted", () => {
       const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
       workflowActionService.addOperator(mockScanPredicate, mockPoint);
@@ -911,57 +768,6 @@ describe("WorkflowEditorComponent", () => {
     //   }
     // });
 
-    // TODO(#3614): the next two shift-click multi-select tests also depend on
-    // jsdom-incompatible JointJS event paths (see the earlier mouse-event
-    // block above). Passing under ng run gui:test-browser; commented out so
-    // the spec file can run under the default jsdom test target.
-    // it("should highlight multiple operators when user clicks on them with 
shift key pressed", () => {
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //
-    //   workflowActionService.addOperator(mockScanPredicate, mockPoint);
-    //   workflowActionService.addOperator(mockResultPredicate, mockPoint);
-    //   jointGraphWrapper.highlightOperators(mockResultPredicate.operatorID);
-    //
-    //   // assert that only the last operator is highlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).not.toContain(mockScanPredicate.operatorID);
-    //
-    //   // find the joint Cell View object of the first operator element
-    //   const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
-    //
-    //   // trigger a shift click on the cell view using its jQuery element
-    //   const event = createJQueryEvent("mousedown", { shiftKey: true });
-    //   jointCellView.$el.trigger(event);
-    //
-    //   fixture.detectChanges();
-    //
-    //   // assert that both operators are highlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockResultPredicate.operatorID);
-    // });
-    //
-    // it("should unhighlight the highlighted operator when user clicks on it 
with shift key pressed", () => {
-    //   const jointGraphWrapper = 
workflowActionService.getJointGraphWrapper();
-    //
-    //   workflowActionService.addOperator(mockScanPredicate, mockPoint);
-    //   jointGraphWrapper.highlightOperators(mockScanPredicate.operatorID);
-    //
-    //   // assert that the operator is highlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).toContain(mockScanPredicate.operatorID);
-    //
-    //   // find the joint Cell View object of the operator element
-    //   const jointCellView = 
component.paper.findViewByModel(mockScanPredicate.operatorID);
-    //
-    //   // trigger a shift click on the cell view using its jQuery element
-    //   const event = createJQueryEvent("mousedown", { shiftKey: true });
-    //   jointCellView.$el.trigger(event);
-    //
-    //   fixture.detectChanges();
-    //
-    //   // assert that the operator is unhighlighted
-    //   
expect(jointGraphWrapper.getCurrentHighlightedOperatorIDs()).not.toContain(mockScanPredicate.operatorID);
-    // });
-
     it("should highlight all operators when user presses command + A", () => {
       const jointGraphWrapper = workflowActionService.getJointGraphWrapper();
 
diff --git 
a/frontend/src/app/workspace/component/workflow-editor/workflow-editor.test-utils.ts
 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.test-utils.ts
new file mode 100644
index 0000000000..62f7962702
--- /dev/null
+++ 
b/frontend/src/app/workspace/component/workflow-editor/workflow-editor.test-utils.ts
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Shared TestBed configuration for WorkflowEditorComponent specs.
+ *
+ * The workflow editor has two spec files that drive the same component:
+ *   - workflow-editor.component.spec.ts          (jsdom test target)
+ *   - workflow-editor.component.browser.spec.ts  (test-browser target,
+ *                                                 for JointJS event paths
+ *                                                 that need real DOM/SVG)
+ *
+ * Both specs configure TestBed with the same set of imports and
+ * providers. Exporting the two arrays here keeps them in lock-step so
+ * the two TestBed setups don't drift over time.
+ */
+
+import { Provider } from "@angular/core";
+import { HttpClientTestingModule } from "@angular/common/http/testing";
+import { NoopAnimationsModule } from "@angular/platform-browser/animations";
+import { RouterTestingModule } from "@angular/router/testing";
+import { NzModalModule, NzModalService } from "ng-zorro-antd/modal";
+import { NzContextMenuService, NzDropDownModule } from 
"ng-zorro-antd/dropdown";
+
+import { WorkflowEditorComponent } from "./workflow-editor.component";
+import { NzModalCommentBoxComponent } from 
"./comment-box-modal/nz-modal-comment-box.component";
+
+import { WorkflowActionService } from 
"../../service/workflow-graph/model/workflow-action.service";
+import { WorkflowUtilService } from 
"../../service/workflow-graph/util/workflow-util.service";
+import { UndoRedoService } from "../../service/undo-redo/undo-redo.service";
+import { DragDropService } from "../../service/drag-drop/drag-drop.service";
+import { ValidationWorkflowService } from 
"../../service/validation/validation-workflow.service";
+import { OperatorMetadataService } from 
"../../service/operator-metadata/operator-metadata.service";
+import { StubOperatorMetadataService } from 
"../../service/operator-metadata/stub-operator-metadata.service";
+import { JointUIService } from "../../service/joint-ui/joint-ui.service";
+import { WorkflowStatusService } from 
"../../service/workflow-status/workflow-status.service";
+import { ExecuteWorkflowService } from 
"../../service/execute-workflow/execute-workflow.service";
+import { WorkflowVersionService } from 
"../../../dashboard/service/user/workflow-version/workflow-version.service";
+import { UserService } from "src/app/common/service/user/user.service";
+import { StubUserService } from 
"src/app/common/service/user/stub-user.service";
+import { commonTestProviders } from "../../../common/testing/test-utils";
+
+export const workflowEditorTestImports = [
+  RouterTestingModule,
+  HttpClientTestingModule,
+  NzModalModule,
+  NzDropDownModule,
+  NoopAnimationsModule,
+  WorkflowEditorComponent,
+  NzModalCommentBoxComponent,
+];
+
+export const workflowEditorTestProviders: Provider[] = [
+  JointUIService,
+  WorkflowUtilService,
+  WorkflowActionService,
+  UndoRedoService,
+  ValidationWorkflowService,
+  DragDropService,
+  NzModalService,
+  NzContextMenuService,
+  { provide: OperatorMetadataService, useClass: StubOperatorMetadataService },
+  { provide: UserService, useClass: StubUserService },
+  WorkflowStatusService,
+  ExecuteWorkflowService,
+  WorkflowVersionService,
+  ...commonTestProviders,
+];

Reply via email to