11import { ComponentFixture , fakeAsync , TestBed , tick } from '@angular/core/testing' ;
22import { FormBuilder , ReactiveFormsModule , Validators } from '@angular/forms' ;
33import { provideRouter , Router } from '@angular/router' ;
4- import { of } from 'rxjs' ;
4+ import { of , throwError } from 'rxjs' ;
55import { IntacctAdvancedSettingsComponent } from './intacct-advanced-settings.component' ;
66import { SiAdvancedSettingService } from 'src/app/core/services/si/si-configuration/si-advanced-setting.service' ;
77import { IntegrationsToastService } from 'src/app/core/services/common/integrations-toast.service' ;
@@ -12,6 +12,8 @@ import { SkipExportComponent } from 'src/app/shared/components/si/helper/skip-ex
1212import { adminEmails , advancedSettings , configurationForAddvancedSettings , expenseFilter , groupedAttributes } from '../../intacct.fixture' ;
1313import { ExpenseFilterResponse } from 'src/app/core/models/intacct/intacct-configuration/advanced-settings.model' ;
1414import { SharedModule } from 'src/app/shared/shared.module' ;
15+ import { IntacctOnboardingState , PaymentSyncDirection , ToastSeverity } from 'src/app/core/models/enum/enum.model' ;
16+ import { SkipExport } from 'src/app/core/models/intacct/misc/skip-export.model' ;
1517
1618describe ( 'IntacctAdvancedSettingsComponent' , ( ) => {
1719 let component : IntacctAdvancedSettingsComponent ;
@@ -25,14 +27,20 @@ describe('IntacctAdvancedSettingsComponent', () => {
2527
2628
2729 beforeEach ( async ( ) => {
28- const advancedSettingsServiceSpy = jasmine . createSpyObj ( 'SiAdvancedSettingService' , [ 'getAdvancedSettings' , 'getExpenseFilter' , 'getAdditionalEmails' ] ) ;
30+ const advancedSettingsServiceSpy = jasmine . createSpyObj ( 'SiAdvancedSettingService' , [
31+ 'getAdvancedSettings' ,
32+ 'getExpenseFilter' ,
33+ 'getAdditionalEmails' ,
34+ 'postAdvancedSettings' ,
35+ 'deleteExpenseFilter'
36+ ] ) ;
2937 const toastServiceSpy = jasmine . createSpyObj ( 'IntegrationsToastService' , [ 'displayToastMessage' ] ) ;
3038 const trackingServiceSpy = jasmine . createSpyObj ( 'TrackingService' , [ 'trackTimeSpent' , 'integrationsOnboardingCompletion' , 'intacctUpdateEvent' ] ) ;
3139 const workspaceServiceSpy = jasmine . createSpyObj ( 'SiWorkspaceService' , [ 'getIntacctOnboardingState' , 'setIntacctOnboardingState' ] ) ;
3240 const mappingServiceSpy = jasmine . createSpyObj ( 'SiMappingsService' , [ 'getGroupedDestinationAttributes' , 'getConfiguration' , 'refreshSageIntacctDimensions' , 'refreshFyleDimensions' ] ) ;
3341 await TestBed . configureTestingModule ( {
34- declarations : [ IntacctAdvancedSettingsComponent , SkipExportComponent ] ,
35- imports : [ SharedModule , ReactiveFormsModule ] ,
42+ declarations : [ IntacctAdvancedSettingsComponent , SkipExportComponent ] ,
43+ imports : [ SharedModule , ReactiveFormsModule ] ,
3644 providers : [
3745 FormBuilder ,
3846 { provide : SiAdvancedSettingService , useValue : advancedSettingsServiceSpy } ,
@@ -50,6 +58,7 @@ describe('IntacctAdvancedSettingsComponent', () => {
5058 workspaceService = TestBed . inject ( SiWorkspaceService ) as jasmine . SpyObj < SiWorkspaceService > ;
5159 mappingService = TestBed . inject ( SiMappingsService ) as jasmine . SpyObj < SiMappingsService > ;
5260 router = TestBed . inject ( Router ) ;
61+ spyOn ( router , 'navigate' ) ;
5362
5463 advancedSettingsService . getAdditionalEmails . and . returnValue ( of ( adminEmails ) ) ;
5564 advancedSettingsService . getAdvancedSettings . and . returnValue ( of ( advancedSettings ) ) ;
@@ -65,55 +74,156 @@ describe('IntacctAdvancedSettingsComponent', () => {
6574 expect ( component ) . toBeTruthy ( ) ;
6675 } ) ;
6776
68- it ( 'should initialize with correct data' , fakeAsync ( ( ) => {
69- fixture . detectChanges ( ) ;
70- tick ( ) ;
71-
72- expect ( component . isLoading ) . toBeFalse ( ) ;
73- expect ( component . adminEmails ) . toEqual ( adminEmails . concat ( advancedSettings . workspace_schedules . additional_email_options ) ) ;
74- expect ( component . advancedSettings ) . toEqual ( advancedSettings ) ;
75- expect ( component . sageIntacctLocations ) . toEqual ( groupedAttributes . LOCATION ) ;
76- expect ( component . sageIntacctDefaultItem ) . toEqual ( groupedAttributes . ITEM ) ;
77- expect ( component . sageIntacctDepartments ) . toEqual ( groupedAttributes . DEPARTMENT ) ;
78- expect ( component . sageIntacctProjects ) . toEqual ( groupedAttributes . PROJECT ) ;
79- expect ( component . sageIntacctClasses ) . toEqual ( groupedAttributes . CLASS ) ;
80- expect ( component . sageIntacctPaymentAccount ) . toEqual ( groupedAttributes . PAYMENT_ACCOUNT ) ;
81- expect ( component . reimbursableExpense ) . toEqual ( configurationForAddvancedSettings . reimbursable_expenses_object ) ;
82- expect ( component . corporateCreditCardExpense ) . toEqual ( configurationForAddvancedSettings . corporate_credit_card_expenses_object ) ;
83- expect ( component . importVendorsAsMerchants ) . toEqual ( configurationForAddvancedSettings . import_vendors_as_merchants ) ;
84- expect ( component . useMerchantInJournalLine ) . toEqual ( configurationForAddvancedSettings . use_merchant_in_journal_line ) ;
85- expect ( component . employeeFieldMapping ) . toEqual ( configurationForAddvancedSettings . employee_field_mapping ) ;
86- } ) ) ;
87-
88- it ( 'should initialize forms correctly' , ( ) => {
89- fixture . detectChanges ( ) ;
90-
91- expect ( component . advancedSettingsForm ) . toBeDefined ( ) ;
92- expect ( component . skipExportForm ) . toBeDefined ( ) ;
93-
94- expect ( component . advancedSettingsForm . get ( 'exportSchedule' ) ?. value ) . toBeTrue ( ) ;
95- expect ( component . advancedSettingsForm . get ( 'exportScheduleFrequency' ) ?. value ) . toBe ( 12 ) ;
96- expect ( component . advancedSettingsForm . get ( 'setDescriptionField' ) ?. value ) . toEqual ( [ 'employee_email' , 'merchant' , 'purpose' ] ) ;
77+ describe ( 'Initialization' , ( ) => {
78+ it ( 'should initialize with correct data' , fakeAsync ( ( ) => {
79+ fixture . detectChanges ( ) ;
80+ tick ( ) ;
81+
82+ expect ( component . isLoading ) . toBeFalse ( ) ;
83+ expect ( component . adminEmails ) . toEqual ( adminEmails . concat ( advancedSettings . workspace_schedules . additional_email_options ) ) ;
84+ expect ( component . advancedSettings ) . toEqual ( advancedSettings ) ;
85+ expect ( component . sageIntacctLocations ) . toEqual ( groupedAttributes . LOCATION ) ;
86+ expect ( component . sageIntacctDefaultItem ) . toEqual ( groupedAttributes . ITEM ) ;
87+ expect ( component . sageIntacctDepartments ) . toEqual ( groupedAttributes . DEPARTMENT ) ;
88+ expect ( component . sageIntacctProjects ) . toEqual ( groupedAttributes . PROJECT ) ;
89+ expect ( component . sageIntacctClasses ) . toEqual ( groupedAttributes . CLASS ) ;
90+ expect ( component . sageIntacctPaymentAccount ) . toEqual ( groupedAttributes . PAYMENT_ACCOUNT ) ;
91+ expect ( component . reimbursableExpense ) . toEqual ( configurationForAddvancedSettings . reimbursable_expenses_object ) ;
92+ expect ( component . corporateCreditCardExpense ) . toEqual ( configurationForAddvancedSettings . corporate_credit_card_expenses_object ) ;
93+ expect ( component . importVendorsAsMerchants ) . toEqual ( configurationForAddvancedSettings . import_vendors_as_merchants ) ;
94+ expect ( component . useMerchantInJournalLine ) . toEqual ( configurationForAddvancedSettings . use_merchant_in_journal_line ) ;
95+ expect ( component . employeeFieldMapping ) . toEqual ( configurationForAddvancedSettings . employee_field_mapping ) ;
96+ } ) ) ;
97+
98+ it ( 'should initialize forms correctly' , ( ) => {
99+ fixture . detectChanges ( ) ;
100+
101+ expect ( component . advancedSettingsForm ) . toBeDefined ( ) ;
102+ expect ( component . skipExportForm ) . toBeDefined ( ) ;
103+
104+ expect ( component . advancedSettingsForm . get ( 'exportSchedule' ) ?. value ) . toBeTrue ( ) ;
105+ expect ( component . advancedSettingsForm . get ( 'exportScheduleFrequency' ) ?. value ) . toBe ( 12 ) ;
106+ expect ( component . advancedSettingsForm . get ( 'setDescriptionField' ) ?. value ) . toEqual ( [ 'employee_email' , 'merchant' , 'purpose' ] ) ;
107+ } ) ;
108+
109+ it ( 'should handle onboarding state correctly' , ( ) => {
110+ spyOnProperty ( router , 'url' ) . and . returnValue ( '/integrations/intacct/onboarding/advanced_settings' ) ;
111+ fixture . detectChanges ( ) ;
112+
113+ expect ( component . isOnboarding ) . toBeTrue ( ) ;
114+ } ) ;
115+
116+ it ( 'should handle non-onboarding state correctly' , ( ) => {
117+ spyOnProperty ( router , 'url' ) . and . returnValue ( '/integrations/intacct/advanced_settings' ) ;
118+ fixture . detectChanges ( ) ;
119+
120+ expect ( component . isOnboarding ) . toBeFalse ( ) ;
121+ } ) ;
122+
123+ it ( 'should create memo preview correctly' , ( ) => {
124+ fixture . detectChanges ( ) ;
125+
126+ const expectedPreview = '[email protected] - Pizza Hut - Client Meeting' ; 127+ expect ( component . memoPreviewText ) . toBe ( expectedPreview ) ;
128+ } ) ;
97129 } ) ;
98130
99- it ( 'should handle onboarding state correctly' , ( ) => {
100- spyOnProperty ( router , 'url' ) . and . returnValue ( '/integrations/intacct/onboarding/advanced_settings' ) ;
101- fixture . detectChanges ( ) ;
131+ describe ( 'Watchers' , ( ) => {
132+ beforeEach ( ( ) => {
133+ fixture . detectChanges ( ) ;
134+ } ) ;
102135
103- expect ( component . isOnboarding ) . toBeTrue ( ) ;
104- } ) ;
136+ it ( 'should update memo preview when setDescriptionField changes' , fakeAsync ( ( ) => {
137+ const newMemoStructure = [ 'category' , 'purpose' , 'spent_on' ] ;
138+ component . advancedSettingsForm . get ( 'setDescriptionField' ) ?. setValue ( newMemoStructure ) ;
139+ tick ( ) ;
105140
106- it ( 'should handle non-onboarding state correctly' , ( ) => {
107- spyOnProperty ( router , 'url' ) . and . returnValue ( '/integrations/intacct/advanced_settings' ) ;
108- fixture . detectChanges ( ) ;
141+ expect ( component . memoStructure ) . toEqual ( newMemoStructure ) ;
142+ expect ( component . memoPreviewText ) . toBe ( 'Client Meeting - Meals and Entertainment - ' + new Date ( Date . now ( ) ) . toLocaleDateString ( ) ) ;
143+ } ) ) ;
109144
110- expect ( component . isOnboarding ) . toBeFalse ( ) ;
111- } ) ;
145+ it ( 'should update defaultPaymentAccount validators when autoSyncPayments changes' , fakeAsync ( ( ) => {
146+ component . advancedSettingsForm . get ( 'autoSyncPayments' ) ?. setValue ( PaymentSyncDirection . FYLE_TO_INTACCT ) ;
147+ tick ( ) ;
148+
149+ expect ( component . advancedSettingsForm . get ( 'defaultPaymentAccount' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
112150
113- it ( 'should create memo preview correctly' , ( ) => {
114- fixture . detectChanges ( ) ;
151+ component . advancedSettingsForm . get ( 'autoSyncPayments' ) ?. setValue ( null ) ;
152+ tick ( ) ;
153+
154+ expect ( component . advancedSettingsForm . get ( 'defaultPaymentAccount' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
155+ } ) ) ;
156+ } ) ;
115157
116- const expectedPreview = '[email protected] - Pizza Hut - Client Meeting' ; 117- expect ( component . memoPreviewText ) . toBe ( expectedPreview ) ;
158+ describe ( 'Save' , ( ) => {
159+ beforeEach ( fakeAsync ( ( ) => {
160+ fixture . detectChanges ( ) ;
161+ advancedSettingsService . deleteExpenseFilter . and . returnValue ( of ( { } as SkipExport ) ) ;
162+ } ) ) ;
163+
164+ it ( 'should handle save advanced settings during onboarding' , fakeAsync ( ( ) => {
165+ const mockResponse = { ...advancedSettings } ;
166+ advancedSettingsService . postAdvancedSettings . and . returnValue ( of ( mockResponse ) ) ;
167+ workspaceService . getIntacctOnboardingState . and . returnValue ( IntacctOnboardingState . ADVANCED_CONFIGURATION ) ;
168+
169+ component . skipExportChild = { saveSkipExportFields : jasmine . createSpy ( 'saveSkipExportFields' ) } as any ;
170+ component . advancedSettingsForm . get ( 'skipSelectiveExpenses' ) ?. setValue ( true ) ;
171+ component . isOnboarding = true ;
172+
173+ component . save ( ) ;
174+ tick ( ) ;
175+
176+ expect ( advancedSettingsService . postAdvancedSettings ) . toHaveBeenCalled ( ) ;
177+ expect ( component . skipExportChild . saveSkipExportFields ) . toHaveBeenCalled ( ) ;
178+ expect ( toastService . displayToastMessage ) . toHaveBeenCalledWith ( ToastSeverity . SUCCESS , 'Advanced settings saved successfully' ) ;
179+ expect ( trackingService . trackTimeSpent ) . toHaveBeenCalled ( ) ;
180+ expect ( trackingService . integrationsOnboardingCompletion ) . toHaveBeenCalled ( ) ;
181+ expect ( workspaceService . setIntacctOnboardingState ) . toHaveBeenCalledWith ( IntacctOnboardingState . COMPLETE ) ;
182+ expect ( router . navigate ) . toHaveBeenCalledWith ( [ '/integrations/intacct/onboarding/done' ] ) ;
183+ } ) ) ;
184+
185+ it ( 'should handle save when skipSelectiveExpenses is false' , fakeAsync ( ( ) => {
186+ const mockResponse = { ...advancedSettings } ;
187+ advancedSettingsService . postAdvancedSettings . and . returnValue ( of ( mockResponse ) ) ;
188+ advancedSettingsService . deleteExpenseFilter . and . returnValue ( of ( { } as SkipExport ) ) ;
189+ workspaceService . getIntacctOnboardingState . and . returnValue ( IntacctOnboardingState . ADVANCED_CONFIGURATION ) ;
190+
191+ component . advancedSettingsForm . get ( 'skipSelectiveExpenses' ) ?. setValue ( false ) ;
192+
193+ component . save ( ) ;
194+ tick ( ) ;
195+
196+ expect ( advancedSettingsService . postAdvancedSettings ) . toHaveBeenCalled ( ) ;
197+ expect ( advancedSettingsService . deleteExpenseFilter ) . toHaveBeenCalledTimes ( 2 ) ;
198+ expect ( advancedSettingsService . deleteExpenseFilter ) . toHaveBeenCalledWith ( 1 ) ;
199+ expect ( advancedSettingsService . deleteExpenseFilter ) . toHaveBeenCalledWith ( 2 ) ;
200+ expect ( toastService . displayToastMessage ) . toHaveBeenCalledWith ( ToastSeverity . SUCCESS , 'Advanced settings saved successfully' ) ;
201+ } ) ) ;
202+
203+ it ( 'should handle save when not in onboarding state' , fakeAsync ( ( ) => {
204+ const mockResponse = { ...advancedSettings } ;
205+ advancedSettingsService . postAdvancedSettings . and . returnValue ( of ( mockResponse ) ) ;
206+ workspaceService . getIntacctOnboardingState . and . returnValue ( IntacctOnboardingState . COMPLETE ) ;
207+
208+ component . isOnboarding = false ;
209+ component . save ( ) ;
210+ tick ( ) ;
211+
212+ expect ( advancedSettingsService . postAdvancedSettings ) . toHaveBeenCalled ( ) ;
213+ expect ( trackingService . intacctUpdateEvent ) . toHaveBeenCalled ( ) ;
214+ expect ( router . navigate ) . not . toHaveBeenCalled ( ) ;
215+ } ) ) ;
216+
217+ it ( 'should handle error when saving advanced settings' , fakeAsync ( ( ) => {
218+ const getError = ( ) => new Error ( 'Error' ) ;
219+ advancedSettingsService . postAdvancedSettings . and . returnValue ( throwError ( getError ) ) ;
220+
221+ component . save ( ) ;
222+ tick ( ) ;
223+
224+ expect ( advancedSettingsService . postAdvancedSettings ) . toHaveBeenCalled ( ) ;
225+ expect ( toastService . displayToastMessage ) . toHaveBeenCalledWith ( ToastSeverity . ERROR , 'Error saving advanced settings, please try again later' ) ;
226+ expect ( component . saveInProgress ) . toBeFalse ( ) ;
227+ } ) ) ;
118228 } ) ;
119229} ) ;
0 commit comments