- ``npm run lint``, will check frontend files against all linters
- ``npm run fix``, will try to fix all the detected linting errors
+Writing Unit Tests
+~~~~~~~~~~~~~~~~~~
+
+To write unit tests most efficient we have a small collection of tools,
+we use within test suites.
+
+Those tools can be found under
+``src/pybind/mgr/dashboard/frontend/src/testing/``, especially take
+a look at ``unit-test-helper.ts``.
+
+There you will be able to find:
+
+``configureTestBed`` that replaces the initial ``TestBed``
+methods. It takes the same arguments as ``TestBed.configureTestingModule``.
+Using it will run your tests a lot faster in development, as it doesn't
+recreate everything from scratch on every test. To use the default behaviour
+pass ``true`` as the second argument.
+
+``PermissionHelper`` to help determine if
+the correct actions are shown based on the current permissions and selection
+in a list.
+
+``FormHelper`` which makes testing a form a lot easier
+with a few simple methods. It allows you to set a control or multiple
+controls, expect if a control is valid or has an error or just do both with
+one method. Additional you can expect a template element or multiple elements
+to be visible in the rendered template.
+
Running Unit Tests
~~~~~~~~~~~~~~~~~~
-import { async, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { AbstractControl } from '@angular/forms';
+import { By } from '@angular/platform-browser';
import * as _ from 'lodash';
import { TableActionsComponent } from '../app/shared/datatable/table-actions/table-actions.component';
+import { CdFormGroup } from '../app/shared/forms/cd-form-group';
import { Permission } from '../app/shared/models/permissions';
import { _DEV_ } from '../unit-test-configuration';
this.tableActions.selection.update();
}
}
+
+export class FormHelper {
+ form: CdFormGroup;
+
+ constructor(form: CdFormGroup) {
+ this.form = form;
+ }
+
+ /**
+ * Changes multiple values in multiple controls
+ */
+ setMultipleValues(values: { [controlName: string]: any }, markAsDirty?: boolean) {
+ Object.keys(values).forEach((key) => {
+ this.setValue(key, values[key], markAsDirty);
+ });
+ }
+
+ /**
+ * Changes the value of a control
+ */
+ setValue(control: AbstractControl | string, value: any, markAsDirty?: boolean): AbstractControl {
+ control = this.getControl(control);
+ if (markAsDirty) {
+ control.markAsDirty();
+ }
+ control.setValue(value);
+ return control;
+ }
+
+ private getControl(control: AbstractControl | string): AbstractControl {
+ if (typeof control === 'string') {
+ return this.form.get(control);
+ }
+ return control;
+ }
+
+ /**
+ * Change the value of the control and expect the control to be valid afterwards.
+ */
+ expectValidChange(control: AbstractControl | string, value: any, markAsDirty?: boolean) {
+ this.expectValid(this.setValue(control, value, markAsDirty));
+ }
+
+ /**
+ * Expect that the given control is valid.
+ */
+ expectValid(control: AbstractControl | string) {
+ // 'isValid' would be false for disabled controls
+ expect(this.getControl(control).errors).toBe(null);
+ }
+
+ /**
+ * Change the value of the control and expect a specific error.
+ */
+ expectErrorChange(
+ control: AbstractControl | string,
+ value: any,
+ error: string,
+ markAsDirty?: boolean
+ ) {
+ this.expectError(this.setValue(control, value, markAsDirty), error);
+ }
+
+ /**
+ * Expect a specific error for the given control.
+ */
+ expectError(control: AbstractControl | string, error: string) {
+ expect(this.getControl(control).hasError(error)).toBeTruthy();
+ }
+
+ /**
+ * Expect a list of id elements to be visible or not.
+ */
+ expectIdElementsVisible(fixture: ComponentFixture<any>, ids: string[], visibility: boolean) {
+ fixture.detectChanges();
+ ids.forEach((css) => {
+ this.expectElementVisible(fixture, `#${css}`, visibility);
+ });
+ }
+
+ /**
+ * Expect a specific element in fixture to be visible or not.
+ */
+ expectElementVisible(fixture: ComponentFixture<any>, css: string, visibility: boolean) {
+ expect(Boolean(fixture.debugElement.query(By.css(css)))).toBe(visibility);
+ }
+}