Skip to content

Commit 57f7306

Browse files
ELin2025claude
andcommitted
test(frontend): add HuggingFace field visibility and validator tests
Cover hide expressions for imageInput, audioInput, promptColumn, systemPrompt, contextColumn, and candidateLabels across task types. Also test requiredPromptColumn, requiredImageInput, and requiredAudioInput validators pass/fail for relevant tasks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 180f482 commit 57f7306

1 file changed

Lines changed: 130 additions & 1 deletion

File tree

frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.spec.ts

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { DatePipe } from "@angular/common";
2828
import { By } from "@angular/platform-browser";
2929
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
3030
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
31-
import { FormlyModule } from "@ngx-formly/core";
31+
import { FormlyFieldConfig, FormlyModule } from "@ngx-formly/core";
3232
import { TEXERA_FORMLY_CONFIG } from "../../../../common/formly/formly-config";
3333
import { HttpClientTestingModule } from "@angular/common/http/testing";
3434
import {
@@ -432,4 +432,133 @@ describe("OperatorPropertyEditFrameComponent", () => {
432432
fixture.detectChanges();
433433
expect(component.huggingFaceTaskPreview).toBeNull();
434434
});
435+
436+
// ── HuggingFace field visibility and validator tests ──
437+
438+
function getHfField(key: string): FormlyFieldConfig | undefined {
439+
return component.formlyFields?.[0]?.fieldGroup?.find(f => f.key === key);
440+
}
441+
442+
let currentTask: string = "";
443+
444+
let hfOperatorCounter = 0;
445+
446+
function initHfOperator(task: string): void {
447+
currentTask = task;
448+
hfOperatorCounter++;
449+
const pred = {
450+
...cloneDeep(mockHuggingFacePredicate),
451+
operatorID: `hf-test-${hfOperatorCounter}`,
452+
operatorProperties: { task, modelId: "org/model" },
453+
};
454+
workflowActionService.addOperator(pred, mockPoint);
455+
component.ngOnChanges({
456+
currentOperatorId: new SimpleChange(undefined, pred.operatorID, true),
457+
});
458+
fixture.detectChanges();
459+
}
460+
461+
function evalHide(field: FormlyFieldConfig | undefined): boolean {
462+
if (!field || !field.expressions) return false;
463+
const hideFn = (field.expressions as Record<string, Function>)["hide"];
464+
if (!hideFn) return !!field.hide;
465+
// Provide model context so getSelectedTask can find the task
466+
const fieldWithModel = { ...field, model: { task: currentTask } } as FormlyFieldConfig;
467+
return hideFn(fieldWithModel);
468+
}
469+
470+
it("should hide imageInput for text-generation task", () => {
471+
initHfOperator("text-generation");
472+
expect(evalHide(getHfField("imageInput"))).toBe(true);
473+
});
474+
475+
it("should show imageInput for image-classification task", () => {
476+
initHfOperator("image-classification");
477+
expect(evalHide(getHfField("imageInput"))).toBe(false);
478+
});
479+
480+
it("should hide audioInput for text-generation task", () => {
481+
initHfOperator("text-generation");
482+
expect(evalHide(getHfField("audioInput"))).toBe(true);
483+
});
484+
485+
it("should show audioInput for automatic-speech-recognition task", () => {
486+
initHfOperator("automatic-speech-recognition");
487+
expect(evalHide(getHfField("audioInput"))).toBe(false);
488+
});
489+
490+
it("should hide promptColumn for image-only tasks", () => {
491+
initHfOperator("image-classification");
492+
expect(evalHide(getHfField("promptColumn"))).toBe(true);
493+
});
494+
495+
it("should hide promptColumn for audio-only tasks", () => {
496+
initHfOperator("automatic-speech-recognition");
497+
expect(evalHide(getHfField("promptColumn"))).toBe(true);
498+
});
499+
500+
it("should show promptColumn for text-generation task", () => {
501+
initHfOperator("text-generation");
502+
expect(evalHide(getHfField("promptColumn"))).toBe(false);
503+
});
504+
505+
it("should show systemPrompt only for text-generation", () => {
506+
initHfOperator("text-generation");
507+
expect(evalHide(getHfField("systemPrompt"))).toBe(false);
508+
509+
initHfOperator("image-classification");
510+
expect(evalHide(getHfField("systemPrompt"))).toBe(true);
511+
});
512+
513+
it("should show contextColumn only for question-answering", () => {
514+
initHfOperator("question-answering");
515+
expect(evalHide(getHfField("contextColumn"))).toBe(false);
516+
517+
initHfOperator("text-generation");
518+
expect(evalHide(getHfField("contextColumn"))).toBe(true);
519+
});
520+
521+
it("should show candidateLabels only for classification tasks", () => {
522+
initHfOperator("zero-shot-classification");
523+
expect(evalHide(getHfField("candidateLabels"))).toBe(false);
524+
525+
initHfOperator("text-generation");
526+
expect(evalHide(getHfField("candidateLabels"))).toBe(true);
527+
});
528+
529+
it("requiredPromptColumn validator should pass when not a prompt-required task", () => {
530+
initHfOperator("image-classification");
531+
const field = getHfField("promptColumn");
532+
const validator = field?.validators?.["requiredPromptColumn"];
533+
expect(validator).toBeDefined();
534+
const mockField = { ...field, model: { task: "image-classification", promptColumn: "" } } as FormlyFieldConfig;
535+
expect(validator!.expression(null as any, mockField)).toBe(true);
536+
});
537+
538+
it("requiredPromptColumn validator should fail when prompt-required task has no column", () => {
539+
initHfOperator("text-generation");
540+
const field = getHfField("promptColumn");
541+
const validator = field?.validators?.["requiredPromptColumn"];
542+
expect(validator).toBeDefined();
543+
const mockField = { ...field, model: { task: "text-generation", promptColumn: "" } } as FormlyFieldConfig;
544+
expect(validator!.expression(null as any, mockField)).toBe(false);
545+
});
546+
547+
it("requiredImageInput validator should pass when not an image task", () => {
548+
initHfOperator("text-generation");
549+
const field = getHfField("imageInput");
550+
const validator = field?.validators?.["requiredImageInput"];
551+
expect(validator).toBeDefined();
552+
const mockField = { ...field, model: { task: "text-generation", imageInput: "" } } as FormlyFieldConfig;
553+
expect(validator!.expression(null as any, mockField)).toBe(true);
554+
});
555+
556+
it("requiredAudioInput validator should pass when not an audio task", () => {
557+
initHfOperator("text-generation");
558+
const field = getHfField("audioInput");
559+
const validator = field?.validators?.["requiredAudioInput"];
560+
expect(validator).toBeDefined();
561+
const mockField = { ...field, model: { task: "text-generation", audioInput: "" } } as FormlyFieldConfig;
562+
expect(validator!.expression(null as any, mockField)).toBe(true);
563+
});
435564
});

0 commit comments

Comments
 (0)