Skip to main content

Features de gestión: casos de prueba

Casos de prueba unitarios (Karma + Jasmine) de las features de gestión: departamentos, etiquetas, respuestas rápidas, tickets bloqueados, control de acceso (módulos) y contactos. Son 10 specs y 112 it(). Salvo contacts-routing.module.spec.ts, todos usan TestBed con NO_ERRORS_SCHEMA; ninguno contiene xit, fdescribe ni fit, y no hay specs vacíos.

Departamentos​

src/app/features/departments/components/department-modal/department-modal.component.spec.ts​

  • SUT: DepartmentModalComponent (modal de alta/edición de departamento con formulario reactivo y pestañas).
  • Mocking: TestBed con ReactiveFormsModule y TranslateModule.forRoot(). Providers: NgbActiveModal real, DepartmentService (jasmine.createSpyObj con create, update, getDepartmentUsers, updateDepartmentUsers) y ToastrNotificationService (showNotification). Fixture auxiliar makeDepartment(). spyOn(component.activeModal, 'close') donde se verifica el cierre.

ngOnInit — ADD action​

it()EscenarioResultado esperadoMocks/spies
should build the form with default valuesDado action = ADD, cuando se ejecuta detectChanges(), entonces se construye el formulario.name vacío, color #000000 y autoResolution.resolveInMinutes igual a 5.Ninguno adicional.
should set the ADD titleDado action = ADD, cuando se inicializa el componente.titleModal es departments.modal.add.Ninguno.

ngOnInit — EDIT action​

it()EscenarioResultado esperadoMocks/spies
should populate the form from the department inputDado action = EDIT y un department asignado, cuando se inicializa.name es Support y autoResolution.notificationMessage es Closing soon.makeDepartment().
should set the EDIT titleDado action = EDIT, cuando se inicializa.titleModal es departments.modal.edit.makeDepartment().

resolution toggles​

it()EscenarioResultado esperadoMocks/spies
should disable the autoResolution group when override is OFFDado el modo ADD, cuando overrideGlobalResolution pasa a false.notificationMessage queda deshabilitado.Ninguno.
should enable the autoResolution group when override is ONDado el modo ADD, cuando overrideGlobalResolution pasa a true.El grupo autoResolution no está deshabilitado.Ninguno.
should keep dependent fields disabled when override is ON but auto-resolution is OFFDado override true, cuando autoResolution.enabled pasa a false (caso límite).notificationMessage sigue deshabilitado.Ninguno.
should enable notificationMessage when override AND auto-resolution are both ONDado override true, cuando autoResolution.enabled pasa a true.notificationMessage queda habilitado.Ninguno.

notify before resolve validation​

Precondición del beforeEach: modo ADD con override y auto-resolución activados.

it()EscenarioResultado esperadoMocks/spies
should be valid when notifyInMinutes is lower than resolveInMinutesDado resolveInMinutes: 5 y notifyInMinutes: 1.notifyBeforeResolveError es false.Ninguno.
should flag the group when notifyInMinutes equals resolveInMinutesDado resolveInMinutes: 5 y notifyInMinutes: 5 (borde).notifyBeforeResolveError es true y el formulario es inválido.Ninguno.
should flag the group when notifyInMinutes is greater than resolveInMinutesDado resolveInMinutes: 2 y notifyInMinutes: 5.notifyBeforeResolveError es true.Ninguno.
should not block the form when the override is OFFDado un nombre válido y tiempos inválidos (2 y 5), el formulario es inválido; cuando se apaga el override.El formulario pasa a válido.Ninguno.
should mark resolveInMinutes as requiredDado resolveInMinutes en null (fallo).El control tiene el error required.Ninguno.

insertVariable​

it()EscenarioResultado esperadoMocks/spies
should append the variable into an empty greetingMessageDado greetingMessage vacío, cuando se llama insertVariable('{{username}}').greetingMessage contiene {{username}}.Ninguno.

onSubmit — create​

