diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 3678926a..5e3e5c23 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -84,3 +84,24 @@ jobs: for OPTS_NAME in ANMS_COMPOSE_OPTS TESTENV_COMPOSE_OPTS; do ${DOCKER_CMD} compose ${!OPTS_NAME} down --remove-orphans done + + anms-ui-unit-test: + runs-on: ubuntu-24.04 + name: ANMS UI Unit Tests + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + submodules: true + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'npm' + cache-dependency-path: anms-ui/package-lock.json + - name: Install dependencies + working-directory: anms-ui + run: npm ci + - name: Run unit tests + working-directory: anms-ui + run: npx ng test --runner=vitest --no-watch diff --git a/anms-ui/src/app/app.spec.ts b/anms-ui/src/app/app.spec.ts index e9c46769..770b0d29 100644 --- a/anms-ui/src/app/app.spec.ts +++ b/anms-ui/src/app/app.spec.ts @@ -1,3 +1,4 @@ +import { provideRouter } from '@angular/router'; import { TestBed } from '@angular/core/testing'; import { App } from './app'; @@ -5,6 +6,7 @@ describe('App', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [App], + providers: [provideRouter([])], }).compileComponents(); }); @@ -14,10 +16,10 @@ describe('App', () => { expect(app).toBeTruthy(); }); - it('should render title', async () => { + it('should render router outlet', async () => { const fixture = TestBed.createComponent(App); await fixture.whenStable(); const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, anms-ui'); + expect(compiled.querySelector('router-outlet')).toBeTruthy(); }); }); diff --git a/anms-ui/src/app/features/adms/adms.spec.ts b/anms-ui/src/app/features/adms/adms.spec.ts index 35f792be..b0486dae 100644 --- a/anms-ui/src/app/features/adms/adms.spec.ts +++ b/anms-ui/src/app/features/adms/adms.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Adms } from './adms'; @@ -8,7 +11,8 @@ describe('Adms', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Adms], + imports: [Adms, HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], }).compileComponents(); fixture = TestBed.createComponent(Adms); diff --git a/anms-ui/src/app/features/dashboard/components/dashboard-home/dashboard-home.spec.ts b/anms-ui/src/app/features/dashboard/components/dashboard-home/dashboard-home.spec.ts index 3712b29c..3543a2c7 100644 --- a/anms-ui/src/app/features/dashboard/components/dashboard-home/dashboard-home.spec.ts +++ b/anms-ui/src/app/features/dashboard/components/dashboard-home/dashboard-home.spec.ts @@ -1,3 +1,4 @@ +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DashboardHome } from './dashboard-home'; @@ -9,6 +10,7 @@ describe('DashboardHome', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [DashboardHome], + providers: [provideRouter([])], }).compileComponents(); fixture = TestBed.createComponent(DashboardHome); diff --git a/anms-ui/src/app/features/dashboard/dashboard.spec.ts b/anms-ui/src/app/features/dashboard/dashboard.spec.ts index 2ce950a7..77f9e0e5 100644 --- a/anms-ui/src/app/features/dashboard/dashboard.spec.ts +++ b/anms-ui/src/app/features/dashboard/dashboard.spec.ts @@ -1,3 +1,7 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Dashboard } from './dashboard'; @@ -8,9 +12,17 @@ describe('Dashboard', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Dashboard], + imports: [Dashboard, HttpClientTestingModule], + providers: [ + provideHttpClient(), + provideToastr(), + provideRouter([]), + ], }).compileComponents(); + // Provide DOM element that sidebar.ngAfterViewInit looks for + document.body.innerHTML = '
'; + fixture = TestBed.createComponent(Dashboard); component = fixture.componentInstance; await fixture.whenStable(); diff --git a/anms-ui/src/app/features/management/agents/agent-modal/agent-modal.spec.ts b/anms-ui/src/app/features/management/agents/agent-modal/agent-modal.spec.ts index c933085f..9ac238f6 100644 --- a/anms-ui/src/app/features/management/agents/agent-modal/agent-modal.spec.ts +++ b/anms-ui/src/app/features/management/agents/agent-modal/agent-modal.spec.ts @@ -1,3 +1,7 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import {AgentModal} from './agent-modal'; @@ -8,7 +12,13 @@ describe('AgentModal', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AgentModal], + imports: [AgentModal, HttpClientTestingModule], + providers: [ + provideHttpClient(), + provideToastr(), + { provide: MatDialogRef, useValue: { close: () => {} } }, + { provide: MAT_DIALOG_DATA, useValue: {} }, + ], }).compileComponents(); fixture = TestBed.createComponent(AgentModal); diff --git a/anms-ui/src/app/features/management/agents/agents.spec.ts b/anms-ui/src/app/features/management/agents/agents.spec.ts index 02cd1076..872f2192 100644 --- a/anms-ui/src/app/features/management/agents/agents.spec.ts +++ b/anms-ui/src/app/features/management/agents/agents.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Agents } from './agents'; @@ -8,7 +11,8 @@ describe('Agents', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Agents], + imports: [Agents, HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], }).compileComponents(); fixture = TestBed.createComponent(Agents); diff --git a/anms-ui/src/app/features/management/agents/crud/crud.spec.ts b/anms-ui/src/app/features/management/agents/crud/crud.spec.ts index 3bec17ff..f14077de 100644 --- a/anms-ui/src/app/features/management/agents/crud/crud.spec.ts +++ b/anms-ui/src/app/features/management/agents/crud/crud.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Crud } from './crud'; @@ -8,7 +11,8 @@ describe('Crud', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Crud], + imports: [Crud, HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], }).compileComponents(); fixture = TestBed.createComponent(Crud); diff --git a/anms-ui/src/app/features/management/agents/manage-agents-dialog/manage-agents-dialog.spec.ts b/anms-ui/src/app/features/management/agents/manage-agents-dialog/manage-agents-dialog.spec.ts index 45c0227c..2b18b211 100644 --- a/anms-ui/src/app/features/management/agents/manage-agents-dialog/manage-agents-dialog.spec.ts +++ b/anms-ui/src/app/features/management/agents/manage-agents-dialog/manage-agents-dialog.spec.ts @@ -1,3 +1,7 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ManageAgentsDialog } from './manage-agents-dialog'; @@ -8,7 +12,13 @@ describe('ManageAgentsDialog', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ManageAgentsDialog], + imports: [ManageAgentsDialog, HttpClientTestingModule], + providers: [ + provideHttpClient(), + provideToastr(), + { provide: MatDialogRef, useValue: { close: () => {} } }, + { provide: MAT_DIALOG_DATA, useValue: { agents: [] } }, + ], }).compileComponents(); fixture = TestBed.createComponent(ManageAgentsDialog); diff --git a/anms-ui/src/app/features/management/agents/reports/reports.spec.ts b/anms-ui/src/app/features/management/agents/reports/reports.spec.ts index b150686b..2be4bad6 100644 --- a/anms-ui/src/app/features/management/agents/reports/reports.spec.ts +++ b/anms-ui/src/app/features/management/agents/reports/reports.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Reports } from './reports'; @@ -8,7 +11,8 @@ describe('Reports', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Reports], + imports: [Reports, HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], }).compileComponents(); fixture = TestBed.createComponent(Reports); diff --git a/anms-ui/src/app/features/management/builder/builder.spec.ts b/anms-ui/src/app/features/management/builder/builder.spec.ts index ebd1aa59..baeb7753 100644 --- a/anms-ui/src/app/features/management/builder/builder.spec.ts +++ b/anms-ui/src/app/features/management/builder/builder.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Builder } from './builder'; @@ -8,7 +11,8 @@ describe('Builder', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Builder], + imports: [Builder, HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], }).compileComponents(); fixture = TestBed.createComponent(Builder); diff --git a/anms-ui/src/app/features/page-not-found/page-not-found.spec.ts b/anms-ui/src/app/features/page-not-found/page-not-found.spec.ts index 8024e435..62cd0225 100644 --- a/anms-ui/src/app/features/page-not-found/page-not-found.spec.ts +++ b/anms-ui/src/app/features/page-not-found/page-not-found.spec.ts @@ -1,3 +1,4 @@ +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PageNotFound } from './page-not-found'; @@ -9,6 +10,7 @@ describe('PageNotFound', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [PageNotFound], + providers: [provideRouter([])], }).compileComponents(); fixture = TestBed.createComponent(PageNotFound); diff --git a/anms-ui/src/app/features/status/status.spec.ts b/anms-ui/src/app/features/status/status.spec.ts index 38397a7b..67f64de1 100644 --- a/anms-ui/src/app/features/status/status.spec.ts +++ b/anms-ui/src/app/features/status/status.spec.ts @@ -1,3 +1,7 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Status } from './status'; @@ -8,7 +12,12 @@ describe('Status', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Status], + imports: [Status, HttpClientTestingModule], + providers: [ + provideHttpClient(), + provideToastr(), + provideRouter([]), + ], }).compileComponents(); fixture = TestBed.createComponent(Status); diff --git a/anms-ui/src/app/layout/header/header.spec.ts b/anms-ui/src/app/layout/header/header.spec.ts index 9ef7403f..5a648ba7 100644 --- a/anms-ui/src/app/layout/header/header.spec.ts +++ b/anms-ui/src/app/layout/header/header.spec.ts @@ -1,3 +1,4 @@ +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Header } from './header'; @@ -9,6 +10,7 @@ describe('Header', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [Header], + providers: [provideRouter([])], }).compileComponents(); fixture = TestBed.createComponent(Header); diff --git a/anms-ui/src/app/layout/sidebar/sidebar.spec.ts b/anms-ui/src/app/layout/sidebar/sidebar.spec.ts index 2f291a9a..e42f35f5 100644 --- a/anms-ui/src/app/layout/sidebar/sidebar.spec.ts +++ b/anms-ui/src/app/layout/sidebar/sidebar.spec.ts @@ -1,3 +1,7 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; +import { provideRouter } from '@angular/router'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Sidebar } from './sidebar'; @@ -8,9 +12,17 @@ describe('Sidebar', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [Sidebar], + imports: [Sidebar, HttpClientTestingModule], + providers: [ + provideHttpClient(), + provideToastr(), + provideRouter([]), + ], }).compileComponents(); + // Provide DOM element that sidebar.ngAfterViewInit looks for + document.body.innerHTML = '
'; + fixture = TestBed.createComponent(Sidebar); component = fixture.componentInstance; await fixture.whenStable(); diff --git a/anms-ui/src/app/store/modules/service-status.spec.ts b/anms-ui/src/app/store/modules/service-status.spec.ts index 12de1b8c..c3731b4b 100644 --- a/anms-ui/src/app/store/modules/service-status.spec.ts +++ b/anms-ui/src/app/store/modules/service-status.spec.ts @@ -1,3 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { provideToastr } from 'ngx-toastr'; import { TestBed } from '@angular/core/testing'; import {ServiceStatusService} from './service-status.service'; @@ -6,7 +9,10 @@ describe('StatusStore', () => { let service: ServiceStatusService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [provideHttpClient(), provideToastr()], + }); service = TestBed.inject(ServiceStatusService); });