Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable dot-notation */
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormArray, FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { FormArray, FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
Comment on lines +1 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Limit the Scope of ESLint Disables

The /* eslint-disable dot-notation */ directive disables the dot-notation rule for the entire file. Consider limiting its scope to only the necessary lines to avoid suppressing linting for unrelated code. This helps maintain code quality by ensuring that other parts of the file still adhere to linting rules.

import { provideRouter, Router, RouterModule } from '@angular/router';
import { of } from 'rxjs';
import { of, throwError } from 'rxjs';
import { IntacctC1ImportSettingsComponent } from './intacct-c1-import-settings.component';
import { SiImportSettingService } from 'src/app/core/services/si/si-configuration/si-import-setting.service';
import { SiMappingsService } from 'src/app/core/services/si/si-core/si-mappings.service';
Expand All @@ -20,12 +21,14 @@ import {
settingsWithDependentFields,
sageIntacctFieldsSortedByPriorityForC1,
importSettingsWithProjectMapping,
expenseFieldsExpectedForC1
expenseFieldsExpectedForC1,
blankMapping
} from '../../intacct.fixture';
import { IntacctConfiguration } from 'src/app/core/models/db/configuration.model';
import { ImportSettingGet } from 'src/app/core/models/intacct/intacct-configuration/import-settings.model';
import { ImportSettingGet, ImportSettingPost, ImportSettings } from 'src/app/core/models/intacct/intacct-configuration/import-settings.model';
import { SharedModule } from 'src/app/shared/shared.module';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { IntacctOnboardingState, IntacctUpdateEvent, Page, ProgressPhase, ToastSeverity, TrackingApp } from 'src/app/core/models/enum/enum.model';

describe('IntacctC1ImportSettingsComponent', () => {
let component: IntacctC1ImportSettingsComponent;
Expand All @@ -48,12 +51,12 @@ describe('IntacctC1ImportSettingsComponent', () => {
'refreshSageIntacctDimensions',
'refreshFyleDimensions'
]);
const importSettingServiceSpy = jasmine.createSpyObj('SiImportSettingService', ['getImportSettings']);
const importSettingServiceSpy = jasmine.createSpyObj('SiImportSettingService', ['getImportSettings', 'postImportSettings']);
const connectorServiceSpy = jasmine.createSpyObj('IntacctConnectorService', ['getLocationEntityMapping']);
const storageServiceSpy = jasmine.createSpyObj('StorageService', ['get']);
const toastServiceSpy = jasmine.createSpyObj('IntegrationsToastService', ['displayToastMessage']);
const trackingServiceSpy = jasmine.createSpyObj('TrackingService', ['trackTimeSpent']);
const workspaceServiceSpy = jasmine.createSpyObj('SiWorkspaceService', ['getIntacctOnboardingState']);
const trackingServiceSpy = jasmine.createSpyObj('TrackingService', ['trackTimeSpent', 'intacctUpdateEvent', 'integrationsOnboardingCompletion']);
const workspaceServiceSpy = jasmine.createSpyObj('SiWorkspaceService', ['getIntacctOnboardingState', 'setIntacctOnboardingState']);
const helperServiceSpy = jasmine.createSpyObj('HelperService', [
'disableFormField',
'enableFormField',
Expand Down Expand Up @@ -166,4 +169,161 @@ describe('IntacctC1ImportSettingsComponent', () => {
expect(component.importSettingsForm.get('costTypes')).toBeDefined();
});
});

describe('Save', () => {
beforeEach(() => {
importSettingService.postImportSettings.and.returnValue(of(importSettings));
});

it('should handle post onboarding state', () => {
component.ngOnInit();

workspaceService.getIntacctOnboardingState.and.returnValue(IntacctOnboardingState.COMPLETE);
component.isOnboarding = false;

component.save();

expect(importSettingService.postImportSettings).toHaveBeenCalled();
expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.SUCCESS, 'Import settings saved successfully');
expect(trackingService.trackTimeSpent).toHaveBeenCalledWith(TrackingApp.INTACCT, Page.IMPORT_SETTINGS_INTACCT, jasmine.any(Date));
expect(trackingService.intacctUpdateEvent).toHaveBeenCalledWith(
IntacctUpdateEvent.ADVANCED_SETTINGS_INTACCT,
{
phase: ProgressPhase.POST_ONBOARDING,
oldState: importSettings,
newState: importSettings
}
);
expect(component.saveInProgress).toBeFalse();
expect(router.navigate).not.toHaveBeenCalled();
});

it('should handle onboarding state', () => {
component.ngOnInit();

workspaceService.getIntacctOnboardingState.and.returnValue(IntacctOnboardingState.IMPORT_SETTINGS);
component.isOnboarding = true;

component.save();

expect(importSettingService.postImportSettings).toHaveBeenCalled();
expect(trackingService.integrationsOnboardingCompletion).toHaveBeenCalledWith(TrackingApp.INTACCT, IntacctOnboardingState.IMPORT_SETTINGS, 3, jasmine.any(Object));
expect(workspaceService.setIntacctOnboardingState).toHaveBeenCalledWith(IntacctOnboardingState.ADVANCED_CONFIGURATION);
expect(router.navigate).toHaveBeenCalledWith(['/integrations/intacct/onboarding/advanced_settings']);
});

it('should handle save error', () => {
component.ngOnInit();

importSettingService.postImportSettings.and.returnValue(throwError(() => new Error('Error')));

component.save();

expect(importSettingService.postImportSettings).toHaveBeenCalled();
expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.ERROR, 'Error saving import settings, please try again later');
expect(component.saveInProgress).toBeFalse();
});
});

describe('Watchers', () => {
let isDependentImportEnabledValueChangeSpy: jasmine.Spy;
let blankExpenseField: FormGroup;
let costCodesValueChangeSubscription: jasmine.Spy;
let costTypesValueChangeSubscription: jasmine.Spy;

beforeEach(() => {
component.ngOnInit();

isDependentImportEnabledValueChangeSpy = spyOn(component.importSettingsForm.controls.isDependentImportEnabled.valueChanges, 'subscribe').and.callThrough();
blankExpenseField = component['createFormGroup'](blankMapping);
costCodesValueChangeSubscription = spyOn(component.importSettingsForm.controls.costCodes.valueChanges, 'subscribe');
costTypesValueChangeSubscription = spyOn(component.importSettingsForm.controls.costTypes.valueChanges, 'subscribe');

spyOn(blankExpenseField.valueChanges, 'subscribe').and.callThrough();
});

describe('dependentFieldWatchers', () => {
beforeEach(() => {
component['dependentFieldWatchers']();
});

it('should setup watchers for dependent fields', () => {
expect(component.importSettingsForm.controls.isDependentImportEnabled.valueChanges.subscribe).toHaveBeenCalled();
expect(component.importSettingsForm.controls.costCodes.valueChanges.subscribe).toHaveBeenCalled();
expect(component.importSettingsForm.controls.costTypes.valueChanges.subscribe).toHaveBeenCalled();
});

it('should handle isDependentImportEnabled being set', () => {
component.importSettingsForm.get('isDependentImportEnabled')?.setValue(true);

expect(helperService.enableFormField).toHaveBeenCalledWith(component.importSettingsForm, 'costCodes');
expect(helperService.enableFormField).toHaveBeenCalledWith(component.importSettingsForm, 'costTypes');
expect(helperService.markControllerAsRequired).toHaveBeenCalledWith(component.importSettingsForm, 'costCodes');
expect(helperService.markControllerAsRequired).toHaveBeenCalledWith(component.importSettingsForm, 'costTypes');
expect(component.dependentImportFields[0].isDisabled).toBeFalse();
expect(component.dependentImportFields[1].isDisabled).toBeFalse();
});

it('should handle isDependentImportEnabled being unset', () => {
component.importSettingsForm.get('isDependentImportEnabled')?.setValue(false);

expect(helperService.disableFormField).toHaveBeenCalledWith(component.importSettingsForm, 'costCodes');
expect(helperService.disableFormField).toHaveBeenCalledWith(component.importSettingsForm, 'costTypes');
expect(helperService.clearValidatorAndResetValue).toHaveBeenCalledWith(component.importSettingsForm, 'costCodes');
expect(helperService.clearValidatorAndResetValue).toHaveBeenCalledWith(component.importSettingsForm, 'costTypes');
expect(component.dependentImportFields[0].isDisabled).toBeTrue();
expect(component.dependentImportFields[1].isDisabled).toBeTrue();
});
});

describe('dependentCostFieldsWatchers', () => {
beforeEach(() => {
component['dependentCostFieldsWatchers']('costCodes');
component['dependentCostFieldsWatchers']('costTypes');
});

it('should setup watchers for cost fields', () => {
expect(component.importSettingsForm.controls.costCodes.valueChanges.subscribe).toHaveBeenCalled();
expect(component.importSettingsForm.controls.costTypes.valueChanges.subscribe).toHaveBeenCalled();
});

it('should handle custom field selection for costCodes', () => {
component.importSettingsForm.controls.costCodes.setValue({ attribute_type: 'custom_field' });

expect(component.customFieldType).toBe('costCodes');
expect(component.customFieldControl).toBe(component.importSettingsForm.controls.costCodes);
});

it('should handle custom field selection for costTypes', () => {
component.importSettingsForm.controls.costTypes.setValue({ attribute_type: 'custom_field' });

expect(component.customFieldType).toBe('costTypes');
expect(component.customFieldControl).toBe(component.importSettingsForm.controls.costTypes);
});

it('should handle non-custom field selection', () => {
component.importSettingsForm.controls.costCodes.setValue({ attribute_type: 'some_field' });
expect(component.dependentImportFields[0].isDisabled).toBeTrue();
});
});

describe('importSettingWatcher', () => {
beforeEach(() => {
(component.importSettingsForm.get('expenseFields') as FormArray).controls = [blankExpenseField];
component['importSettingWatcher']();
});

it('should setup watchers for expense fields', () => {
expect(blankExpenseField.valueChanges.subscribe).toHaveBeenCalled();
});

it('should handle custom field selection in expense fields', () => {
spyOn(blankExpenseField, 'patchValue').and.callThrough();
blankExpenseField.patchValue({ source_field: 'custom_field' });

expect(component.customFieldControl).toBe(blankExpenseField);
expect(blankExpenseField.patchValue).toHaveBeenCalledWith(blankMapping);
});
});
});
});
12 changes: 10 additions & 2 deletions src/app/integrations/intacct/intacct.fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ExpenseGroup, ExpenseGroupDescription, ExpenseGroupResponse } from 'src
import { Paginator } from 'src/app/core/models/misc/paginator.model';
import { SkipExportLogResponse } from "src/app/core/models/intacct/db/expense-group.model";
import { ExpenseField } from 'src/app/core/models/intacct/db/expense-field.model';
import { DependentFieldSetting, ImportSettingGet } from 'src/app/core/models/intacct/intacct-configuration/import-settings.model';
import { DependentFieldSetting, ImportSettingGet, MappingSetting } from 'src/app/core/models/intacct/intacct-configuration/import-settings.model';
import { LocationEntityMapping } from 'src/app/core/models/intacct/db/location-entity-mapping.model';
import { GroupedDestinationAttribute } from "src/app/core/models/intacct/db/destination-attribute.model";
import { IntacctConfiguration } from "src/app/core/models/db/configuration.model";
Expand Down Expand Up @@ -929,4 +929,12 @@ export const expenseFieldsExpectedForC1 = [
is_custom: false,
source_placeholder: null
}
];
];

export const blankMapping: MappingSetting = {
source_field: '',
destination_field: '',
import_to_fyle: true,
is_custom: false,
source_placeholder: null
};
Loading