11/* eslint-disable dot-notation */
22import { ComponentFixture , fakeAsync , TestBed , tick } from '@angular/core/testing' ;
3- import { AbstractControl , FormArray , FormBuilder , ReactiveFormsModule } from '@angular/forms' ;
3+ import { AbstractControl , FormArray , FormBuilder , FormGroup , ReactiveFormsModule , Validators } from '@angular/forms' ;
44import { provideRouter , Router , RouterModule } from '@angular/router' ;
55import { of , throwError } from 'rxjs' ;
66
@@ -13,8 +13,8 @@ import { TrackingService } from 'src/app/core/services/integration/tracking.serv
1313import { IntegrationsToastService } from 'src/app/core/services/common/integrations-toast.service' ;
1414import { StorageService } from 'src/app/core/services/common/storage.service' ;
1515import { SiWorkspaceService } from 'src/app/core/services/si/si-core/si-workspace.service' ;
16- import { configuration , costCodeFieldValue , costTypeFieldValue , fyleFields , groupedDestinationAttributes , importSettings , importSettingsWithProject , intacctImportCodeConfig , locationEntityMapping , sageIntacctFields , sageIntacctFieldsSortedByPriority , settingsWithDependentFields } from '../../intacct.fixture' ;
17- import { IntacctCategoryDestination , IntacctOnboardingState , IntacctUpdateEvent , Page , ProgressPhase , ToastSeverity , TrackingApp } from 'src/app/core/models/enum/enum.model' ;
16+ import { configuration , costCodeFieldValue , costTypeFieldValue , customField , customFieldValue , fyleFields , groupedDestinationAttributes , importSettings , importSettingsWithProject , intacctImportCodeConfig , locationEntityMapping , sageIntacctFields , sageIntacctFieldsSortedByPriority , settingsWithDependentFields } from '../../intacct.fixture' ;
17+ import { IntacctCategoryDestination , IntacctOnboardingState , IntacctUpdateEvent , MappingSourceField , Page , ProgressPhase , SageIntacctField , ToastSeverity , TrackingApp } from 'src/app/core/models/enum/enum.model' ;
1818import { SharedModule } from 'src/app/shared/shared.module' ;
1919import { Org } from 'src/app/core/models/org/org.model' ;
2020import { HttpClientTestingModule } from '@angular/common/http/testing' ;
@@ -82,6 +82,8 @@ describe('IntacctImportSettingsComponent', () => {
8282 siMappingsService . getFyleFields . and . returnValue ( of ( fyleFields ) ) ;
8383 siMappingsService . getGroupedDestinationAttributes . and . returnValue ( of ( groupedDestinationAttributes ) ) ;
8484 siMappingsService . getConfiguration . and . returnValue ( of ( configuration ) ) ;
85+ siMappingsService . refreshSageIntacctDimensions . and . returnValue ( of ( '' ) ) ;
86+ siMappingsService . refreshFyleDimensions . and . returnValue ( of ( '' ) ) ;
8587 intacctConnectorService . getLocationEntityMapping . and . returnValue ( of ( locationEntityMapping ) ) ;
8688 orgService . getCachedOrg . and . returnValue ( { created_at : new Date ( ) } as Org ) ;
8789 siWorkspaceService . getIntacctOnboardingState . and . returnValue ( IntacctOnboardingState . IMPORT_SETTINGS ) ;
@@ -388,4 +390,208 @@ describe('IntacctImportSettingsComponent', () => {
388390 } ) ;
389391 } ) ;
390392 } ) ;
393+
394+ describe ( 'Utility Functions' , ( ) => {
395+ beforeEach ( ( ) => {
396+ fixture . detectChanges ( ) ;
397+ } ) ;
398+
399+ it ( 'importCodeFieldGetter should return a valid FormArray' , ( ) => {
400+ expect ( component . importCodeFieldGetter instanceof FormArray ) . toBeTrue ( ) ;
401+ } ) ;
402+
403+ it ( 'addImportCodeField should add and remove fields correctly' , ( ) => {
404+ const sourceField = IntacctCategoryDestination . ACCOUNT ;
405+
406+ component . addImportCodeField ( { checked : true } , sourceField ) ;
407+ expect ( component . importCodeFieldGetter . length ) . toBe ( 1 ) ;
408+
409+ component . addImportCodeField ( { checked : false } , sourceField ) ;
410+ expect ( component . importCodeFieldGetter . length ) . toBe ( 0 ) ;
411+ } ) ;
412+
413+ it ( 'getFormGroup should return FormGroup' , ( ) => {
414+ const formGroup = component [ 'formBuilder' ] . group ( {
415+ test : [ 'value' ]
416+ } ) ;
417+ expect ( component . getFormGroup ( formGroup ) instanceof FormGroup ) . toBeTrue ( ) ;
418+ } ) ;
419+
420+ it ( 'getDestinationField should correctly transform field names' , ( ) => {
421+ expect ( component . getDestinationField ( 'category' ) ) . toBe ( 'categories' ) ;
422+ expect ( component . getDestinationField ( 'tax' ) ) . toBe ( 'taxes' ) ;
423+ expect ( component . getDestinationField ( 'match' ) ) . toBe ( 'matches' ) ;
424+ expect ( component . getDestinationField ( 'import' ) ) . toBe ( 'imports' ) ;
425+ } ) ;
426+
427+ it ( 'refreshDimensions should call refresh services and show toast' , fakeAsync ( ( ) => {
428+ tick ( ) ;
429+
430+ component . refreshDimensions ( true ) ;
431+ expect ( siMappingsService . refreshSageIntacctDimensions ) . toHaveBeenCalled ( ) ;
432+ expect ( siMappingsService . refreshFyleDimensions ) . toHaveBeenCalled ( ) ;
433+ expect ( toastService . displayToastMessage ) . toHaveBeenCalledWith (
434+ ToastSeverity . SUCCESS ,
435+ 'Syncing data dimensions from Sage Intacct'
436+ ) ;
437+ } ) ) ;
438+
439+ it ( 'removeFilter should reset form controls' , ( ) => {
440+ const formGroup = component [ 'formBuilder' ] . group ( {
441+ source_field : [ 'test' ] ,
442+ import_to_fyle : [ true ] ,
443+ destination_field : [ 'ACCOUNT' ]
444+ } ) ;
445+ spyOn ( component , 'addImportCodeField' ) ;
446+
447+ component . removeFilter ( formGroup ) ;
448+
449+ expect ( formGroup . get ( 'source_field' ) ?. value ) . toBe ( '' ) ;
450+ expect ( formGroup . get ( 'import_to_fyle' ) ?. value ) . toBeFalse ( ) ;
451+ expect ( component . addImportCodeField ) . toHaveBeenCalledWith (
452+ { checked : false } ,
453+ 'ACCOUNT'
454+ ) ;
455+ } ) ;
456+
457+ it ( 'hasDuplicateOption should check control validity' , ( ) => {
458+ const formGroup = component [ 'formBuilder' ] . group ( {
459+ testControl : [ 'value' ]
460+ } ) ;
461+ expect ( component . hasDuplicateOption ( formGroup , 0 , 'testControl' ) ) . toBeTrue ( ) ;
462+ } ) ;
463+
464+ it ( 'showOrHideAddButton should return correct visibility' , ( ) => {
465+ component . sageIntacctFields = [ ] ;
466+ expect ( component . showOrHideAddButton ( ) ) . toBeTrue ( ) ;
467+
468+ for ( let i = 0 ; i < component . importSettingsForm . controls . expenseFields . value . length ; i ++ ) {
469+ component . sageIntacctFields . push ( { } as ExpenseField ) ;
470+ }
471+ expect ( component . showOrHideAddButton ( ) ) . toBeFalse ( ) ;
472+ } ) ;
473+
474+ it ( 'showPreviewDialog should set dialog visibility' , ( ) => {
475+ component . showPreviewDialog ( true ) ;
476+ expect ( component . isDialogVisible ) . toBeTrue ( ) ;
477+
478+ component . showPreviewDialog ( false ) ;
479+ expect ( component . isDialogVisible ) . toBeFalse ( ) ;
480+ } ) ;
481+
482+ it ( 'addExpenseField should add new expense field' , ( ) => {
483+ const initialLength = component . expenseFieldsGetter . length ;
484+ component . addExpenseField ( ) ;
485+ expect ( component . expenseFieldsGetter . length ) . toBe ( initialLength + 1 ) ;
486+ } ) ;
487+
488+ it ( 'closeModel should reset form and close dialog' , ( ) => {
489+ component . customFieldForm = component [ 'formBuilder' ] . group ( {
490+ testField : [ 'value' ]
491+ } ) ;
492+ component . showDialog = true ;
493+
494+ component . closeModel ( ) ;
495+
496+ expect ( component . customFieldForm . get ( 'testField' ) ?. value ) . toBeNull ( ) ;
497+ expect ( component . showDialog ) . toBeFalse ( ) ;
498+ } ) ;
499+
500+ describe ( 'saveCustomField' , ( ) => {
501+
502+ it ( 'should handle dependent field creation' , ( ) => {
503+ component . customFieldForDependentField = true ;
504+ component . customFieldForm = component [ 'formBuilder' ] . group ( {
505+ attribute_type : [ 'Test Field' ] ,
506+ source_placeholder : [ 'Test Placeholder' ]
507+ } ) ;
508+ component [ 'isCostCodeFieldSelected' ] = true ;
509+ component . customFieldControl = component . importSettingsForm . get ( 'costCodes' ) as AbstractControl ;
510+
511+ component . saveCustomField ( ) ;
512+
513+ expect ( component . costCodeFieldOption . length ) . toBeGreaterThan ( 1 ) ;
514+ expect ( component . showDialog ) . toBeFalse ( ) ;
515+ } ) ;
516+
517+ it ( 'should handle non-dependent field creation' , ( ) => {
518+ component . customFieldForDependentField = false ;
519+ component . customFieldForm = component [ 'formBuilder' ] . group ( {
520+ attribute_type : [ 'Test Field' ] ,
521+ source_placeholder : [ 'Test Placeholder' ]
522+ } ) ;
523+ spyOn ( component . customFieldForm , 'reset' ) . and . callThrough ( ) ;
524+ component . customFieldControl = component [ 'createFormGroup' ] ( customFieldValue ) ;
525+
526+ component . saveCustomField ( ) ;
527+
528+ expect ( component . customField ) . toEqual ( customField ) ;
529+ expect ( component . fyleFields [ component . fyleFields . length - 2 ] ) . toEqual ( customField ) ;
530+ expect ( component . fyleFields [ component . fyleFields . length - 1 ] ) . toEqual ( component . customFieldOption [ 0 ] ) ;
531+ expect ( component . customFieldForm . reset ) . toHaveBeenCalled ( ) ;
532+ } ) ;
533+ } ) ;
534+
535+ it ( 'updateDependentField should handle dependent field updates' , ( ) => {
536+ component . importSettingsForm . patchValue ( {
537+ isDependentImportEnabled : true
538+ } ) ;
539+
540+ component . updateDependentField ( 'DEPARTMENT' , true ) ;
541+ expect ( component . importSettingsForm . get ( 'isDependentImportEnabled' ) ?. value ) . toBeFalse ( ) ;
542+
543+ component . updateDependentField ( 'PROJECT' , true ) ;
544+ expect ( component . importSettingsForm . get ( 'isDependentImportEnabled' ) ?. value ) . toBeFalse ( ) ;
545+ } ) ;
546+
547+ it ( 'onDropdownChange should handle dependent fields' , ( ) => {
548+ const expenseFieldsArray = component . importSettingsForm . get ( 'expenseFields' ) as FormArray ;
549+ expenseFieldsArray . push ( component [ 'formBuilder' ] . group ( {
550+ import_to_fyle : [ true ] ,
551+ destination_field : [ 'TEST_FIELD' ]
552+ } ) ) ;
553+
554+ component . fyleFields = [ {
555+ attribute_type : 'DEPENDENT_FIELD' ,
556+ is_dependent : true
557+ } as ExpenseField ] ;
558+
559+ component . onDropdownChange ( { value : 'DEPENDENT_FIELD' } , 0 ) ;
560+
561+ expect ( expenseFieldsArray . at ( 0 ) . get ( 'import_to_fyle' ) ?. value ) . toBeFalse ( ) ;
562+ expect ( expenseFieldsArray . at ( 0 ) . get ( 'import_to_fyle' ) ?. disabled ) . toBeTrue ( ) ;
563+ } ) ;
564+
565+ it ( 'acceptDependentFieldWarning should handle warning being rejected' , ( ) => {
566+ const expenseFieldsArray = component . importSettingsForm . get ( 'expenseFields' ) as FormArray ;
567+ const newExpenseField = component [ 'formBuilder' ] . group ( {
568+ source_field : [ MappingSourceField . PROJECT ] ,
569+ destination_field : [ 'TEST_FIELD' ] ,
570+ import_to_fyle : [ false ] ,
571+ is_custom : [ false ]
572+ } ) ;
573+ expenseFieldsArray . push ( newExpenseField ) ;
574+
575+ component . acceptDependentFieldWarning ( false ) ;
576+
577+ expect ( newExpenseField . get ( 'import_to_fyle' ) ?. value ) . toBeTrue ( ) ;
578+ expect ( component . importSettingsForm . get ( 'isDependentImportEnabled' ) ?. value ) . toBeTrue ( ) ;
579+ expect ( component . importSettingsForm . get ( 'costCodes' ) ?. disabled ) . toBeTrue ( ) ;
580+ expect ( component . importSettingsForm . get ( 'costTypes' ) ?. disabled ) . toBeTrue ( ) ;
581+ } ) ;
582+
583+ it ( 'showWarningForDependentFields should show warning dialog' , ( ) => {
584+ const formGroup = component [ 'formBuilder' ] . group ( {
585+ source_field : [ MappingSourceField . PROJECT ] ,
586+ destination_field : [ 'TEST_FIELD' ]
587+ } ) ;
588+
589+ component . costCodeFieldOption = [ { attribute_type : 'existing_field' } as ExpenseField ] ;
590+ component . costTypeFieldOption = [ { attribute_type : 'existing_field' } as ExpenseField ] ;
591+
592+ component . showWarningForDependentFields ( { checked : false } , formGroup ) ;
593+
594+ expect ( component . showDependentFieldWarning ) . toBeTrue ( ) ;
595+ } ) ;
596+ } ) ;
391597} ) ;
0 commit comments