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

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

commit 9fe6c03126f51fdc0c4e43fe6b040b9823347b69
Author: Matthew B. <[email protected]>
AuthorDate: Tue Jul 21 18:54:02 2026 -0700

    test(frontend): cover setOperatorInputAttrs schema transforms (#6693)
    
    ### What changes were proposed in this PR?
    - Add coverage for setOperatorInputAttrs enum injection (optional
    default, additionalEnumValue, required, empty-map short-circuit,
    attributeNameList).
    - Add coverage for restoreOperatorInputAttrs clearing the injected
    enums.
    ### Any related issues, documentation, discussions?
    Closes: #6692
    ### How was this PR tested?
    - Run: `cd frontend && node --max-old-space-size=8192
    ./node_modules/nx/dist/bin/nx.js test gui --watch=false
    
--include=src/app/workspace/service/compile-workflow/workflow-compiling.service.spec.ts`,
    expect the suite passing.
    - Test-only change; no production code is modified.
    ### Was this PR authored or co-authored using generative AI tooling?
    Co-authored with Claude Opus 4.8 in compliance with ASF
    
    ---------
    
    Signed-off-by: Xinyuan Lin <[email protected]>
    Co-authored-by: Xinyuan Lin <[email protected]>
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
---
 .../workflow-compiling.service.spec.ts             | 224 +++++++++++++++++++++
 1 file changed, 224 insertions(+)

diff --git 
a/frontend/src/app/workspace/service/compile-workflow/workflow-compiling.service.spec.ts
 
b/frontend/src/app/workspace/service/compile-workflow/workflow-compiling.service.spec.ts
index 78f6923665..b21e0c3b1f 100644
--- 
a/frontend/src/app/workspace/service/compile-workflow/workflow-compiling.service.spec.ts
+++ 
b/frontend/src/app/workspace/service/compile-workflow/workflow-compiling.service.spec.ts
@@ -33,6 +33,7 @@ import { serializePortIdentity } from 
"../../../common/util/port-identity-serde"
 import { commonTestImports, commonTestProviders } from 
"../../../common/testing/test-utils";
 import { firstValueFrom } from "rxjs";
 import { CompilationState } from "../../types/workflow-compiling.interface";
+import { OperatorSchema } from "../../types/operator-schema.interface";
 
 describe("WorkflowCompilingService.dropInvalidAttributeValues", () => {
   // A schema shaped like the Aggregate operator after schema propagation has 
filled in the
@@ -328,3 +329,226 @@ describe("WorkflowCompilingService public getters", () => 
{
     expect(service.getOperatorInputAttributeType("op1", 0, 
"missing")).toBeUndefined();
   });
 });
+
+describe("WorkflowCompilingService.setOperatorInputAttrs / 
restoreOperatorInputAttrs", () => {
+  const port0 = serializePortIdentity({ id: 0, internal: false });
+
+  // Builds an OperatorSchema wrapping the given json schema. Only jsonSchema 
matters for these pure transforms;
+  // additionalMetadata is included only to satisfy the OperatorSchema type.
+  const makeOperatorSchema = (jsonSchema: any): OperatorSchema =>
+    ({
+      operatorType: "TestOp",
+      operatorVersion: "1",
+      jsonSchema,
+      additionalMetadata: {
+        userFriendlyName: "Test Op",
+        operatorGroupName: "Test",
+        inputPorts: [{ displayName: "input" }],
+        outputPorts: [{ displayName: "output" }],
+      },
+    }) as unknown as OperatorSchema;
+
+  // input port 0 exposes two attributes.
+  const inputPortSchemaMap = {
+    [port0]: [
+      { attributeName: "col_a", attributeType: "string" },
+      { attributeName: "col_b", attributeType: "integer" },
+    ],
+  } as any;
+
+  describe("setOperatorInputAttrs", () => {
+    it("returns the original operator schema unchanged when the input schema 
map is undefined", () => {
+      const schema = makeOperatorSchema({ type: "object", properties: {} });
+      expect(WorkflowCompilingService.setOperatorInputAttrs(schema, 
undefined)).toBe(schema);
+    });
+
+    it("returns the original operator schema unchanged when the input schema 
map is empty", () => {
+      const schema = makeOperatorSchema({ type: "object", properties: {} });
+      expect(WorkflowCompilingService.setOperatorInputAttrs(schema, 
{})).toBe(schema);
+    });
+
+    it("injects the input attribute names as an enum on an optional 
attributeName property", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 0 },
+        },
+      });
+
+      const result = WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap);
+      const prop = (result.jsonSchema.properties as any).attribute;
+      // optional (not in `required`) properties append "" so the empty 
selection passes validation.
+      expect(prop.enum).toEqual(["col_a", "col_b", ""]);
+      expect(prop.type).toBe("string");
+      expect(prop.uniqueItems).toBe(true);
+    });
+
+    it('appends the property\'s string default instead of "" for optional 
properties', () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 0, default: "col_a" },
+        },
+      });
+
+      const result = WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap);
+      expect((result.jsonSchema.properties as 
any).attribute.enum).toEqual(["col_a", "col_b", "col_a"]);
+    });
+
+    it("throws when the property's default value is not a string", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 0, default: 42 },
+        },
+      });
+
+      expect(() => WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap)).toThrow(
+        "default value must be a string"
+      );
+    });
+
+    it("does not append an empty option for required properties", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        required: ["attribute"],
+        properties: {
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 0 },
+        },
+      });
+
+      expect(
+        (WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap).jsonSchema.properties as any)
+          .attribute.enum
+      ).toEqual(["col_a", "col_b"]);
+    });
+
+    it("includes additionalEnumValue before the optional empty option", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: {
+            type: "string",
+            autofill: "attributeName",
+            autofillAttributeOnPort: 0,
+            additionalEnumValue: "*",
+          },
+        },
+      });
+
+      expect(
+        (WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap).jsonSchema.properties as any)
+          .attribute.enum
+      ).toEqual(["col_a", "col_b", "*", ""]);
+    });
+
+    it("yields an undefined enum when autofillAttributeOnPort is missing", () 
=> {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: { type: "string", autofill: "attributeName" },
+        },
+      });
+
+      expect(
+        (WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap).jsonSchema.properties as any)
+          .attribute.enum
+      ).toBeUndefined();
+    });
+
+    it("yields an undefined enum when the referenced input port has no 
schema", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          // port 5 is not present in inputPortSchemaMap.
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 5 },
+        },
+      });
+
+      expect(
+        (WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap).jsonSchema.properties as any)
+          .attribute.enum
+      ).toBeUndefined();
+    });
+
+    it("injects the enum into the items of an attributeNameList property", () 
=> {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attributes: {
+            type: "array",
+            autofill: "attributeNameList",
+            autofillAttributeOnPort: 0,
+            items: { type: "string" },
+          },
+        },
+      });
+
+      const prop = (
+        WorkflowCompilingService.setOperatorInputAttrs(schema, 
inputPortSchemaMap).jsonSchema.properties as any
+      ).attributes;
+      expect(prop.type).toBe("array");
+      expect(prop.uniqueItems).toBe(true);
+      expect(prop.items.type).toBe("string");
+      expect(prop.items.enum).toEqual(["col_a", "col_b", ""]);
+    });
+  });
+
+  describe("restoreOperatorInputAttrs", () => {
+    it("clears the injected enum/uniqueItems from an attributeName property", 
() => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: {
+            type: "string",
+            autofill: "attributeName",
+            autofillAttributeOnPort: 0,
+            enum: ["col_a", "col_b", ""],
+            uniqueItems: true,
+          },
+        },
+      });
+
+      const prop = 
(WorkflowCompilingService.restoreOperatorInputAttrs(schema).jsonSchema.properties
 as any).attribute;