it()EscenarioResultado esperadoMocks/spies
should call DepartmentService.create with the built payloadDado modo ADD con name New department, cuando se ejecuta onSubmit().create se invoca y el payload tiene name New department.create devuelve of(created).
should close the modal with the created department after successful creationDado el mismo caso, con create exitoso.activeModal.close se llama con el departamento creado.create devuelve of(created); spyOn(component.activeModal, 'close').

onSubmit — update​

it()EscenarioResultado esperadoMocks/spies
should call DepartmentService.update with the department idDado modo EDIT con un departamento, cuando se ejecuta onSubmit().update se llama con _id y objectContaining({ name }).update devuelve of(department).
should include the autoResolution times in the save payloadDado modo EDIT, cuando se guarda.El payload lleva resolveInMinutes 10 y notifyInMinutes 2.update devuelve of(department).
should close the modal with the updated department after a successful updateDado update que devuelve el departamento renombrado.close se llama con el departamento actualizado.update devuelve of(updated); spyOn(component.activeModal, 'close').

onTabChange​

it()EscenarioResultado esperadoMocks/spies
should load department users when switching to the users tab for the first timeDado modo EDIT, cuando se cambia a la pestaña users.getDepartmentUsers se llama con el _id y activeTab es users.getDepartmentUsers devuelve of([]).
should NOT reload users on a second switch to the users tabDado un cambio users, resolution, users (borde).getDepartmentUsers se llama una sola vez.getDepartmentUsers devuelve of([]).

Tests en este archivo: 21.

Etiquetas​

src/app/features/labels/components/label-modal-form/label-modal-form.component.spec.ts​

  • SUT: LabelModalFormComponent (modal de etiqueta con acciones ADD, EDIT y VIEW).
  • Mocking: TestBed con ReactiveFormsModule y TranslateModule.forRoot con TranslateFakeLoader. NgbActiveModal (createSpyObj: close, dismiss) y LabelService (createLabel, updateLabel). Fixture mockLabel.

ADD action​

it()EscenarioResultado esperadoMocks/spies
should createDado action = ADD, tras detectChanges().El componente existe.Ninguno.
should set titleModal to add keyDado action = ADD.titleModal es labels.modal.add.Ninguno.
should build an enabled form with default color #000000Dado action = ADD.Formulario habilitado y color igual a #000000.Ninguno.
should be invalid when name is emptyDado el formulario recién creado.El control name es inválido.Ninguno.
should be valid with required fields filledDado patchValue con name, color e isActive.El formulario es válido.Ninguno.
onSubmit: should call createLabel and close modal on valid formDado un formulario válido, cuando se ejecuta onSubmit().createLabel se llama con el valor del formulario y close con saved.createLabel devuelve of(mockLabel); activeModal.close.
onSubmit: should NOT call createLabel when form is invalidDado un formulario vacío (fallo).createLabel no se llama.createLabel.
should reject name longer than MAX_LENGTHDado un name de 101 caracteres (borde).El control name es inválido.Ninguno.

EDIT action​

it()EscenarioResultado esperadoMocks/spies
should set titleModal to edit keyDado action = EDIT y label asignada.titleModal es labels.modal.edit.Ninguno.
should populate form with label valuesDado action = EDIT.El valor del formulario es igual a los datos de mockLabel.Ninguno.
should leave the form enabledDado action = EDIT.Formulario habilitado.Ninguno.
onSubmit: should call updateLabel with _id and form valueDado action = EDIT, cuando se envía.updateLabel se llama con oid-001 y el valor del formulario; close con saved.updateLabel devuelve of(mockLabel); activeModal.close.

VIEW action​

it()EscenarioResultado esperadoMocks/spies
should set titleModal to view keyDado action = VIEW.titleModal es labels.modal.view.Ninguno.
should disable the formDado action = VIEW.El formulario está deshabilitado.Ninguno.
onSubmit: should NOT call createLabel or updateLabelDado modo VIEW, cuando se ejecuta onSubmit() (borde).No se llama a createLabel ni a updateLabel.createLabel, updateLabel.

