@@ -28,7 +28,7 @@ import { DatePipe } from "@angular/common";
2828import { By } from "@angular/platform-browser" ;
2929import { BrowserAnimationsModule } from "@angular/platform-browser/animations" ;
3030import { FormsModule , ReactiveFormsModule } from "@angular/forms" ;
31- import { FormlyModule } from "@ngx-formly/core" ;
31+ import { FormlyFieldConfig , FormlyModule } from "@ngx-formly/core" ;
3232import { TEXERA_FORMLY_CONFIG } from "../../../../common/formly/formly-config" ;
3333import { HttpClientTestingModule } from "@angular/common/http/testing" ;
3434import {
@@ -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