From 63d2f38a94292ea68bf2bc0ae6e678069e9df0d2 Mon Sep 17 00:00:00 2001 From: Viswas Date: Fri, 4 Oct 2024 04:22:17 +0530 Subject: [PATCH 1/2] test: intacct export settings initialization --- .../intacct-dashboard.component.spec.ts | 2 +- .../intacct-export-settings.component.spec.ts | 121 ++++- .../integrations/intacct/intacct.fixture.ts | 412 +++++++++++++++++- 3 files changed, 512 insertions(+), 23 deletions(-) diff --git a/src/app/integrations/intacct/intacct-main/intacct-dashboard/intacct-dashboard.component.spec.ts b/src/app/integrations/intacct/intacct-main/intacct-dashboard/intacct-dashboard.component.spec.ts index 17ddaf49f..485ae6cd2 100644 --- a/src/app/integrations/intacct/intacct-main/intacct-dashboard/intacct-dashboard.component.spec.ts +++ b/src/app/integrations/intacct/intacct-main/intacct-dashboard/intacct-dashboard.component.spec.ts @@ -10,7 +10,7 @@ import { SiExportSettingService } from 'src/app/core/services/si/si-configuratio import { MinimalUser } from 'src/app/core/models/db/user.model'; import { of } from 'rxjs'; import { AccountingExportSummary, AccountingExportSummaryModel } from 'src/app/core/models/db/accounting-export-summary.model'; -import { mockAccountingExportSummary, mockCompletedTasksWithFailures, mockConfiguration, mockErrors, mockExportableAccountingExportIds, mockExportSettingGet, mockExportSettings, mockTasksInProgress } from '../../intacct.fixture'; +import { mockAccountingExportSummary, mockCompletedTasksWithFailures, mockConfiguration, mockErrors, mockExportableAccountingExportIds, mockExportSettingGet, mockTasksInProgress } from '../../intacct.fixture'; import { SharedModule } from 'src/app/shared/shared.module'; import { Error } from 'src/app/core/models/db/error.model'; import { AccountingErrorType, AppName, CCCImportState, IntacctCategoryDestination, ReimbursableImportState, TaskLogState } from 'src/app/core/models/enum/enum.model'; diff --git a/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts b/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts index 6943290a6..4ff7c568d 100644 --- a/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts +++ b/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts @@ -1,23 +1,128 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { provideRouter, Router, RouterModule } from '@angular/router'; +import { of, throwError } from 'rxjs'; import { IntacctExportSettingsComponent } from './intacct-export-settings.component'; +import { SiExportSettingService } from 'src/app/core/services/si/si-configuration/si-export-setting.service'; +import { SiMappingsService } from 'src/app/core/services/si/si-core/si-mappings.service'; +import { SiWorkspaceService } from 'src/app/core/services/si/si-core/si-workspace.service'; +import { IntegrationsToastService } from 'src/app/core/services/common/integrations-toast.service'; +import { TrackingService } from 'src/app/core/services/integration/tracking.service'; +import { mockExportSettings, mockPaginatedDestinationAttributes } from '../../intacct.fixture'; +import { IntacctOnboardingState, Page, ToastSeverity } from 'src/app/core/models/enum/enum.model'; +import { ExportSettingOptionSearch } from 'src/app/core/models/common/export-settings.model'; +import { IntacctDestinationAttribute, PaginatedintacctDestinationAttribute } from 'src/app/core/models/intacct/db/destination-attribute.model'; +import { SharedModule } from 'src/app/shared/shared.module'; -xdescribe('IntacctExportSettingsComponent', () => { +describe('IntacctExportSettingsComponent', () => { let component: IntacctExportSettingsComponent; let fixture: ComponentFixture; + let exportSettingService: jasmine.SpyObj; + let mappingService: jasmine.SpyObj; + let workspaceService: jasmine.SpyObj; + let toastService: jasmine.SpyObj; + let trackingService: jasmine.SpyObj; + let router: Router; beforeEach(async () => { + const exportSettingServiceSpy = jasmine.createSpyObj('SiExportSettingService', ['getExportSettings', 'postExportSettings']); + const mappingServiceSpy = jasmine.createSpyObj('SiMappingsService', ['getPaginatedDestinationAttributes', 'refreshSageIntacctDimensions', 'refreshFyleDimensions']); + const workspaceServiceSpy = jasmine.createSpyObj('SiWorkspaceService', ['getIntacctOnboardingState', 'setIntacctOnboardingState']); + const toastServiceSpy = jasmine.createSpyObj('IntegrationsToastService', ['displayToastMessage']); + const trackingServiceSpy = jasmine.createSpyObj('TrackingService', ['trackTimeSpent', 'integrationsOnboardingCompletion', 'intacctUpdateEvent']); + await TestBed.configureTestingModule({ - declarations: [ IntacctExportSettingsComponent ] - }) - .compileComponents(); + declarations: [ IntacctExportSettingsComponent ], + imports: [ SharedModule, ReactiveFormsModule, RouterModule.forRoot([]) ], + providers: [ + FormBuilder, + { provide: SiExportSettingService, useValue: exportSettingServiceSpy }, + { provide: SiMappingsService, useValue: mappingServiceSpy }, + { provide: SiWorkspaceService, useValue: workspaceServiceSpy }, + { provide: IntegrationsToastService, useValue: toastServiceSpy }, + { provide: TrackingService, useValue: trackingServiceSpy }, + provideRouter([]) + ] + }).compileComponents(); + + exportSettingService = TestBed.inject(SiExportSettingService) as jasmine.SpyObj; + mappingService = TestBed.inject(SiMappingsService) as jasmine.SpyObj; + workspaceService = TestBed.inject(SiWorkspaceService) as jasmine.SpyObj; + toastService = TestBed.inject(IntegrationsToastService) as jasmine.SpyObj; + trackingService = TestBed.inject(TrackingService) as jasmine.SpyObj; + router = TestBed.inject(Router); + spyOn(router, 'navigate'); + + exportSettingService.getExportSettings.and.returnValue(of(mockExportSettings)); + mappingService.refreshSageIntacctDimensions.and.returnValue(of(null)); + mappingService.refreshFyleDimensions.and.returnValue(of(null)); + + const copy = structuredClone(mockPaginatedDestinationAttributes); + mappingService.getPaginatedDestinationAttributes.and.returnValues( + of(copy.ACCOUNT as unknown as PaginatedintacctDestinationAttribute), + of(copy.EXPENSE_PAYMENT_TYPE as unknown as PaginatedintacctDestinationAttribute), + of(copy.VENDOR as unknown as PaginatedintacctDestinationAttribute), + of(copy.CHARGE_CARD_NUMBER as unknown as PaginatedintacctDestinationAttribute) + ); fixture = TestBed.createComponent(IntacctExportSettingsComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); -}); + + describe('Initialization', () => { + beforeEach(fakeAsync(() => { + fixture.detectChanges(); + tick(); + })); + + it('should initialize destination options correctly', () => { + + expect(component.destinationOptions.ACCOUNT).toEqual(jasmine.arrayContaining( + mockPaginatedDestinationAttributes.ACCOUNT.results + ) as unknown as IntacctDestinationAttribute[]); + + expect(component.destinationOptions.EXPENSE_PAYMENT_TYPE).toEqual(jasmine.arrayContaining( + (mockPaginatedDestinationAttributes.EXPENSE_PAYMENT_TYPE.results) + .filter((attr) => attr.detail.is_reimbursable) + ) as unknown as IntacctDestinationAttribute[]); + + expect(component.destinationOptions.CCC_EXPENSE_PAYMENT_TYPE).toEqual(jasmine.arrayContaining( + (mockPaginatedDestinationAttributes.EXPENSE_PAYMENT_TYPE.results) + .filter((attr) => !attr.detail.is_reimbursable) + ) as unknown as IntacctDestinationAttribute[]); + + expect(component.destinationOptions.VENDOR).toEqual(jasmine.arrayContaining( + mockPaginatedDestinationAttributes.VENDOR.results + ) as unknown as IntacctDestinationAttribute[]); + + expect(component.destinationOptions.CHARGE_CARD).toEqual(jasmine.arrayContaining( + mockPaginatedDestinationAttributes.CHARGE_CARD_NUMBER.results as unknown as IntacctDestinationAttribute[] + ) as unknown as IntacctDestinationAttribute[]); + }); + + it('should add missing destination options', () => { + + expect(component.destinationOptions.ACCOUNT).toContain({ + destination_id: mockExportSettings.general_mappings.default_gl_account.id, + value: mockExportSettings.general_mappings.default_gl_account.name + } as unknown as IntacctDestinationAttribute); + + expect(component.destinationOptions.ACCOUNT).toContain({ + destination_id: mockExportSettings.general_mappings.default_credit_card.id, + value: mockExportSettings.general_mappings.default_credit_card.name + } as unknown as IntacctDestinationAttribute); + + }); + + it('should fetch and store export settings', () => { + expect(exportSettingService.getExportSettings).toHaveBeenCalled(); + expect(component.exportSettings).toEqual(mockExportSettings); + expect(component.exportSettingsForm).toBeDefined(); + expect(component.isLoading).toBeFalse(); + }); + }); +}); \ No newline at end of file diff --git a/src/app/integrations/intacct/intacct.fixture.ts b/src/app/integrations/intacct/intacct.fixture.ts index 165c738e9..23707afda 100644 --- a/src/app/integrations/intacct/intacct.fixture.ts +++ b/src/app/integrations/intacct/intacct.fixture.ts @@ -2,10 +2,12 @@ import { minimalUser } from "src/app/core/interceptor/jwt.fixture"; import { AccountingExportSummary } from "src/app/core/models/db/accounting-export-summary.model"; import { Error } from "src/app/core/models/db/error.model"; import { MinimalUser } from "src/app/core/models/db/user.model"; -import { AccountingErrorType, CCCExpenseState, ExpenseState, ExportDateType, FyleField, IntacctCorporateCreditCardExpensesObject, IntacctOnboardingState, IntacctReimbursableExpensesObject, SplitExpenseGrouping, TaskLogState, TaskLogType } from "src/app/core/models/enum/enum.model"; +import { AccountingErrorType, CCCExpenseState, ExpenseGroupingFieldOption, ExpenseState, ExportDateType, FyleField, IntacctCorporateCreditCardExpensesObject, IntacctOnboardingState, IntacctReimbursableExpensesObject, SplitExpenseGrouping, TaskLogState, TaskLogType } from "src/app/core/models/enum/enum.model"; import { IntacctWorkspace } from "src/app/core/models/intacct/db/workspaces.model"; import { ExportSettingGet } from "src/app/core/models/intacct/intacct-configuration/export-settings.model"; - +import { ExpenseGroup, ExpenseGroupDescription, ExpenseGroupResponse } from 'src/app/core/models/db/expense-group.model'; +import { Paginator } from 'src/app/core/models/misc/paginator.model'; +import { SkipExportLogResponse } from "src/app/core/models/intacct/db/expense-group.model"; export const workspaceResponse: IntacctWorkspace[] = [{ "id": 1, @@ -297,18 +299,6 @@ export const mockErrors = [ { id: 3, type: AccountingErrorType.ACCOUNTING_ERROR, error_title: 'Accounting error' } ] as Error[]; -export const mockExportSettings = { - configurations: { - reimbursable_expenses_object: IntacctReimbursableExpensesObject.EXPENSE_REPORT, - corporate_credit_card_expenses_object: IntacctCorporateCreditCardExpensesObject.BILL - }, - expense_group_settings: { - expense_state: ExpenseState.PAYMENT_PROCESSING, - ccc_expense_state: ExpenseState.PAID - } -} as unknown as ExportSettingGet; - - export const mockMappingSettingsResponse = { results: [ { source_field: FyleField.EMPLOYEE, destination_field: 'EMPLOYEE' }, @@ -351,3 +341,397 @@ export const mockDestinationAttributesResponse = { } ] }; + +export const mockExpenseGroupResponse: ExpenseGroupResponse = { + count: 2, + next: null, + previous: null, + results: [ + { + id: 7715, + expenses: [ + { + updated_at: new Date('2024-08-12T12:17:27.837958Z'), + claim_number: 'C/2024/08/R/8', + employee_email: 'ashwin.t@fyle.in', + employee_name: 'Ashwin', + fund_source: 'CCC', + expense_number: 'E/2024/08/T/8', + payment_number: 'P/2024/08/T/P/2024/08/R/7', + category: 'ABN Withholding', + amount: -460.0, + expense_id: 'txPpUSwko5es' + } + ], + description: { + spent_at: new Date("2024-08-12T00:00:00"), + expense_id: "txPpUSwko5es", + fund_source: "CCC", + employee_email: "ashwin.t@fyle.in" + } as unknown as ExpenseGroupDescription, + fund_source: 'CCC', + export_type: 'CHARGE_CARD_TRANSACTION', + exported_at: new Date('2024-08-27T16:51:07.206898Z'), + employee_name: 'Ashwin', + export_url: 'https://example.com/export/7715' + }, + { + id: 7714, + expenses: [ + { + updated_at: new Date('2024-08-12T12:17:27.698968Z'), + claim_number: 'C/2024/08/R/9', + employee_email: 'ashwin.t@fyle.in', + employee_name: 'Ashwin', + fund_source: 'CCC', + expense_number: 'E/2024/08/T/9', + payment_number: 'P/2024/08/T/P/2024/08/R/8', + category: 'ABN Withholding', + amount: -550.0, + expense_id: 'txoerMCRLkJ4' + } + ], + description: { + spent_at: new Date("2024-08-12T00:00:00"), + expense_id: "txPpUSwko5es", + fund_source: "CCC", + employee_email: "ashwin.t@fyle.in" + } as unknown as ExpenseGroupDescription, + fund_source: 'CCC', + export_type: 'CHARGE_CARD_TRANSACTION', + exported_at: new Date('2024-08-27T16:50:57.620969Z'), + employee_name: 'Ashwin', + export_url: 'https://example.com/export/7714' + } + ] as ExpenseGroup[] +}; + +export const mockSkipExportLogResponse = { + count: 2, + next: null, + previous: null, + results: [ + { + id: 1, + expenses: [ + { + updated_at: '2024-08-12T12:17:27.837958Z', + claim_number: 'C/2024/08/R/8', + employee_email: 'ashwin.t@fyle.in', + employee_name: 'Ashwin', + fund_source: 'CCC', + expense_number: 'E/2024/08/T/8', + category: 'ABN Withholding', + amount: -460.0, + expense_id: 'txPpUSwko5es' + } + ], + fund_source: 'CCC', + created_at: '2024-08-12T12:17:27.916749Z', + updated_at: '2024-08-27T16:51:07.218092Z', + workspace: 240 + }, + { + id: 2, + expenses: [ + { + updated_at: '2024-08-12T12:17:27.698968Z', + claim_number: 'C/2024/08/R/9', + employee_email: 'ashwin.t@fyle.in', + employee_name: 'Ashwin', + fund_source: 'CCC', + expense_number: 'E/2024/08/T/9', + category: 'ABN Withholding', + amount: -550.0, + expense_id: 'txoerMCRLkJ4' + } + ], + fund_source: 'CCC', + created_at: '2024-08-12T12:17:27.903912Z', + updated_at: '2024-08-27T16:50:57.633246Z', + workspace: 240 + } + ] +} as unknown as SkipExportLogResponse; + +export const mockPaginator: Paginator = { + limit: 50, + offset: 0 +}; + + +export const mockExportSettings = { + configurations: { + reimbursable_expenses_object: IntacctReimbursableExpensesObject.EXPENSE_REPORT, + corporate_credit_card_expenses_object: IntacctCorporateCreditCardExpensesObject.CHARGE_CARD_TRANSACTION, + employee_field_mapping: FyleField.EMPLOYEE, + auto_map_employees: 'EMAIL', + use_merchant_in_journal_line: true + }, + expense_group_settings: { + reimbursable_expense_group_fields: [ExpenseGroupingFieldOption.EXPENSE_ID], + reimbursable_export_date_type: ExportDateType.CURRENT_DATE, + expense_state: ExpenseState.PAYMENT_PROCESSING, + corporate_credit_card_expense_group_fields: [ExpenseGroupingFieldOption.EXPENSE_ID], + ccc_export_date_type: ExportDateType.SPENT_AT, + ccc_expense_state: CCCExpenseState.PAID, + split_expense_grouping: null + }, + general_mappings: { + default_gl_account: { id: '1', name: 'Account 1' }, + default_charge_card: { id: '2', name: 'Card 1' }, + default_reimbursable_expense_payment_type: { id: '3', name: 'Type 1' }, + default_ccc_expense_payment_type: { id: '4', name: 'Type 2' }, + default_ccc_vendor: { id: '5', name: 'Vendor 1' }, + default_credit_card: { id: '6', name: 'Credit Card 1' } + }, + workspace_id: 1 +} as unknown as ExportSettingGet; + + +export const mockPaginatedDestinationAttributes = { + ACCOUNT: { + "count": 4, + "next": "http://intacct-api.staging-integrations:8000/api/workspaces/366/sage_intacct/paginated_destination_attributes/?attribute_type=ACCOUNT&limit=100&offset=100", + "previous": null, + "results": [ + { + "id": 250084, + "attribute_type": "ACCOUNT", + "display_name": "account", + "value": "Accounts Payable", + "destination_id": "2000", + "auto_created": false, + "active": true, + "detail": { + "account_type": "balancesheet" + }, + "code": "2000", + "created_at": "2024-08-26T11:54:56.743019Z", + "updated_at": "2024-09-23T08:32:57.719332Z", + "workspace": 366 + }, + { + "id": 250077, + "attribute_type": "ACCOUNT", + "display_name": "account", + "value": "Accounts Receivable - trade", + "destination_id": "1100", + "auto_created": false, + "active": true, + "detail": { + "account_type": "balancesheet" + }, + "code": "1100", + "created_at": "2024-08-26T11:54:56.737413Z", + "updated_at": "2024-09-23T08:32:57.719266Z", + "workspace": 366 + }, + { + "id": 250078, + "attribute_type": "ACCOUNT", + "display_name": "account", + "value": "Accounts Receivable - unbilled", + "destination_id": "1110", + "auto_created": false, + "active": true, + "detail": { + "account_type": "balancesheet" + }, + "code": "1110", + "created_at": "2024-08-26T11:54:56.742752Z", + "updated_at": "2024-09-23T08:32:57.719286Z", + "workspace": 366 + }, + { + "id": 249997, + "attribute_type": "ACCOUNT", + "display_name": "account", + "value": "Accrued Bonus", + "destination_id": "2022", + "auto_created": false, + "active": true, + "detail": { + "account_type": "balancesheet" + }, + "code": "2022", + "created_at": "2024-08-26T11:54:56.719668Z", + "updated_at": "2024-09-23T08:32:57.718161Z", + "workspace": 366 + } + ] + }, + EXPENSE_PAYMENT_TYPE: { + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 249873, + "attribute_type": "EXPENSE_PAYMENT_TYPE", + "display_name": "expense payment type", + "value": "Elon Baba CCC", + "destination_id": "2", + "auto_created": false, + "active": true, + "detail": { + "is_reimbursable": false + }, + "code": null, + "created_at": "2024-08-26T11:54:41.504318Z", + "updated_at": "2024-08-26T11:54:41.504329Z", + "workspace": 366 + }, + { + "id": 249872, + "attribute_type": "EXPENSE_PAYMENT_TYPE", + "display_name": "expense payment type", + "value": "Elon musk", + "destination_id": "1", + "auto_created": false, + "active": true, + "detail": { + "is_reimbursable": true + }, + "code": null, + "created_at": "2024-08-26T11:54:41.504228Z", + "updated_at": "2024-08-26T11:54:41.504262Z", + "workspace": 366 + } + ] + }, + VENDOR: { + "count": 4, + "next": null, + "previous": null, + "results": [ + { + "id": 249883, + "attribute_type": "VENDOR", + "display_name": "vendor", + "value": "A-1 Electric Company", + "destination_id": "V100", + "auto_created": false, + "active": true, + "detail": { + "email": null + }, + "code": null, + "created_at": "2024-08-26T11:54:51.315724Z", + "updated_at": "2024-08-26T11:54:51.315731Z", + "workspace": 366 + }, + { + "id": 249886, + "attribute_type": "VENDOR", + "display_name": "vendor", + "value": "AAA Insurance and Bonding", + "destination_id": "V104", + "auto_created": false, + "active": true, + "detail": { + "email": "andree@abuckley.COM" + }, + "code": null, + "created_at": "2024-08-26T11:54:51.315883Z", + "updated_at": "2024-08-26T11:54:51.315893Z", + "workspace": 366 + }, + { + "id": 249943, + "attribute_type": "VENDOR", + "display_name": "vendor", + "value": "ABC Electric", + "destination_id": "V164", + "auto_created": false, + "active": true, + "detail": { + "email": null + }, + "code": null, + "created_at": "2024-08-26T11:54:51.338322Z", + "updated_at": "2024-08-26T11:54:51.338330Z", + "workspace": 366 + }, + { + "id": 249885, + "attribute_type": "VENDOR", + "display_name": "vendor", + "value": "Ace Drywall", + "destination_id": "V103", + "auto_created": false, + "active": true, + "detail": { + "email": null + }, + "code": null, + "created_at": "2024-08-26T11:54:51.315818Z", + "updated_at": "2024-08-26T11:54:51.315827Z", + "workspace": 366 + } + ] + }, + CHARGE_CARD_NUMBER: { + "count": 4, + "next": null, + "previous": null, + "results": [ + { + "id": 249875, + "attribute_type": "CHARGE_CARD_NUMBER", + "display_name": "Charge Card Account", + "value": "1234", + "destination_id": "1234", + "auto_created": false, + "active": true, + "detail": null, + "code": null, + "created_at": "2024-08-26T11:54:46.642086Z", + "updated_at": "2024-08-26T11:54:46.642093Z", + "workspace": 366 + }, + { + "id": 249876, + "attribute_type": "CHARGE_CARD_NUMBER", + "display_name": "Charge Card Account", + "value": "Mastercard - 6789", + "destination_id": "Mastercard - 6789", + "auto_created": false, + "active": true, + "detail": null, + "code": null, + "created_at": "2024-08-26T11:54:46.642117Z", + "updated_at": "2024-08-26T11:54:46.642125Z", + "workspace": 366 + }, + { + "id": 249874, + "attribute_type": "CHARGE_CARD_NUMBER", + "display_name": "Charge Card Account", + "value": "Nilesh Credit Card", + "destination_id": "Nilesh Credit Card", + "auto_created": false, + "active": true, + "detail": null, + "code": null, + "created_at": "2024-08-26T11:54:46.642035Z", + "updated_at": "2024-08-26T11:54:46.642058Z", + "workspace": 366 + }, + { + "id": 249877, + "attribute_type": "CHARGE_CARD_NUMBER", + "display_name": "Charge Card Account", + "value": "Visa - 1234", + "destination_id": "Visa - 1234", + "auto_created": false, + "active": true, + "detail": null, + "code": null, + "created_at": "2024-08-26T11:54:46.642147Z", + "updated_at": "2024-08-26T11:54:46.642154Z", + "workspace": 366 + } + ] + } +}; \ No newline at end of file From bbda337537b912a7c219f55a3d4f34e59fc2a20a Mon Sep 17 00:00:00 2001 From: Viswas Date: Fri, 4 Oct 2024 04:24:22 +0530 Subject: [PATCH 2/2] test: intacct export settings save functionality + misc tests --- .../intacct-export-settings.component.spec.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts b/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts index 4ff7c568d..238f5266a 100644 --- a/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts +++ b/src/app/integrations/intacct/intacct-shared/intacct-export-settings/intacct-export-settings.component.spec.ts @@ -125,4 +125,57 @@ describe('IntacctExportSettingsComponent', () => { expect(component.isLoading).toBeFalse(); }); }); + + describe('Form Save', () => { + it('should save export settings successfully during onboarding', fakeAsync(() => { + workspaceService.getIntacctOnboardingState.and.returnValue(IntacctOnboardingState.EXPORT_SETTINGS); + exportSettingService.postExportSettings.and.returnValue(of(mockExportSettings)); + spyOnProperty(router, 'url').and.returnValue('/integrations/intacct/onboarding/export_settings'); + + fixture.detectChanges(); + component.save(); + tick(); + + expect(exportSettingService.postExportSettings).toHaveBeenCalled(); + expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.SUCCESS, 'Export settings saved successfully'); + expect(trackingService.integrationsOnboardingCompletion).toHaveBeenCalled(); + expect(workspaceService.setIntacctOnboardingState).toHaveBeenCalledWith(IntacctOnboardingState.IMPORT_SETTINGS); + expect(router.navigate).toHaveBeenCalledWith(['/integrations/intacct/onboarding/import_settings']); + })); + + it('should save export settings successfully post onboarding', () => { + workspaceService.getIntacctOnboardingState.and.returnValue(IntacctOnboardingState.COMPLETE); + exportSettingService.postExportSettings.and.returnValue(of(mockExportSettings)); + + fixture.detectChanges(); + component.save(); + + expect(exportSettingService.postExportSettings).toHaveBeenCalled(); + expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.SUCCESS, 'Export settings saved successfully'); + expect(trackingService.intacctUpdateEvent).toHaveBeenCalled(); + expect(router.navigate).not.toHaveBeenCalled(); + }); + + it('should handle save failure', () => { + exportSettingService.postExportSettings.and.returnValue(throwError(() => new Error('API Error'))); + + fixture.detectChanges(); + component.save(); + + expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.ERROR, 'Error saving export settings, please try again later'); + expect(component.saveInProgress).toBeFalse(); + }); + }); + + it('should handle refresh dimensions', () => { + component.refreshDimensions(true); + expect(mappingService.refreshSageIntacctDimensions).toHaveBeenCalled(); + expect(mappingService.refreshFyleDimensions).toHaveBeenCalled(); + expect(toastService.displayToastMessage).toHaveBeenCalledWith(ToastSeverity.SUCCESS, 'Syncing data dimensions from Sage Intacct'); + }); + + it('should navigate to previous step', () => { + component.navigateToPreviousStep(); + expect(router.navigate).toHaveBeenCalledWith(['/integrations/intacct/onboarding/connector']); + }); }); \ No newline at end of file