Nivel raíz​

it()EscenarioResultado esperadoMocks/spies
closeModal: should call activeModal.dismissDado modo ADD, cuando se llama closeModal().activeModal.dismiss se invoca.activeModal.dismiss.

Tests en este archivo: 16.

src/app/features/labels/components/labels-filter/labels-filter.component.spec.ts​

  • SUT: LabelsFilterComponent (filtro por nombre y estado, emite filterApply y filterReset).
  • Mocking: TestBed con FormsModule y TranslateModule con TranslateFakeLoader; sin servicios. Los EventEmitter se espían con spyOn(component.filterApply, 'emit').

LabelsFilterComponent​

it()EscenarioResultado esperadoMocks/spies
should createDado el componente inicializado.El componente existe.Ninguno.
should start with empty filterFormDado el estado inicial.filterForm es { name: '', isActive: '' }.Ninguno.
should start with activeFiltersCount = 0Dado el estado inicial.activeFiltersCount es 0.Ninguno.
onApply: should emit empty filter when form is blankDado un formulario en blanco.Emite {} y el contador sigue en 0.spyOn(filterApply, 'emit').
onApply: should include name when filled inDado name igual a VIP.Emite un objeto con name: 'VIP' y el contador es 1.spyOn(filterApply, 'emit').
onApply: should trim whitespace from nameDado name igual a VIP (borde).Emite name: 'VIP' sin espacios.spyOn(filterApply, 'emit').
onApply: should include isActive=true when "true" selectedDado isActive igual a 'true'.Emite isActive: true (booleano).spyOn(filterApply, 'emit').
onApply: should include isActive=false when "false" selectedDado isActive igual a 'false'.Emite isActive: false (booleano).spyOn(filterApply, 'emit').
onApply: should NOT include isActive when empty string selectedDado isActive igual a ''.El objeto emitido no contiene la clave isActive.spyOn(filterApply, 'emit').
onApply: should count both filters when both are setDado name VIP e isActive 'true'.activeFiltersCount es 2.Ninguno.
onReset: should reset form to empty stateDado un formulario con valores, cuando se llama onReset().filterForm vuelve a { name: '', isActive: '' }.Ninguno.
onReset: should reset activeFiltersCount to 0Dado activeFiltersCount = 2.El contador pasa a 0.Ninguno.
onReset: should emit filterResetCuando se llama onReset().filterReset.emit se invoca.spyOn(filterReset, 'emit').

Tests en este archivo: 13.

src/app/features/labels/components/labels-table/labels-table.component.spec.ts​

  • SUT: LabelsTableComponent (tabla paginada de etiquetas con filtros y modal).
  • Mocking: TestBed con TranslateModule y TranslateFakeLoader. LabelService (createSpyObj: findLabelsPaginated, removeLabel, ambos con of(...)) y NgbModal (open). El modal se simula con un NgbModalRef falso (componentInstance: {}, closed: of('saved')).

LabelsTableComponent​

it()EscenarioResultado esperadoMocks/spies
should createDado el componente inicializado.El componente existe.Ninguno.
should call findLabelsPaginated on initDado ngOnInit.findLabelsPaginated se llama con (1, 10, {}).findLabelsPaginated.
should populate labels after loadDada una respuesta con una etiqueta.labels es [mockLabel].findLabelsPaginated.
should set isLoading to false after loadTras la carga inicial.isLoading es false.findLabelsPaginated.
onFilterApply: should reset to page 1 and fetch with new filterCuando se aplica el filtro { name: 'VIP' }.Consulta (1, 10, { name: 'VIP' }).calls.reset() previo.
onFilterReset: should reset to page 1 and fetch with empty filterDado un filtro aplicado, cuando se resetea.Consulta (1, 10, {}).calls.reset() previo.
onPageChange: should fetch the requested pageCuando se pide la página 3.Consulta (3, 10, {}).calls.reset() previo.
onLimitChange: should fetch page 1 with new limitCuando el límite pasa a 50.Consulta (1, 50, {}).calls.reset() previo.
onDelete: should call removeLabel with _id and reloadCuando se elimina mockLabel.removeLabel se llama con oid-001 y se recarga la lista.removeLabel, findLabelsPaginated.
openModal: should open modal with ADD action and no labelCuando se abre el modal en modo ADD.modal.open se llama, action es ADD, label es undefined y se recarga al cerrar con saved.NgbModal.open devuelve la ref falsa.
openModal: should pass the label for EDIT actionCuando se abre en modo EDIT con una etiqueta.componentInstance.label es mockLabel.NgbModal.open devuelve la ref falsa.

