Skip to content

Cover the property editor's Formly field-mapping rules #7909

Description

@mengw15

Task Summary

OperatorPropertyEditFrameComponent is at 74.76 % with 73 uncovered lines, and the largest block is setFormlyFormBinding's field-mapping chain — the long run of per-key rules that rewrite each Formly field config before the form renders. Two earlier passes (#6348, #6826) covered the component's other methods; this chain is what they left.

Each rule fires on a specific mappedField.key or operator type, so covering them is a matter of feeding schemas that contain those keys and asserting the produced field config. Pure EXTEND of operator-property-edit-frame.component.spec.ts.

Vitest/jsdom; see frontend/TESTING.md and frontend/AGENTS.md. Use the local coverage report to catch what is left — the lines below are where the report points today, not a fence.

Behavior to add

OperatorPropertyEditFrameComponent.setFormlyFormBinding (frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.ts, codecov 74.76 % — EXTEND)

Drive a schema through the binding and assert the resulting field config rather than calling the helpers directly:

  • Dummy-field rulesdummyOperator (812–816) sets templateOptions.disabled / readonly expressions; dummyProperty and dummyValue (821–825) set the same pair in the opposite order; dummyPropertyList (830–837) additionally sets hide from currentOperatorSchema?.operatorType !== "Dummy" and pins canRemove / canAdd to false. Cover each key, and cover dummyPropertyList with the operator type both equal to and different from "Dummy" so the hide expression is evaluated both ways.
  • Type-substitution rulesfileName (860–861) becomes type: "inputautocomplete", huggingFaceModel (864–865) becomes type: "huggingface". Assert the substituted type on the mapped field.
  • Aggregate requirement (1073–1077) — when currentOperatorSchema?.operatorType === "Aggregate" and the field is the aggregate attribute, an expression delegating to isAggregateAttributeRequired(field.parent?.model?.aggFunction) is installed. Cover an aggregate function that makes the attribute required and one that does not, and the non-Aggregate operator so the rule is skipped.
  • Style overrides (780–806) — when operatorPropertyDiff has an entry for the current operator, fieldStyleOverride is populated; a operatorVersion entry then writes the boundary style onto the element with class operator-version (786). That line indexes document.getElementsByClassName("operator-version")[0] directly, so the element must exist in the DOM or the test throws — attach the fixture to document.body, or insert the element, before exercising this path. Also cover the lookup at 799–806 that returns { style: … } for an overridden key and {} for a key with no override.
  • Preset wrapper (1099–1109) — the mappedField.type guard and the branch gated on config.env.userPresetEnabled that calls PresetWrapperComponent.setupFieldConfig. Cover the flag both on and off.
  • Validator defaults (1140–1143, and the same shape at 1286–1287) — the validators === undefined branch that initialises the object before attaching validation. Cover a field that already declares validators and one that does not.
  • Interactivity (1310–1311) — if (!this.interactive) fieldConfig?.form?.disable(). Cover both interactive and read-only frames.
  • Schema-driven dependencies (1320–1333) — if (schemaProperties && fields), the typeof propertyValue === "boolean" early return, the toggleHidden branch calling setHideExpression, and the dependOn branch which, when currentOperatorId is defined, pulls the input schema map and calls setChildTypeDependency. Cover a boolean property value, a toggleHidden property, and a dependOn property.

Determinism notes:

  • fixture.detectChanges() after each state change; attach the fixture to document.body for the style-override case so the operator-version element resolves.
  • Stub workflowCompilingService.getOperatorInputSchemaMap rather than reaching a backend.
  • Assert on the mapped field object (type, hide, expressions, validators) and on the result of calling an installed expression, not on its source text.
  • vi.restoreAllMocks() in afterEach; fixture.destroy() so untilDestroyed subscriptions stop.
  • No layout or geometry assertions — setting an inline style attribute is fine to assert, measured geometry is not.

Out of scope: the Quill title-editing methods (connectQuillToText, disconnectQuillFromText, registerQuillBinding), which #6826 deliberately set aside.

Note open PRs touch this component (#7644, #7351, #7184, #6897) — rebase before finishing.

Task Type

  • Refactor / Cleanup
  • DevOps / Deployment / CI
  • Testing / QA
  • Documentation
  • Performance
  • Other

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions