diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c024c4699d..9b8d2e0273 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,29 +35,3 @@ jobs: uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} - frontend: - runs-on: ubuntu-latest - name: Run frontend karma tests - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Fetch version - working-directory: frontend - run: | - python fetch-version.py - - name: Install dependencies - working-directory: frontend - run: | - npm i -g @angular/cli - npm ci - CHROME_BIN="$(which chromium)" - export CHROME_BIN - - name: Run tests - working-directory: frontend - run: | - ng test --watch=false --browsers=ChromeHeadless diff --git a/docs/docs/development/frontend/testing.md b/docs/docs/development/frontend/testing.md deleted file mode 100644 index 25dc27ba6e..0000000000 --- a/docs/docs/development/frontend/testing.md +++ /dev/null @@ -1,105 +0,0 @@ - - -# Frontend Testing - -**Note:** While frontend testing is valuable, the process of writing and -maintaining such tests can be challenging and time-consuming in certain -instances. Therefore, our team does not require frontend tests for every -component or service. Please ensure that ".spec" files are only included if -they have active tests. Before writing tests, consider the overhead and weigh -it against the potential benefits. - -## Unit & Integration Testing - -### Technologies - -- We use [Jasmine] as testing framework -- [Karma] is used as test runner -- We use [istanbul] to measure and visualize the code coverage - -### Additional Sources - -- [Official angular testing guide] -- Recommended: [Detailed angular testing guide] - -### General - -#### Robust Component Tests - -When testing components, we must query the elements needed for the test. To -ensure that even if the element type or attributes changes, the element can -still be queried, we assign a `data-testId` to each needed element. This not -only increases robustness, but also makes it very easy to query elements. The -value assigned to the test id should clearly describe the usage of the element -and should not be too long. For example, one can use the schema -`data-testId=-` where the prefix usually describes the -general context (e.g., whether it is an input, button, textfield, etc.) and the -following description specifies the usage of it (e.g., createProject). - -#### Element Helper Functions - -Usually testing components consists of querying elements, applying changes to -them, triggering events on them, and then comparing the results with the -expected results. To reduce repetition and increase readability, one should use -existing helper functions or create new ones if none exist. - -### Executing Tests - -To execute the integration tests, one needs to run `make test`. However, in -some cases it is not possible to correctly set the `CHROME_BIN` that is needed -to generate the test output inside the browser. If this is the case, one should -either set the `CHORME_BIN` in the make file or simply run -`EXPORT CHROME_BIN=` followed by `ng test`. Beyond that, it is not -necessary to run anything else (e.g., the backend) for test execution. - -#### Output - -The resulting output in the browser considers three different cases: - -1. Green tests are _successful_ tests -2. Yellow tests (marked with a ☆) are _deactivated_ tests -3. Red tests are _failed_ tests - -The general code coverage statistics (i.e. statement, branch, function, and -line coverage) are output to the console. To also see what exactly is covered -and what is missing, one can open the `index.html` file in the -`/frontend/test-results/istanbul-coverage` folder. - -## End-to-End Testing - -### Technologies - -- We use [playwright] for E2E testing - -### Test Generation - -Playwright supports the generation of E2E tests by interacting with the -frontend and recording each action and input. This can be started by executing -`npx playwright codegen localhost:4200` but needs a running frontend and -backend to work. - -Test generation can significantly speed up test creation, but in general one -should only use the resulting test as a base and adjust it accordingly. For -example, check selectors and adjust them to make them more robust, or add more -expectations as needed. - -### Executing Tests - -To run the E2E tests, one must first make sure that a backend is running. If -that is the case, one can run `npx playwright test` to start the tests. In case -of an error the browser will be directly opened and show the last test report, -otherwise one can open it with `npx playwright show-report`. A very helpful -option when running the tests is `--trace on`. This provides, for example, a -screenshot of the action and the before/after state (for each step), contains a -detailed log, and one can also view the console output and network calls -performed. - -[jasmine]: https://jasmine.github.io -[karma]: https://karma-runner.github.io -[istanbul]: https://istanbul.js.org/ -[playwright]: https://playwright.dev -[official angular testing guide]: https://angular.dev/guide/testing -[detailed angular testing guide]: https://testing-angular.com/ diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index e132ac5d7e..53fa5662b9 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -119,7 +119,6 @@ nav: - Code Style: development/frontend/code-style.md - Responsive Design: development/frontend/responsive-design/mobile-view.md - Routes: development/frontend/routes.md - - Testing: development/frontend/testing.md - Customization: development/frontend/customize.md - Storybook: development/frontend/storybook.md - Kubernetes: diff --git a/frontend/angular.json b/frontend/angular.json index 1a5eb6da1e..9333204121 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -118,22 +118,6 @@ "buildTarget": "capellacollab:build" } }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.dev.ts" - } - ], - "codeCoverage": true - } - }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { diff --git a/frontend/karma.conf.js b/frontend/karma.conf.js deleted file mode 100644 index 811599ddb9..0000000000 --- a/frontend/karma.conf.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const webpack = require("webpack"); -const path = require("path"); - -const webpackConfig = { - mode: "development", - module: { - rules: [ - { - test: /\.ts$/, - loader: "tslint-loader", - exclude: /node_modules/, - enforce: "pre", - }, - { - test: /\.ts$/, - loader: "ts-loader?silent=true", - exclude: /node_modules/, - }, - { - test: /\.ts$/, - exclude: /(node_modules|\.spec\.ts$)/, - loader: "coverage-istanbul-loader", - enforce: "post", - options: { - esModules: true, - }, - }, - ], - }, - plugins: [ - new webpack.SourceMapDevToolPlugin({ - filename: null, - test: /\.(ts|js)($|\?)/i, - }), - ], - resolve: { - extensions: [".ts", ".js"], - }, -}; - -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("karma-coverage-istanbul-reporter"), - require("@angular-devkit/build-angular/plugins/karma"), - require("webpack"), - ], - 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` - failSpecWithNoExpectations: true, - random: false, - }, - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, - coverageIstanbulReporter: { - fixWebpackSourcePaths: true, - reports: ["html", "text-summary"], - dir: path.join(__dirname, "test-results", "istanbul-coverage"), - }, - reporters: ["progress", "kjhtml", "coverage-istanbul"], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ["Chrome"], - singleRun: false, - restartOnFileChange: true, - webpackConfig: webpackConfig, - }); -}; diff --git a/frontend/package.json b/frontend/package.json index e40f042692..d98b3ca125 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -51,7 +51,6 @@ "@angular/compiler-cli": "~18.2.7", "@compodoc/compodoc": "^1.1.25", "@eslint/js": "^9.12.0", - "@playwright/test": "^1.47.2", "@storybook/addon-docs": "^8.3.5", "@storybook/addon-essentials": "^8.3.5", "@storybook/addon-interactions": "^8.3.5", @@ -62,7 +61,6 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/eslint__js": "^8.42.3", "@types/file-saver": "^2.0.7", - "@types/jasmine": "~5.1.4", "@types/node": "^22.7.5", "@types/semver": "^7.5.8", "@types/uuid": "^10.0.0", @@ -74,13 +72,6 @@ "eslint-plugin-storybook": "0.10.0--canary.156.408aed4.0", "eslint-plugin-tailwindcss": "^3.17.4", "eslint-plugin-unused-imports": "^4.1.4", - "jasmine-core": "~5.3.0", - "karma": "~6.4.4", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.1", - "karma-coverage-istanbul-reporter": "^3.0.3", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "^2.1.0", "npm-check-updates": "^17.1.3", "postcss": "^8.4.47", "prettier": "^3.3.3", diff --git a/frontend/src/app/helpers/skeleton-loaders/mat-checkbox-loader/mat-checkbox-loader.component.spec.ts b/frontend/src/app/helpers/skeleton-loaders/mat-checkbox-loader/mat-checkbox-loader.component.spec.ts deleted file mode 100644 index ec6e456e4c..0000000000 --- a/frontend/src/app/helpers/skeleton-loaders/mat-checkbox-loader/mat-checkbox-loader.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatCheckboxLoaderComponent } from './mat-checkbox-loader.component'; - -describe('MatCheckboxLoaderComponent', () => { - let component: MatCheckboxLoaderComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatCheckboxLoaderComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(MatCheckboxLoaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/projects/create-project/create-project.component.spec.ts b/frontend/src/app/projects/create-project/create-project.component.spec.ts deleted file mode 100644 index 81d871e181..0000000000 --- a/frontend/src/app/projects/create-project/create-project.component.spec.ts +++ /dev/null @@ -1,256 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ -import { HttpClientModule } from '@angular/common/http'; -import { SpyLocation } from '@angular/common/testing'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - AbstractControl, - AsyncValidatorFn, - ReactiveFormsModule, - ValidationErrors, -} from '@angular/forms'; -import { MatCardModule } from '@angular/material/card'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatRadioModule } from '@angular/material/radio'; -import { MatStepperModule } from '@angular/material/stepper'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterTestingModule } from '@angular/router/testing'; -import { BehaviorSubject, map, Observable, of, take } from 'rxjs'; -import slugify from 'slugify'; -import { - click, - findComponent, - findElByTestId, - setFieldValue, -} from 'src/../tests/spec-helper/element.spec-helper'; -import { PatchProject, Project, Visibility } from 'src/app/openapi'; -import { ToastService } from '../../helpers/toast/toast.service'; -import { ProjectUserService } from '../project-detail/project-users/service/project-user.service'; -import { - ProjectWrapperService, - ProjectVisibilityDescriptions, -} from '../service/project.service'; -import { CreateProjectComponent } from './create-project.component'; - -const mockProjects: Project[] = [ - { - name: 'existing-test-project-name', - slug: 'existing-test-project-name', - description: 'existing-test-project-description', - visibility: 'private', - type: 'general', - users: { - leads: 1, - contributors: 0, - subscribers: 0, - }, - is_archived: false, - }, -]; - -const testProjectName = 'test-project-name'; -const testProjectSlug = 'test-project-name'; -const testProjectDescription = 'test-project-description'; - -describe('CreateProjectComponent', () => { - let fixture: ComponentFixture; - let component: CreateProjectComponent; - - const fakeToastService: Pick = { - showSuccess(): void {}, - }; - - const fakeProjectUserService = { - get nonAdminProjectUsers$(): Observable { - return of(undefined); - }, - - resetProjectUserOnProjectReset(): void {}, - resetProjectUsersOnProjectReset(): void {}, - loadProjectUsersOnProjectChange(): void {}, - loadProjectUserOnProjectChange(): void {}, - }; - - const fakeProjectService = { - _project: new BehaviorSubject(undefined), - _projects: new BehaviorSubject(undefined), - - get project$(): Observable { - return this._project.asObservable(); - }, - - get projects$(): Observable { - return this._projects.asObservable(); - }, - - loadProjects() { - this._projects.next(mockProjects); - return of(mockProjects); - }, - createProject(project: PatchProject): Observable { - const projectToCreate: Project = { - name: project.name!, - description: project.description!, - slug: project.name!, - visibility: project.visibility!, - type: project.type!, - users: { leads: 1, contributors: 0, subscribers: 0 }, - is_archived: false, - }; - this._project.next(projectToCreate); - return of(projectToCreate); - }, - clearProject(): void { - this._project.next(undefined); - }, - asyncSlugValidator(): AsyncValidatorFn { - return ( - control: AbstractControl, - ): Observable => { - const projectSlug = slugify(control.value, { lower: true }); - return this.projects$.pipe( - take(1), - map((projects) => { - return projects?.find((project) => project.slug === projectSlug) - ? { uniqueSlug: { value: projectSlug } } - : null; - }), - ); - }; - }, - getProjectVisibilityDescription(visibility: Visibility): string { - return ProjectVisibilityDescriptions[visibility]; - }, - getAvailableVisibilities(): Visibility[] { - return Object.keys(ProjectVisibilityDescriptions) as Visibility[]; - }, - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - providers: [ - { provide: ProjectWrapperService, useValue: fakeProjectService }, - { provide: ToastService, useValue: fakeToastService }, - { provide: ProjectUserService, useValue: fakeProjectUserService }, - { provide: Location, useClass: SpyLocation }, - ], - imports: [ - RouterTestingModule, - MatFormFieldModule, - MatInputModule, - MatStepperModule, - MatCardModule, - MatRadioModule, - ReactiveFormsModule, - BrowserAnimationsModule, - CreateProjectComponent, - HttpClientModule, - ], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - fixture = TestBed.createComponent(CreateProjectComponent); - component = fixture.componentInstance; - - fixture.detectChanges(); - }); - - it('creates', () => { - expect(component).toBeTruthy(); - }); - - it('should not be possible to click on create project when project name already exists', () => { - const existingTestProjectName = mockProjects[0].name; - - setFieldValue(fixture, 'input-name', existingTestProjectName); - fixture.detectChanges(); - - const createButton: HTMLButtonElement = findElByTestId( - fixture, - 'button-create-project', - ).nativeElement; - expect(createButton.disabled).toBeTruthy(); - }); - - it('calls create project with input name and empty input description when clicked on create project button', () => { - spyOn(fakeProjectService, 'createProject').and.callThrough(); - spyOn(fakeToastService, 'showSuccess').and.callThrough(); - - setFieldValue(fixture, 'input-name', testProjectName); - click(fixture, 'button-create-project'); - - fixture.detectChanges(); - - expect(fakeProjectService.createProject).toHaveBeenCalledOnceWith({ - name: testProjectName, - description: '', - visibility: 'private', - }); - expect(fakeToastService.showSuccess).toHaveBeenCalledTimes(1); - }); - - it('calls create project with input name and input description when clicked on create project button', () => { - spyOn(fakeProjectService, 'createProject').and.callThrough(); - spyOn(fakeToastService, 'showSuccess').and.callThrough(); - - setFieldValue(fixture, 'input-name', testProjectName); - setFieldValue(fixture, 'textarea-description', testProjectDescription); - click(fixture, 'button-create-project'); - - fixture.detectChanges(); - - expect(fakeProjectService.createProject).toHaveBeenCalledOnceWith({ - name: testProjectName, - description: testProjectDescription, - visibility: 'private', - }); - expect(fakeToastService.showSuccess).toHaveBeenCalledTimes(1); - }); - - it('loads the app-project-user-settings when clicked on create project button', () => { - setFieldValue(fixture, 'input-name', testProjectName); - click(fixture, 'button-create-project'); - - fixture.detectChanges(); - - const appProjectUserSettingComponent = findComponent( - fixture, - 'app-project-user-settings', - ); - - expect(appProjectUserSettingComponent).toBeTruthy(); - }); - - it('loads the app-create-model when clicked on skip button in add member step', () => { - setFieldValue(fixture, 'input-name', testProjectName); - click(fixture, 'button-create-project'); - - fixture.detectChanges(); - - click(fixture, 'button-skipAddMembers'); - fixture.detectChanges(); - - const appCreateModelComponent = findComponent(fixture, 'app-create-model'); - - expect(appCreateModelComponent).toBeTruthy(); - }); - - it('gets redirected to project/:projectName after clicking on finish', () => { - setFieldValue(fixture, 'input-name', testProjectName); - click(fixture, 'button-create-project'); - fixture.detectChanges(); - - click(fixture, 'button-skipAddMembers'); - fixture.detectChanges(); - - const skipEl: HTMLElement = findElByTestId( - fixture, - 'a-skipModelAndFinishProjectCreation', - ).nativeElement; - - expect(skipEl.getAttribute('href')).toEqual(`/project/${testProjectSlug}`); - }); -}); diff --git a/frontend/src/test.ts b/frontend/src/test.ts deleted file mode 100644 index 3ae6aa455f..0000000000 --- a/frontend/src/test.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting, -} from '@angular/platform-browser-dynamic/testing'; -import 'zone.js/testing'; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting(), -); diff --git a/frontend/tests/config.playwright.ts b/frontend/tests/config.playwright.ts deleted file mode 100644 index 921bca9837..0000000000 --- a/frontend/tests/config.playwright.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const config = { - backend_url: 'http://localhost:8000/api/v1', - api_docs_url: 'http://localhost:8000/api/docs', - frontend_url: 'http://localhost:4200', -}; diff --git a/frontend/tests/project-creation.spec.ts b/frontend/tests/project-creation.spec.ts deleted file mode 100644 index 73326d2f9b..0000000000 --- a/frontend/tests/project-creation.spec.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ -import { test, expect } from '@playwright/test'; -import { config } from 'tests/config.playwright'; - -const nearPixelArea = 50; // Specifies how far away an element can be when using near - -const backendUrl = config.backend_url; -const frontendUrl = config.frontend_url; - -test('test the full project creation workflow', async ({ page }) => { - const testProjectName = `test-project-name-${Math.trunc( - Math.random() * 1000, - )}`; - const testProjectDescription = 'test-project-description'; - - await page.goto(frontendUrl); - - // Check whether you got redirected to the /auth page - await expect(page).toHaveURL(frontendUrl + '/auth'); - - await page.locator('button:text-matches("Login with .*", "g")').click(); - - // Wait for the response from the backend - await page.waitForResponse(backendUrl + '/authentication/'); - - await page - .locator('[placeholder="Enter any user\\/subject"]') - .fill('username'); - await page.locator('input:has-text("Sign-in")').click(); - await expect(page).toHaveURL(frontendUrl); - - await page.locator('a:has-text("Projects")').click(); - await expect(page).toHaveURL(frontendUrl + '/projects'); - - await page.locator('a', { hasText: 'Add new project' }).click(); - await expect(page).toHaveURL(frontendUrl + '/projects/create'); - - const genInfoMatStepHeaderLocator = page.locator('mat-step-header', { - hasText: 'General information', - }); - const addTeamMemMatStepHeaderLocator = page.locator('mat-step-header', { - hasText: 'Add team members', - }); - const addModelsMatStepHeaderLocator = page.locator('mat-step-header', { - hasText: 'Add models', - }); - - await expect(genInfoMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'true', - ); - await expect(addTeamMemMatStepHeaderLocator).toHaveAttribute( - 'aria-disabled', - 'true', - ); - await expect(addModelsMatStepHeaderLocator).toHaveAttribute( - 'aria-disabled', - 'true', - ); - - await page - .locator(`input:near(:text("Name"), ${nearPixelArea})`) - .first() - .fill(testProjectName); - await page - .locator(`textarea:near(:text("Description"), ${nearPixelArea})`) - .first() - .fill(testProjectDescription); - await page.locator('button:has-text("Create Project")').click(); - - await expect(genInfoMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'false', - ); - await expect(addTeamMemMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'true', - ); - await expect(addModelsMatStepHeaderLocator).toHaveAttribute( - 'aria-disabled', - 'true', - ); - - await page.locator('button', { hasText: 'Skip' }).click(); - - await expect(genInfoMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'false', - ); - await expect(addTeamMemMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'false', - ); - await expect(addModelsMatStepHeaderLocator).toHaveAttribute( - 'aria-selected', - 'true', - ); - - await page - .locator('a:has-text("Skip model creation and finish project creation")') - .click(); - await expect(page).toHaveURL(frontendUrl + `/project/${testProjectName}`); - - await page.locator('a:has-text("Projects")').click(); - await expect(page).toHaveURL(frontendUrl + '/projects'); - - await expect( - page.locator(`//a[@href='/project/${testProjectName}']`), - ).toBeVisible(); -}); diff --git a/frontend/tests/spec-helper/element.spec-helper.ts b/frontend/tests/spec-helper/element.spec-helper.ts deleted file mode 100644 index 62835ef774..0000000000 --- a/frontend/tests/spec-helper/element.spec-helper.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors - * SPDX-License-Identifier: Apache-2.0 - */ -import { DebugElement } from '@angular/core'; -import { ComponentFixture } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -export function findElByTestId( - fixture: ComponentFixture, - testId: string, -): DebugElement { - return fixture.debugElement.query(By.css(`[data-testId="${testId}"]`)); -} - -export function findComponent( - fixture: ComponentFixture, - selector: string, -): DebugElement { - return fixture.debugElement.query(By.css(selector)); -} - -export function click(fixture: ComponentFixture, testId: string): void { - const element = findElByTestId(fixture, testId); - const event = makeClickEvent(element.nativeElement); - element.triggerEventHandler('click', event); -} - -export function makeClickEvent(target: EventTarget): Partial { - return { - preventDefault(): void {}, - stopPropagation(): void {}, - stopImmediatePropagation(): void {}, - type: 'click', - target, - currentTarget: target, - bubbles: true, - cancelable: true, - button: 0, - }; -} - -export function expectText( - fixture: ComponentFixture, - testId: string, - expectedText: string, -): void { - const element = findElByTestId(fixture, testId); - const actualText = element.nativeElement.text; - expect(actualText).toBe(expectedText); -} - -export function setFieldValue( - fixture: ComponentFixture, - testId: string, - value: string, -): void { - setElementValue(findElByTestId(fixture, testId).nativeElement, value); -} - -export function setElementValue( - element: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, - value: string, -): void { - element.value = value; - const event = new Event('input', { bubbles: true, cancelable: false }); - element.dispatchEvent(event); -}