Tests en este archivo: 11.

Respuestas rápidas​

src/app/features/quick-responses/components/quick-response-modal-form/quick-response-modal-form.component.spec.ts​

  • SUT: QuickResponseModalFormComponent (modal de alta, edición y vista de respuesta rápida).
  • Mocking: TestBed con ReactiveFormsModule y TranslateModule con TranslateFakeLoader. NgbActiveModal (close, dismiss) y QuickResponseService (create, update) como createSpyObj. Fixture mockRecord.

ADD action​

it()EscenarioResultado esperadoMocks/spies
should createDado action = ADD.El componente existe.Ninguno.
should set titleModal to add keyDado action = ADD.titleModal es quickResponses.modal.add.Ninguno.
should build an enabled formDado action = ADD.El formulario existe y está habilitado.Ninguno.
should be invalid when form is emptyDado el formulario vacío.Formulario inválido.Ninguno.
should be valid with shortcut and message filledDado shortcut /hi, message Hello! e isActive.Formulario válido.Ninguno.
onSubmit: should call create and close modal on valid formDado un formulario válido, al enviar.create se llama con el valor del formulario y close con saved.create devuelve of(mockRecord); activeModal.close.
onSubmit: should NOT call create when form is invalidDado un formulario vacío (fallo).create no se llama.create.

EDIT action​

it()EscenarioResultado esperadoMocks/spies
should set titleModal to edit keyDado action = EDIT con registro.titleModal es quickResponses.modal.edit.Ninguno.
should populate form with record valuesDado action = EDIT.El formulario contiene shortcut, message e isActive del registro.Ninguno.
onSubmit: should call update with identifier and close modalDado action = EDIT, al enviar.update se llama con uuid-001 (el identifier, no el _id) y el valor del formulario; close con saved.update devuelve of(mockRecord); activeModal.close.

VIEW action​

it()EscenarioResultado esperadoMocks/spies
should set titleModal to view keyDado action = VIEW.titleModal es quickResponses.modal.view.Ninguno.
should disable the formDado action = VIEW.El formulario está deshabilitado.Ninguno.
onSubmit: should NOT call create or updateDado modo VIEW, al enviar (borde).No se llama a create ni a update.create, update.

Nivel raíz​

it()EscenarioResultado esperadoMocks/spies
closeModal: should call activeModal.dismissDado modo ADD, al llamar closeModal().activeModal.dismiss se invoca.activeModal.dismiss.

Tests en este archivo: 14.

src/app/features/quick-responses/components/quick-responses-filter/quick-responses-filter.component.spec.ts​

  • SUT: QuickResponsesFilterComponent (filtro por atajo y estado).
  • Mocking: TestBed con FormsModule y TranslateModule con TranslateFakeLoader; sin servicios. spyOn sobre los EventEmitter filterApply y filterReset.

QuickResponsesFilterComponent​

