Skip to content

Commit 6244190

Browse files
test: intacct advanced settings save functionality (#1026)
* test: intacct advanced settings initialization * test: intacct advanced settings watchers * test: intacct advanced settings save functionality
1 parent f4767e6 commit 6244190

File tree

1 file changed

+157
-47
lines changed

1 file changed

+157
-47
lines changed
Lines changed: 157 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
22
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
33
import { provideRouter, Router } from '@angular/router';
4-
import { of } from 'rxjs';
4+
import { of, throwError } from 'rxjs';
55
import { IntacctAdvancedSettingsComponent } from './intacct-advanced-settings.component';
66
import { SiAdvancedSettingService } from 'src/app/core/services/si/si-configuration/si-advanced-setting.service';
77
import { 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
1212
import { adminEmails, advancedSettings, configurationForAddvancedSettings, expenseFilter, groupedAttributes } from '../../intacct.fixture';
1313
import { ExpenseFilterResponse } from 'src/app/core/models/intacct/intacct-configuration/advanced-settings.model';
1414
import { 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

1618
describe('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

Comments
 (0)