import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { type ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router, convertToParamMap, provideRouter } from '@angular/router'; import { of } from 'rxjs'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { DocumentFormPage } from './document-form.page'; import { hasFolio } from './document-layouts'; import { DOCUMENT_SCREENS } from './document-screens'; const invoice = (over: Record = {}) => ({ 'odata.etag': 'W/"5"', DocEntry: 8, DocNum: 108, CardCode: 'P1', CardName: 'Proveedor Uno', FederalTaxID: '76543210-K', NumAtCard: 'REF-1', FolioPrefixString: 'F001', FolioNumber: 198837, DocDate: '2026-09-11T00:00:00Z', DocDueDate: '2026-09-20T00:00:00Z', DiscountPercent: 0, Comments: '', DocumentStatus: 'bost_Open', Cancelled: 'tNO', DocumentLines: [{ LineNum: 0, ItemCode: 'A1', ItemDescription: 'Pieza', Quantity: 1, Price: 10, DiscountPercent: 0, TaxCode: 'IVA', LineTotal: 10, WarehouseCode: '01' }], ...over, }); describe('folio y RUT en los formularios', () => { let fixture: ComponentFixture; let ctrl: HttpTestingController; const el = () => fixture.nativeElement as HTMLElement; // eslint-disable-next-line @typescript-eslint/no-explicit-any const page = () => fixture.componentInstance as any; const tick = async () => { fixture.detectChanges(); await new Promise((r) => setTimeout(r)); fixture.detectChanges(); }; const labels = () => [...el().querySelectorAll('label')].map((l) => l.textContent?.trim()); async function open(resource: string, doc: Record | null) { const screen = DOCUMENT_SCREENS.find((s) => s.resource === resource)!; const params = doc ? { docEntry: '8' } : {}; const route = { snapshot: { data: { screen, title: 'Documento' }, paramMap: convertToParamMap(params) }, paramMap: of(convertToParamMap(params)), }; await TestBed.configureTestingModule({ imports: [DocumentFormPage], providers: [provideRouter([]), provideHttpClient(), provideHttpClientTesting(), { provide: ActivatedRoute, useValue: route }], }).compileComponents(); ctrl = TestBed.inject(HttpTestingController); vi.spyOn(TestBed.inject(Router), 'navigate').mockResolvedValue(true); fixture = TestBed.createComponent(DocumentFormPage); await tick(); ctrl.expectOne((r) => r.url === '/api/sl/SalesTaxCodes').flush({ value: [{ Code: 'IVA', Rate: 19 }] }); if (doc) ctrl.expectOne(`/api/sl/${resource}/8`).flush(doc); await tick(); } beforeEach(() => TestBed.resetTestingModule()); it('lo llevan facturas, boletas, notas de crédito, entregas y recepciones (ventas y compras)', () => { const withFolio = DOCUMENT_SCREENS.filter((s) => hasFolio(s.layout)).map((s) => s.path); expect(withFolio.sort()).toEqual( [ '/ventas/facturas', '/ventas/boletas', '/ventas/facturas-reserva', '/ventas/boletas-reserva', '/ventas/notas-credito', '/ventas/entrega', '/compras/facturas', '/compras/notas-credito', '/compras/recepcion', ].sort(), ); }); it('una factura muestra folio, número de folio, referencia y RUT', async () => { await open('PurchaseInvoices', invoice()); expect(labels()).toEqual(expect.arrayContaining(['Folio', 'Nº referencia', 'RUT'])); const inputs = [...el().querySelectorAll('input')].map((i) => i.value); expect(inputs).toEqual(expect.arrayContaining(['F001', '198837', 'REF-1', '76543210-K'])); }); it('una orden muestra referencia y RUT pero no el folio', async () => { await open('Orders', invoice()); expect(labels()).toEqual(expect.arrayContaining(['Nº referencia', 'RUT'])); expect(labels()).not.toContain('Folio'); }); it('cambiar el folio envía el número como número', async () => { await open('Invoices', invoice()); page().setHeader('FolioPrefixString', 'F002'); page().setHeader('FolioNumber', '200100'); await tick(); (el().querySelector('.actions .btn.main') as HTMLElement).click(); await tick(); const req = ctrl.expectOne((r) => r.method === 'PATCH'); expect(req.request.body).toEqual({ FolioPrefixString: 'F002', FolioNumber: 200100 }); req.flush(null); await tick(); ctrl.expectOne('/api/sl/Invoices/8').flush(invoice()); }); it('un folio que no es numérico no se envía', async () => { await open('Invoices', invoice()); page().setHeader('FolioNumber', '12ab'); await tick(); (el().querySelector('.actions .btn.main') as HTMLElement).click(); await tick(); ctrl.expectNone((r) => r.method === 'PATCH'); expect(el().querySelector('.status')?.textContent).toContain('folio debe ser numérico'); }); it('un documento nuevo sin folio no lo envía', async () => { await open('Invoices', null); page().setHeader('CardCode', 'C1'); page().setLines([{ ItemCode: 'A1', Quantity: 1, Price: 50, LineTotal: 50 }]); await tick(); (el().querySelector('.actions .btn.main') as HTMLElement).click(); await tick(); const body = ctrl.expectOne((r) => r.method === 'POST' && !r.url.includes('SeriesService')).request.body as Record; expect(body).not.toHaveProperty('FolioNumber'); expect(body).not.toHaveProperty('FolioPrefixString'); }); });