it()EscenarioResultado esperadoMocks/spies
should createDado el componente inicializado.El componente existe.Ninguno.
should start with empty filterFormDado el estado inicial.filterForm es { shortcut: '', isActive: '' }.Ninguno.
should start with activeFiltersCount = 0Dado el estado inicial.El contador es 0.Ninguno.
onApply: should emit empty filter when form is blankDado un formulario en blanco.Emite {} y el contador es 0.spyOn(filterApply, 'emit').
onApply: should include shortcut when filled inDado shortcut /hi.Emite shortcut: '/hi' y el contador es 1.spyOn(filterApply, 'emit').
onApply: should trim whitespace from shortcutDado shortcut /hi (borde).Emite shortcut: '/hi'.spyOn(filterApply, 'emit').
onApply: should include isActive=true when "true" selectedDado isActive 'true'.Emite isActive: true.spyOn(filterApply, 'emit').
onApply: should include isActive=false when "false" selectedDado isActive 'false'.Emite isActive: false.spyOn(filterApply, 'emit').
onApply: should count both filters when both are setDados shortcut e isActive informados.activeFiltersCount es 2.Ninguno.
onReset: should reset form to empty stateDado un formulario con valores.filterForm vuelve a su estado vacío.Ninguno.
onReset: should reset activeFiltersCount to 0Dado activeFiltersCount = 2.El contador pasa a 0.Ninguno.
onReset: should emit filterResetAl llamar onReset().filterReset.emit se invoca.spyOn(filterReset, 'emit').

Tests en este archivo: 12. A diferencia del filtro de etiquetas, no hay caso que verifique que isActive en '' se omite del objeto emitido.

src/app/features/quick-responses/components/quick-responses-table/quick-responses-table.component.spec.ts​

  • SUT: QuickResponsesTableComponent (tabla paginada con filtros, activación y modal).
  • Mocking: TestBed con TranslateModule y TranslateFakeLoader. QuickResponseService (findPaginated, toggleActive, remove, todos con of(...)) y NgbModal (open) con NgbModalRef falso.

QuickResponsesTableComponent​

it()EscenarioResultado esperadoMocks/spies
should createDado el componente inicializado.El componente existe.Ninguno.
should call findPaginated on initDado ngOnInit.findPaginated se llama con (1, 10, {}).findPaginated.
should populate quickResponses after loadDada una respuesta con un registro.quickResponses es [mockRecord].findPaginated.
should set isLoading to false after loadTras la carga.isLoading es false.findPaginated.
onFilterApply: should reset to page 1 and fetch with new filterCon filtro { shortcut: '/hi' }.Consulta (1, 10, { shortcut: '/hi' }).calls.reset() previo.
onFilterReset: should reset to page 1 and fetch with empty filterDado un filtro aplicado, al resetear.Consulta (1, 10, {}).calls.reset() previo.
onPageChange: should fetch the requested pageAl pedir la página 2.Consulta (2, 10, {}).calls.reset() previo.
onLimitChange: should fetch page 1 with new limitAl cambiar el límite a 50.Consulta (1, 50, {}).calls.reset() previo.
onToggleActive: should call toggleActive with identifier and reloadAl activar o desactivar mockRecord.toggleActive se llama con uuid-001 y se recarga la lista.toggleActive, findPaginated.
openModal: should open modal with action and recordAl abrir el modal en modo EDIT con registro.modal.open se llama, action es EDIT, quickResponse es el registro y se recarga al cerrar con saved.NgbModal.open devuelve la ref falsa.
openModal: should open modal without record for ADD actionAl abrir en modo ADD sin registro.quickResponse es undefined.NgbModal.open devuelve la ref falsa.

Tests en este archivo: 11. El spec declara remove en el spy, pero ningún it() lo ejercita.

Tickets bloqueados​

src/app/features/locked-tickets/components/locked-tickets-table/locked-tickets-table.component.spec.ts​

  • SUT: LockedTicketsTableComponent (vista de administración de tickets bloqueados; servicio simple y ngx-datatable, sin NgRx).
  • Mocking: TestBed con TranslateModule y TranslateFakeLoader. TicketService (getLockedTickets, forceUnlockTicket, con of(...)) y ConfirmDialogService (confirm, que devuelve Promise). Los tests de releaseTicket son async y avanzan microtareas con await Promise.resolve().

