1+ /* eslint-disable dot-notation */
12import { ComponentFixture , fakeAsync , TestBed , tick } from '@angular/core/testing' ;
2- import { FormBuilder , ReactiveFormsModule } from '@angular/forms' ;
3+ import { FormBuilder , ReactiveFormsModule , Validators } from '@angular/forms' ;
34import { provideRouter , Router , RouterModule } from '@angular/router' ;
45import { of , throwError } from 'rxjs' ;
56import { IntacctExportSettingsComponent } from './intacct-export-settings.component' ;
@@ -9,10 +10,13 @@ import { SiWorkspaceService } from 'src/app/core/services/si/si-core/si-workspac
910import { IntegrationsToastService } from 'src/app/core/services/common/integrations-toast.service' ;
1011import { TrackingService } from 'src/app/core/services/integration/tracking.service' ;
1112import { mockExportSettings , mockPaginatedDestinationAttributes } from '../../intacct.fixture' ;
12- import { IntacctOnboardingState , Page , ToastSeverity } from 'src/app/core/models/enum/enum.model' ;
13- import { ExportSettingOptionSearch } from 'src/app/core/models/common/export-settings.model' ;
13+ import { EmployeeFieldMapping , ExpenseGroupingFieldOption , ExportDateType , FyleField , IntacctCorporateCreditCardExpensesObject , IntacctOnboardingState , IntacctReimbursableExpensesObject , Page , ToastSeverity } from 'src/app/core/models/enum/enum.model' ;
14+ import { ExportSettingOptionSearch , ExportSettingModel } from 'src/app/core/models/common/export-settings.model' ;
1415import { IntacctDestinationAttribute , PaginatedintacctDestinationAttribute } from 'src/app/core/models/intacct/db/destination-attribute.model' ;
1516import { SharedModule } from 'src/app/shared/shared.module' ;
17+ import { brandingConfig } from 'src/app/branding/branding-config' ;
18+ import { BrandingConfiguration } from 'src/app/core/models/branding/branding-configuration.model' ;
19+ import { ExportSettingModel as IntacctExportSettingModel } from 'src/app/core/models/intacct/intacct-configuration/export-settings.model' ;
1620
1721describe ( 'IntacctExportSettingsComponent' , ( ) => {
1822 let component : IntacctExportSettingsComponent ;
@@ -57,7 +61,7 @@ describe('IntacctExportSettingsComponent', () => {
5761 mappingService . refreshSageIntacctDimensions . and . returnValue ( of ( null ) ) ;
5862 mappingService . refreshFyleDimensions . and . returnValue ( of ( null ) ) ;
5963
60- const copy = structuredClone ( mockPaginatedDestinationAttributes ) ;
64+ const copy = structuredClone ( mockPaginatedDestinationAttributes ) ;
6165 mappingService . getPaginatedDestinationAttributes . and . returnValues (
6266 of ( copy . ACCOUNT as unknown as PaginatedintacctDestinationAttribute ) ,
6367 of ( copy . EXPENSE_PAYMENT_TYPE as unknown as PaginatedintacctDestinationAttribute ) ,
@@ -178,4 +182,229 @@ describe('IntacctExportSettingsComponent', () => {
178182 component . navigateToPreviousStep ( ) ;
179183 expect ( router . navigate ) . toHaveBeenCalledWith ( [ '/integrations/intacct/onboarding/connector' ] ) ;
180184 } ) ;
185+
186+ describe ( 'Watchers' , ( ) => {
187+ beforeEach ( ( ) => {
188+ fixture . detectChanges ( ) ;
189+ } ) ;
190+
191+ describe ( 'Reimbursable Expense Toggle Watcher' , ( ) => {
192+ it ( 'should enable fields on enabling reimbursable expenses' , fakeAsync ( ( ) => {
193+ component . exportSettingsForm . get ( 'reimbursableExpense' ) ?. setValue ( true ) ;
194+ tick ( ) ;
195+
196+ expect ( component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
197+ expect ( component . exportSettingsForm . get ( 'reimbursableExportGroup' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
198+ expect ( component . exportSettingsForm . get ( 'reimbursableExportDate' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
199+ } ) ) ;
200+
201+ it ( 'should disable fields on disabling reimbursable expenses' , fakeAsync ( ( ) => {
202+ component . exportSettingsForm . get ( 'reimbursableExpense' ) ?. setValue ( false ) ;
203+ tick ( ) ;
204+
205+ expect ( component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
206+ expect ( component . exportSettingsForm . get ( 'reimbursableExportGroup' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
207+ expect ( component . exportSettingsForm . get ( 'reimbursableExportDate' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
208+ expect ( component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. value ) . toBeNull ( ) ;
209+ } ) ) ;
210+ } ) ;
211+
212+ describe ( 'Reimbursable Export Type Watchers' , ( ) => {
213+
214+ it ( 'should handle reimbursableExportType being changed to Journal Entry' , fakeAsync ( ( ) => {
215+ component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. setValue ( IntacctReimbursableExpensesObject . JOURNAL_ENTRY ) ;
216+ tick ( ) ;
217+
218+ expect ( component . exportSettingsForm . get ( 'glAccount' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
219+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. enabled ) . toBeTrue ( ) ;
220+ } ) ) ;
221+
222+ it ( 'should handle reimbursableExportType being changed to Expense Report' , fakeAsync ( ( ) => {
223+ component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. setValue ( IntacctReimbursableExpensesObject . EXPENSE_REPORT ) ;
224+ tick ( ) ;
225+
226+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. value ) . toBe ( FyleField . EMPLOYEE ) ;
227+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. disabled ) . toBeTrue ( ) ;
228+ } ) ) ;
229+
230+ it ( 'should handle reimbursableExportType being changed to Bill' , fakeAsync ( ( ) => {
231+ component . exportSettingsForm . get ( 'reimbursableExportType' ) ?. setValue ( IntacctReimbursableExpensesObject . BILL ) ;
232+ tick ( ) ;
233+
234+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. value ) . toBe ( FyleField . VENDOR ) ;
235+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. disabled ) . toBeTrue ( ) ;
236+ } ) ) ;
237+ } ) ;
238+
239+ describe ( 'Credit Card Expense Toggle Watcher' , ( ) => {
240+ it ( 'should enable fields on enabling CCC expenses' , fakeAsync ( ( ) => {
241+ component . exportSettingsForm . get ( 'creditCardExpense' ) ?. setValue ( true ) ;
242+ tick ( ) ;
243+
244+ expect ( component . exportSettingsForm . get ( 'cccExportType' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
245+ expect ( component . exportSettingsForm . get ( 'cccExportGroup' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
246+ expect ( component . exportSettingsForm . get ( 'cccExportDate' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
247+ } ) ) ;
248+
249+ it ( 'should disable fields on disabling CCC expenses' , fakeAsync ( ( ) => {
250+ component . exportSettingsForm . get ( 'creditCardExpense' ) ?. setValue ( false ) ;
251+ tick ( ) ;
252+
253+ expect ( component . exportSettingsForm . get ( 'cccExportType' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
254+ expect ( component . exportSettingsForm . get ( 'cccExportGroup' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
255+ expect ( component . exportSettingsForm . get ( 'cccExportDate' ) ?. hasValidator ( Validators . required ) ) . toBeFalse ( ) ;
256+ expect ( component . exportSettingsForm . get ( 'cccExportType' ) ?. value ) . toBeNull ( ) ;
257+ } ) ) ;
258+ } ) ;
259+
260+ describe ( 'CCC Export Type Watchers' , ( ) => {
261+ it ( 'should handle cccExportType being changed to Charge Card Transaction' , fakeAsync ( ( ) => {
262+ component . exportSettingsForm . get ( 'cccExportType' ) ?. setValue ( IntacctCorporateCreditCardExpensesObject . CHARGE_CARD_TRANSACTION ) ;
263+ tick ( ) ;
264+
265+ expect ( component . exportSettingsForm . get ( 'chargeCard' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
266+ expect ( component . exportSettingsForm . get ( 'cccExportGroup' ) ?. disabled ) . toBeTrue ( ) ;
267+ expect ( component . exportSettingsForm . get ( 'cccExportGroup' ) ?. value ) . toBe ( ExpenseGroupingFieldOption . EXPENSE_ID ) ;
268+ } ) ) ;
269+
270+ it ( 'should handle cccExportType being changed to Bill' , fakeAsync ( ( ) => {
271+ component . exportSettingsForm . get ( 'cccExportType' ) ?. setValue ( IntacctCorporateCreditCardExpensesObject . BILL ) ;
272+ tick ( ) ;
273+
274+ expect ( component . exportSettingsForm . get ( 'creditCardVendor' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
275+ } ) ) ;
276+
277+ it ( 'should handle cccExportType being changed to Expense Report' , fakeAsync ( ( ) => {
278+ component . exportSettingsForm . get ( 'cccExportType' ) ?. setValue ( IntacctCorporateCreditCardExpensesObject . EXPENSE_REPORT ) ;
279+ tick ( ) ;
280+
281+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. value ) . toBe ( EmployeeFieldMapping . EMPLOYEE ) ;
282+ expect ( component . exportSettingsForm . get ( 'cccExpensePaymentType' ) ?. hasValidator ( Validators . required ) ) . toBeTrue ( ) ;
283+ } ) ) ;
284+ } ) ;
285+
286+ describe ( 'Custom Watchers' , ( ) => {
287+ beforeEach ( ( ) => {
288+ brandingConfig . brandId = 'fyle' ;
289+ } ) ;
290+
291+ it ( 'should update reimbursable expense grouping date options when group changes' , fakeAsync ( ( ) => {
292+ fixture . detectChanges ( ) ;
293+ component . exportSettingsForm . get ( 'reimbursableExportGroup' ) ?. setValue ( ExpenseGroupingFieldOption . CLAIM_NUMBER ) ;
294+ tick ( ) ;
295+
296+ expect ( component . reimbursableExpenseGroupingDateOptions ) . not . toContain ( {
297+ label : 'Spend date' ,
298+ value : ExportDateType . SPENT_AT
299+ } ) ;
300+ } ) ) ;
301+
302+ it ( 'should update CCC expense grouping date options when group changes' , fakeAsync ( ( ) => {
303+ spyOn < IntacctExportSettingsComponent , any > ( component , 'setCCExpenseDateOptions' ) . and . callThrough ( ) ;
304+ spyOn ( IntacctExportSettingModel , 'getExpenseGroupingDateOptions' ) . and . callThrough ( ) ;
305+ spyOn ( ExportSettingModel , 'constructGroupingDateOptions' ) . and . callThrough ( ) ;
306+
307+ component . exportSettingsForm . get ( 'cccExportType' ) ?. setValue ( IntacctCorporateCreditCardExpensesObject . CHARGE_CARD_TRANSACTION ) ;
308+ component . exportSettingsForm . get ( 'cccExportGroup' ) ?. setValue ( ExpenseGroupingFieldOption . CLAIM_NUMBER ) ;
309+
310+ tick ( ) ;
311+
312+ expect ( IntacctExportSettingModel . getExpenseGroupingDateOptions ) . toHaveBeenCalledWith ( ) ;
313+ expect ( ExportSettingModel . constructGroupingDateOptions ) . toHaveBeenCalledWith (
314+ ExpenseGroupingFieldOption . CLAIM_NUMBER ,
315+ IntacctExportSettingModel . getExpenseGroupingDateOptions ( )
316+ ) ;
317+ expect ( component [ 'setCCExpenseDateOptions' ] ) . toHaveBeenCalled ( ) ;
318+ } ) ) ;
319+ } ) ;
320+
321+ describe ( 'Export Selection Validator' , ( ) => {
322+ beforeEach ( ( ) => {
323+ fixture . detectChanges ( ) ;
324+ } ) ;
325+
326+ it ( 'should invalidate form when neither reimbursable nor credit card expense is selected' , ( ) => {
327+ component . exportSettingsForm . get ( 'reimbursableExpense' ) ?. setValue ( false ) ;
328+ component . exportSettingsForm . get ( 'creditCardExpense' ) ?. setValue ( false ) ;
329+
330+ expect ( component . exportSettingsForm . valid ) . toBeFalse ( ) ;
331+ } ) ;
332+
333+ it ( 'should validate the form when at least one export type is selected' , ( ) => {
334+ component . exportSettingsForm . get ( 'reimbursableExpense' ) ?. setValue ( true ) ;
335+ component . exportSettingsForm . get ( 'creditCardExpense' ) ?. setValue ( false ) ;
336+
337+ expect ( component . exportSettingsForm . valid ) . toBeTrue ( ) ;
338+ } ) ;
339+ } ) ;
340+
341+ describe ( 'Destination Options Handling' , ( ) => {
342+ beforeEach ( ( ) => {
343+ fixture . detectChanges ( ) ;
344+ } ) ;
345+
346+ it ( 'should handle option search for reimbursable expense payment type' , fakeAsync ( ( ) => {
347+ const searchEvent = {
348+ searchTerm : 'test' ,
349+ destinationOptionKey : 'EXPENSE_PAYMENT_TYPE'
350+ } as ExportSettingOptionSearch ;
351+
352+ mappingService . getPaginatedDestinationAttributes . and . returnValue (
353+ of ( mockPaginatedDestinationAttributes . EXPENSE_PAYMENT_TYPE as unknown as PaginatedintacctDestinationAttribute )
354+ ) ;
355+
356+ component . searchOptionsDropdown ( searchEvent ) ;
357+ tick ( 1000 ) ;
358+
359+ const isReimbursable = ( option : IntacctDestinationAttribute ) => (
360+ option . detail ? option . detail . is_reimbursable : true
361+ ) ;
362+
363+ expect ( mappingService . getPaginatedDestinationAttributes ) . toHaveBeenCalledWith ( 'EXPENSE_PAYMENT_TYPE' , 'test' ) ;
364+ expect ( component . destinationOptions . EXPENSE_PAYMENT_TYPE . every ( isReimbursable ) ) . toBeTrue ( ) ;
365+ expect ( component . isOptionSearchInProgress ) . toBeFalse ( ) ;
366+ } ) ) ;
367+
368+ it ( 'should handle option search for CCC expense payment type' , fakeAsync ( ( ) => {
369+ const searchEvent = {
370+ searchTerm : 'test' ,
371+ destinationOptionKey : 'CCC_EXPENSE_PAYMENT_TYPE'
372+ } ;
373+
374+ mappingService . getPaginatedDestinationAttributes . and . returnValue (
375+ of ( mockPaginatedDestinationAttributes . EXPENSE_PAYMENT_TYPE as unknown as PaginatedintacctDestinationAttribute )
376+ ) ;
377+
378+ component . searchOptionsDropdown ( searchEvent as ExportSettingOptionSearch ) ;
379+ tick ( 1000 ) ;
380+
381+ expect ( mappingService . getPaginatedDestinationAttributes ) . toHaveBeenCalledWith ( 'EXPENSE_PAYMENT_TYPE' , 'test' ) ;
382+ expect ( component . destinationOptions . CCC_EXPENSE_PAYMENT_TYPE . every ( option => (
383+ option . detail ? ! option . detail . is_reimbursable : true
384+ ) ) ) . toBeTrue ( ) ;
385+ expect ( component . isOptionSearchInProgress ) . toBeFalse ( ) ;
386+ } ) ) ;
387+ } ) ;
388+
389+
390+ } ) ;
391+
392+
393+ describe ( 'C1 Specific Behavior' , ( ) => {
394+ it ( 'should handle setup with c1 branding' , ( ) => {
395+ brandingConfig . brandId = 'co' ;
396+
397+ fixture = TestBed . createComponent ( IntacctExportSettingsComponent ) ;
398+ component = fixture . componentInstance ;
399+ fixture . detectChanges ( ) ;
400+
401+ expect ( component . exportSettingsForm . get ( 'creditCardExpense' ) ?. value ) . toBeTrue ( ) ;
402+ expect ( component . exportSettingsForm . get ( 'employeeFieldMapping' ) ?. value ) . toBe ( FyleField . VENDOR ) ;
403+ expect ( component . isMultiLineOption ) . toBeFalse ( ) ;
404+ } ) ;
405+
406+ afterAll ( ( ) => {
407+ brandingConfig . brandId = 'fyle' ;
408+ } ) ;
409+ } ) ;
181410} ) ;
0 commit comments