+      expect(prop.enum).toBeUndefined();
+      expect(prop.uniqueItems).toBeUndefined();
+      expect(prop.type).toBe("string");
+    });
+
+    it("clears the injected enum from the items of an attributeNameList 
property", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attributes: {
+            type: "array",
+            autofill: "attributeNameList",
+            autofillAttributeOnPort: 0,
+            uniqueItems: true,
+            items: { type: "string", enum: ["col_a", "col_b", ""] },
+          },
+        },
+      });
+
+      const prop = 
(WorkflowCompilingService.restoreOperatorInputAttrs(schema).jsonSchema.properties
 as any).attributes;
+      expect(prop.type).toBe("array");
+      expect(prop.uniqueItems).toBeUndefined();
+      expect(prop.items.enum).toBeUndefined();
+      expect(prop.items.type).toBe("string");
+    });
+
+    it("round-trips: restore reverses the enums that setOperatorInputAttrs 
injected", () => {
+      const schema = makeOperatorSchema({
+        type: "object",
+        properties: {
+          attribute: { type: "string", autofill: "attributeName", 
autofillAttributeOnPort: 0 },
+        },
+      });
+
+      const propagated = 
WorkflowCompilingService.setOperatorInputAttrs(schema, inputPortSchemaMap);
+      expect((propagated.jsonSchema.properties as 
any).attribute.enum).toEqual(["col_a", "col_b", ""]);
+
+      const restored = 
WorkflowCompilingService.restoreOperatorInputAttrs(propagated);
+      expect((restored.jsonSchema.properties as 
any).attribute.enum).toBeUndefined();
+    });
+  });
+});

Reply via email to