LockedTicketsTableComponent​

it()EscenarioResultado esperadoMocks/spies
should createDado el componente inicializado.El componente existe.Ninguno.
calls getLockedTickets(page:1, limit:10) on initDado ngOnInit.getLockedTickets se llama con { page: 1, limit: 10 }.getLockedTickets.
populates tickets from the responseDada la respuesta con un ticket.tickets es [mockLockedTicket].getLockedTickets.
sets isLoading to false after loadTras la carga.isLoading es false.getLockedTickets.

onPageChange​

it()EscenarioResultado esperadoMocks/spies
fetches the requested pageAl pedir la página 3.Consulta con { page: 3, limit: 10 }.calls.reset() previo.

onLimitChange​

it()EscenarioResultado esperadoMocks/spies
resets to page 1 with the new limitAl cambiar el límite a 50.Consulta con { page: 1, limit: 50 }.calls.reset() previo.

getContactName​

it()EscenarioResultado esperadoMocks/spies
joins firstname + lastNameDado un ticket con contacto Ada Lovelace.Devuelve Ada Lovelace.Ninguno.
returns an empty string when there is no contactDado un ticket sin contact (borde).Devuelve cadena vacía.Ninguno.

getLockedByName​

it()EscenarioResultado esperadoMocks/spies
joins the lockedByUser firstname + lastNameDado un ticket bloqueado por Grace Hopper.Devuelve Grace Hopper.Ninguno.
returns an empty string when lockedByUser is absentDado un ticket sin lockedByUser (borde).Devuelve cadena vacía.Ninguno.

releaseTicket​

it()EscenarioResultado esperadoMocks/spies
does NOT call forceUnlockTicket when the confirmation is cancelledDado que el usuario cancela la confirmación.forceUnlockTicket no se llama.confirm devuelve Promise.resolve(false).
calls forceUnlockTicket and reloads the list when confirmedDado que el usuario confirma.forceUnlockTicket se llama con ticket-1 y se vuelve a consultar getLockedTickets.confirm devuelve Promise.resolve(true); calls.reset() previo.

Tests en este archivo: 12.

Control de acceso​

src/app/features/access-control/features/modules/components/modules-table/modules-table.component.spec.ts​

  • SUT: ModulesTableComponent (tabla de módulos del sistema).
  • Mocking: TestBed con TranslateModule.forRoot y TranslateFakeLoader. SystemModuleService (createSpyObj: getAll, remove; getAll devuelve of([])) y NgbModal como objeto vacío. Helper buildComponent() para crear el fixture.

ModulesTableComponent​

it()EscenarioResultado esperadoMocks/spies
loads modules on initDado un servicio que devuelve lista vacía, al llamar ngOnInit().getAll se invoca.getAll devuelve of([]).

Tests en este archivo: 1.

Contactos​

src/app/features/contacts/contacts-routing.module.spec.ts​

  • SUT: constante routes de contacts-routing.module (cableado de permisos).
  • Mocking: sin TestBed ni espías; importa routes y permissionGuard y comprueba la configuración de la ruta.

ContactsRoutingModule routes (permission wiring)​

it()EscenarioResultado esperadoMocks/spies
should gate the contacts page route on CONTACT_READ via permissionGuardDada la ruta con path === ''.data es { permission: 'CONTACT_READ' } y canActivate contiene permissionGuard.Ninguno.

Tests en este archivo: 1.

Total de la página​

SpecTests
department-modal.component.spec.ts21
label-modal-form.component.spec.ts16
labels-filter.component.spec.ts13
labels-table.component.spec.ts11
quick-response-modal-form.component.spec.ts14
quick-responses-filter.component.spec.ts12
quick-responses-table.component.spec.ts11
locked-tickets-table.component.spec.ts12
modules-table.component.spec.ts1
contacts-routing.module.spec.ts1
Total112