diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e6d5cf8..09a3aaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -110,38 +110,25 @@ backend_pytest: path: coverage.xml interruptible: true -# backend_pytest: -# stage: test -# image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:23-dind -# services: -# - name: docker:dind -# entrypoint: ["dockerd-entrypoint.sh", "--tls=false"] -# needs: [] -# script: -# - if [[ "$CI_PROJECT_PATH" != "bec/bec_atlas" ]]; then -# apk update; apk add git; echo -e "\033[35;1m Using branch $CHILD_PIPELINE_BRANCH of BEC Atlas \033[0;m"; -# test -d bec_atlas || git clone --branch $CHILD_PIPELINE_BRANCH https://gitlab.psi.ch/bec/bec_atlas.git; cd bec_atlas; -# TARGET_BRANCH=$CHILD_PIPELINE_BRANCH; -# else -# TARGET_BRANCH=$CI_COMMIT_REF_NAME; -# fi -# # start services -# - docker-compose -f ./backend/tests/docker-compose.yml up -d - -# # build test environment -# - echo "$CI_DEPENDENCY_PROXY_PASSWORD" | docker login $CI_DEPENDENCY_PROXY_SERVER --username $CI_DEPENDENCY_PROXY_USER --password-stdin -# - docker build -t bec_atlas_backend:test -f ./backend/tests/Dockerfile.run_pytest --build-arg PY_VERSION=3.10 --build-arg BEC_ATLAS_BRANCH=$TARGET_BRANCH --build-arg BEC_CORE_BRANCH=$BEC_CORE_BRANCH --build-arg CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX . -# - docker run --network=host --name bec_atlas_backend bec_atlas_backend:test -# after_script: -# - docker cp bec_atlas_backend:/code/bec_atlas/test_files/. $CI_PROJECT_DIR -# coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' -# artifacts: -# reports: -# junit: report.xml -# coverage_report: -# coverage_format: cobertura -# path: coverage.xml -# interruptible: true +frontend_test: + stage: test + image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/cypress/browsers:22.13.1 + needs: [] + before_script: + - cd frontend/bec_atlas + script: + - npm install + - npx ng test --no-watch --no-progress --browsers=ChromeHeadlessCI --code-coverage + - cp ./coverage/cobertura-coverage.xml ../../cobertura-coverage.xml + - cp ./coverage/junit-report.xml ../../junit-report.xml + coverage: '/^Statements\s*:\s*([^%]+)/' + artifacts: + reports: + junit: junit-report.xml + coverage_report: + coverage_format: cobertura + path: cobertura-coverage.xml + interruptible: true # semver: # stage: Deploy diff --git a/frontend/bec_atlas/angular.json b/frontend/bec_atlas/angular.json index 9718572..d97e87b 100644 --- a/frontend/bec_atlas/angular.json +++ b/frontend/bec_atlas/angular.json @@ -91,7 +91,8 @@ "@angular/material/prebuilt-themes/cyan-orange.css", "src/styles.scss" ], - "scripts": [] + "scripts": [], + "karmaConfig": "karma.conf.js" } } } diff --git a/frontend/bec_atlas/karma.conf.js b/frontend/bec_atlas/karma.conf.js new file mode 100644 index 0000000..408b89d --- /dev/null +++ b/frontend/bec_atlas/karma.conf.js @@ -0,0 +1,51 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma'), + require('karma-junit-reporter') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, './coverage'), + subdir: '.', + reporters: [ + { type: 'cobertura'}, + { type: 'html' }, + { type: 'text-summary' }, + ] + }, + junitReporter: { + outputDir: './coverage', + outputFile: 'junit-report.xml', + useBrowserName: false + }, + reporters: ['progress', 'kjhtml', 'junit' ], + browsers: ['ChromeHeadlessCI'], + customLaunchers: { + ChromeHeadlessCI: { + base: 'ChromeHeadless', + flags: ['--no-sandbox'] + } + }, + restartOnFileChange: true + }); +}; diff --git a/frontend/bec_atlas/package-lock.json b/frontend/bec_atlas/package-lock.json index 6c8e560..af76fbb 100644 --- a/frontend/bec_atlas/package-lock.json +++ b/frontend/bec_atlas/package-lock.json @@ -39,6 +39,7 @@ "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", + "karma-junit-reporter": "^2.0.1", "typescript": "~5.6.2" } }, @@ -10576,6 +10577,23 @@ "dev": true, "license": "MIT" }, + "node_modules/karma-junit-reporter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", + "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-is-absolute": "^1.0.0", + "xmlbuilder": "12.0.0" + }, + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "karma": ">=0.9" + } + }, "node_modules/karma-source-map-support": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", @@ -16762,6 +16780,16 @@ } } }, + "node_modules/xmlbuilder": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", + "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", diff --git a/frontend/bec_atlas/package.json b/frontend/bec_atlas/package.json index 6ec1294..5b2c603 100644 --- a/frontend/bec_atlas/package.json +++ b/frontend/bec_atlas/package.json @@ -41,6 +41,7 @@ "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", + "karma-junit-reporter": "^2.0.1", "typescript": "~5.6.2" } } diff --git a/frontend/bec_atlas/src/app/app-config.service.spec.ts b/frontend/bec_atlas/src/app/app-config.service.spec.ts index ee08175..1b5d128 100644 --- a/frontend/bec_atlas/src/app/app-config.service.spec.ts +++ b/frontend/bec_atlas/src/app/app-config.service.spec.ts @@ -1,13 +1,24 @@ import { TestBed } from '@angular/core/testing'; - +import { + HttpTestingController, + provideHttpClientTesting, +} from '@angular/common/http/testing'; import { AppConfigService } from './app-config.service'; +import { provideHttpClient } from '@angular/common/http'; describe('AppConfigService', () => { let service: AppConfigService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + AppConfigService, + ], + }); service = TestBed.inject(AppConfigService); + const httpTesting = TestBed.inject(HttpTestingController); }); it('should be created', () => { diff --git a/frontend/bec_atlas/src/app/app.component.spec.ts b/frontend/bec_atlas/src/app/app.component.spec.ts index 05c8e91..6764694 100644 --- a/frontend/bec_atlas/src/app/app.component.spec.ts +++ b/frontend/bec_atlas/src/app/app.component.spec.ts @@ -19,11 +19,4 @@ describe('AppComponent', () => { const app = fixture.componentInstance; expect(app.title).toEqual('bec_atlas'); }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, bec_atlas'); - }); }); diff --git a/frontend/bec_atlas/src/app/core/auth.service.spec.ts b/frontend/bec_atlas/src/app/core/auth.service.spec.ts index f1251ca..50abaaa 100644 --- a/frontend/bec_atlas/src/app/core/auth.service.spec.ts +++ b/frontend/bec_atlas/src/app/core/auth.service.spec.ts @@ -1,13 +1,28 @@ import { TestBed } from '@angular/core/testing'; import { AuthService } from './auth.service'; +import { provideHttpClient } from '@angular/common/http'; +import { + HttpTestingController, + provideHttpClientTesting, +} from '@angular/common/http/testing'; +import { AppConfigService } from '../app-config.service'; describe('AuthService', () => { let service: AuthService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + AuthService, + AppConfigService, + ], + }); service = TestBed.inject(AuthService); + const appConfigService = TestBed.inject(AppConfigService); + const httpTesting = TestBed.inject(HttpTestingController); }); it('should be created', () => { diff --git a/frontend/bec_atlas/src/app/core/redis-connector.service.spec.ts b/frontend/bec_atlas/src/app/core/redis-connector.service.spec.ts index d573991..94bc038 100644 --- a/frontend/bec_atlas/src/app/core/redis-connector.service.spec.ts +++ b/frontend/bec_atlas/src/app/core/redis-connector.service.spec.ts @@ -1,13 +1,31 @@ import { TestBed } from '@angular/core/testing'; import { RedisConnectorService } from './redis-connector.service'; +import { AppConfigService } from '../app-config.service'; +import { provideHttpClient } from '@angular/common/http'; +import { + HttpTestingController, + provideHttpClientTesting, +} from '@angular/common/http/testing'; +import { DeploymentService } from '../deployment.service'; describe('RedisConnectorService', () => { let service: RedisConnectorService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + RedisConnectorService, + DeploymentService, + AppConfigService, + ], + }); service = TestBed.inject(RedisConnectorService); + const appConfigService = TestBed.inject(AppConfigService); + const httpTesting = TestBed.inject(HttpTestingController); + const deploymentService = TestBed.inject(DeploymentService); }); it('should be created', () => { diff --git a/frontend/bec_atlas/src/app/core/remote-data.service.spec.ts b/frontend/bec_atlas/src/app/core/remote-data.service.spec.ts index 653e555..613bdd8 100644 --- a/frontend/bec_atlas/src/app/core/remote-data.service.spec.ts +++ b/frontend/bec_atlas/src/app/core/remote-data.service.spec.ts @@ -1,13 +1,28 @@ import { TestBed } from '@angular/core/testing'; import { RemoteDataService } from './remote-data.service'; +import { provideHttpClient } from '@angular/common/http'; +import { + HttpTestingController, + provideHttpClientTesting, +} from '@angular/common/http/testing'; +import { AppConfigService } from '../app-config.service'; describe('RemoteDataService', () => { let service: RemoteDataService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + RemoteDataService, + AppConfigService, + ], + }); service = TestBed.inject(RemoteDataService); + const httpTesting = TestBed.inject(HttpTestingController); + const appConfigService = TestBed.inject(AppConfigService); }); it('should be created', () => { diff --git a/frontend/bec_atlas/src/app/dashboard/dashboard.component.spec.ts b/frontend/bec_atlas/src/app/dashboard/dashboard.component.spec.ts index 30e39a2..4ed6858 100644 --- a/frontend/bec_atlas/src/app/dashboard/dashboard.component.spec.ts +++ b/frontend/bec_atlas/src/app/dashboard/dashboard.component.spec.ts @@ -1,6 +1,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DashboardComponent } from './dashboard.component'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { AppConfigService } from '../app-config.service'; +import { ActivatedRoute, provideRouter } from '@angular/router'; describe('DashboardComponent', () => { let component: DashboardComponent; @@ -8,9 +12,20 @@ describe('DashboardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [DashboardComponent] - }) - .compileComponents(); + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + AppConfigService, + provideRouter([]), + { + provide: ActivatedRoute, + useValue: { + snapshot: { paramMap: new Map() }, // Mocks route params + }, + }, + ], + imports: [DashboardComponent], + }).compileComponents(); fixture = TestBed.createComponent(DashboardComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/deployment-admin/deployment-admin.component.spec.ts b/frontend/bec_atlas/src/app/deployment-admin/deployment-admin.component.spec.ts index 0cd6bf5..7bbdc78 100644 --- a/frontend/bec_atlas/src/app/deployment-admin/deployment-admin.component.spec.ts +++ b/frontend/bec_atlas/src/app/deployment-admin/deployment-admin.component.spec.ts @@ -1,6 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DeploymentAdminComponent } from './deployment-admin.component'; +import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; describe('DeploymentAdminComponent', () => { let component: DeploymentAdminComponent; @@ -8,9 +9,9 @@ describe('DeploymentAdminComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [DeploymentAdminComponent] - }) - .compileComponents(); + providers: [DeploymentAdminComponent, provideAnimationsAsync()], + imports: [DeploymentAdminComponent], + }).compileComponents(); fixture = TestBed.createComponent(DeploymentAdminComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/deployment-selection/deployment-selection.component.spec.ts b/frontend/bec_atlas/src/app/deployment-selection/deployment-selection.component.spec.ts index 2380d32..6ad6620 100644 --- a/frontend/bec_atlas/src/app/deployment-selection/deployment-selection.component.spec.ts +++ b/frontend/bec_atlas/src/app/deployment-selection/deployment-selection.component.spec.ts @@ -1,6 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DeploymentSelectionComponent } from './deployment-selection.component'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { AppConfigService } from '../app-config.service'; +import { MatDialogRef } from '@angular/material/dialog'; +import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; describe('DeploymentSelectionComponent', () => { let component: DeploymentSelectionComponent; @@ -8,9 +13,18 @@ describe('DeploymentSelectionComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [DeploymentSelectionComponent] - }) - .compileComponents(); + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + { + provide: MatDialogRef, + useValue: {}, + }, + provideAnimationsAsync(), + AppConfigService, + ], + imports: [DeploymentSelectionComponent], + }).compileComponents(); fixture = TestBed.createComponent(DeploymentSelectionComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/deployment.service.spec.ts b/frontend/bec_atlas/src/app/deployment.service.spec.ts index ac55044..55a87c3 100644 --- a/frontend/bec_atlas/src/app/deployment.service.spec.ts +++ b/frontend/bec_atlas/src/app/deployment.service.spec.ts @@ -1,12 +1,22 @@ import { TestBed } from '@angular/core/testing'; import { DeploymentService } from './deployment.service'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { AppConfigService } from './app-config.service'; describe('DeploymentService', () => { let service: DeploymentService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + DeploymentService, + AppConfigService, + ], + }); service = TestBed.inject(DeploymentService); }); diff --git a/frontend/bec_atlas/src/app/device-box/device-box.component.spec.ts b/frontend/bec_atlas/src/app/device-box/device-box.component.spec.ts index 0992233..c41dc8c 100644 --- a/frontend/bec_atlas/src/app/device-box/device-box.component.spec.ts +++ b/frontend/bec_atlas/src/app/device-box/device-box.component.spec.ts @@ -1,6 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DeviceBoxComponent } from './device-box.component'; +import { RedisConnectorService } from '../core/redis-connector.service'; +import { AppConfigService } from '../app-config.service'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { DeploymentService } from '../deployment.service'; describe('DeviceBoxComponent', () => { let component: DeviceBoxComponent; @@ -8,9 +13,16 @@ describe('DeviceBoxComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [DeviceBoxComponent] - }) - .compileComponents(); + providers: [ + DeviceBoxComponent, + RedisConnectorService, + AppConfigService, + provideHttpClient(), + provideHttpClientTesting(), + DeploymentService, + ], + imports: [DeviceBoxComponent], + }).compileComponents(); fixture = TestBed.createComponent(DeviceBoxComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/gridstack-test/gridstack-test.component.spec.ts b/frontend/bec_atlas/src/app/gridstack-test/gridstack-test.component.spec.ts index 0f441a7..b9ac093 100644 --- a/frontend/bec_atlas/src/app/gridstack-test/gridstack-test.component.spec.ts +++ b/frontend/bec_atlas/src/app/gridstack-test/gridstack-test.component.spec.ts @@ -1,18 +1,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { GridstackTestComponent } from './gridstack-test.component'; +import { GridStackTestComponent } from './gridstack-test.component'; describe('GridstackTestComponent', () => { - let component: GridstackTestComponent; - let fixture: ComponentFixture; + let component: GridStackTestComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [GridstackTestComponent] - }) - .compileComponents(); + imports: [GridStackTestComponent], + }).compileComponents(); - fixture = TestBed.createComponent(GridstackTestComponent); + fixture = TestBed.createComponent(GridStackTestComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/frontend/bec_atlas/src/app/login/login.component.spec.ts b/frontend/bec_atlas/src/app/login/login.component.spec.ts index 18f3685..c0cf1e5 100644 --- a/frontend/bec_atlas/src/app/login/login.component.spec.ts +++ b/frontend/bec_atlas/src/app/login/login.component.spec.ts @@ -1,6 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { LoginComponent } from './login.component'; +import { AppConfigService } from '../app-config.service'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { ActivatedRoute, provideRouter } from '@angular/router'; +import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; describe('LoginComponent', () => { let component: LoginComponent; @@ -8,9 +13,21 @@ describe('LoginComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [LoginComponent] - }) - .compileComponents(); + providers: [ + provideHttpClient(), + provideHttpClientTesting(), + provideRouter([]), + provideAnimationsAsync(), + { + provide: ActivatedRoute, + useValue: { + snapshot: { paramMap: new Map() }, // Mocks route params + }, + }, + AppConfigService, + ], + imports: [LoginComponent], + }).compileComponents(); fixture = TestBed.createComponent(LoginComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/queue-table/queue-table.component.spec.ts b/frontend/bec_atlas/src/app/queue-table/queue-table.component.spec.ts index 5e23b25..77a941f 100644 --- a/frontend/bec_atlas/src/app/queue-table/queue-table.component.spec.ts +++ b/frontend/bec_atlas/src/app/queue-table/queue-table.component.spec.ts @@ -1,6 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { QueueTableComponent } from './queue-table.component'; +import { RedisConnectorService } from '../core/redis-connector.service'; +import { AppConfigService } from '../app-config.service'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { DeploymentService } from '../deployment.service'; describe('QueueTableComponent', () => { let component: QueueTableComponent; @@ -8,9 +13,16 @@ describe('QueueTableComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [QueueTableComponent] - }) - .compileComponents(); + providers: [ + QueueTableComponent, + RedisConnectorService, + AppConfigService, + provideHttpClient(), + provideHttpClientTesting(), + DeploymentService, + ], + imports: [QueueTableComponent], + }).compileComponents(); fixture = TestBed.createComponent(QueueTableComponent); component = fixture.componentInstance; diff --git a/frontend/bec_atlas/src/app/server-settings.service.spec.ts b/frontend/bec_atlas/src/app/server-settings.service.spec.ts index 49e700f..57d4044 100644 --- a/frontend/bec_atlas/src/app/server-settings.service.spec.ts +++ b/frontend/bec_atlas/src/app/server-settings.service.spec.ts @@ -1,12 +1,22 @@ import { TestBed } from '@angular/core/testing'; import { ServerSettingsService } from './server-settings.service'; +import { AppConfigService } from './app-config.service'; +import { provideHttpClient } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; describe('ServerSettingsService', () => { let service: ServerSettingsService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + ServerSettingsService, + AppConfigService, + provideHttpClient(), + provideHttpClientTesting(), + ], + }); service = TestBed.inject(ServerSettingsService); });