Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-133118 / 25.04 / Addes tests for glossary and form-section components, form-service #11352

Merged
merged 9 commits into from
Jan 21, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[formControl]="searchControl"
[placeholder]="'Search Input Fields' | translate"
[autocompleteOptions]="searchOptions()"
[label]="'Search' | translate"
></ix-input>

@for (section of sections(); track section) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { fakeAsync, tick } from '@angular/core/testing';
import {
FormControl, FormGroup, NgControl, ReactiveFormsModule,
} from '@angular/forms';
import { MatAutocomplete } from '@angular/material/autocomplete';
import { createHostFactory, mockProvider, SpectatorHost } from '@ngneat/spectator/jest';
import { of, Subject } from 'rxjs';
import { NavigateAndHighlightService } from 'app/directives/navigate-and-interact/navigate-and-highlight.service';
import { IxFormGlossaryComponent } from 'app/modules/forms/ix-forms/components/ix-form-glossary/ix-form-glossary.component';
import { IxFormSectionComponent } from 'app/modules/forms/ix-forms/components/ix-form-section/ix-form-section.component';
import { IxInputComponent } from 'app/modules/forms/ix-forms/components/ix-input/ix-input.component';
import { IxInputHarness } from 'app/modules/forms/ix-forms/components/ix-input/ix-input.harness';
import { IxFormService } from 'app/modules/forms/ix-forms/services/ix-form.service';
import { IxIconComponent } from 'app/modules/ix-icon/ix-icon.component';

describe('IxFormGlossaryComponent', () => {
let spectator: SpectatorHost<IxFormGlossaryComponent>;
let harnessLoader: HarnessLoader;
const statusChanges$ = new Subject<void>();
const element = document.createElement('div');

const createHost = createHostFactory({
component: IxFormGlossaryComponent,
imports: [
IxInputComponent,
ReactiveFormsModule,
IxFormSectionComponent,
IxIconComponent,
MatAutocomplete,
],
providers: [
mockProvider(IxFormService, {
controlSections$: of([
{
section: { label: () => 'Section' } as IxFormSectionComponent,
controls: [
{ valid: true, statusChanges: statusChanges$ } as unknown as NgControl,
{ valid: false, statusChanges: statusChanges$ } as unknown as NgControl,
],
},
]),
controlNamesWithLabels$: of([
{
label: 'Control1',
name: 'control1',
},
{
label: 'Control2',
name: 'control2',
},
]),
getElementByControlName: jest.fn(() => element),
}),
mockProvider(NavigateAndHighlightService),
],
});

beforeEach(() => {
spectator = createHost(`
<form [formGroup]="fg"><ix-form-section [label]="'Section'"><ix-input [formControlName]="'control1'" [label]="'Control1'"></ix-input> <ix-input [formControlName]="'control2'" [label]="'Control2'"></ix-input></ix-form-section></form> <ix-form-glossary></ix-form-glossary>
`, {
hostProps: {
fg: new FormGroup({
control1: new FormControl(),
control2: new FormControl(),
}),
},
});

harnessLoader = TestbedHarnessEnvironment.loader(spectator.fixture);
});

it('loads input options from form glossary', async () => {
expect(spectator.component).toBeTruthy();
const input = await harnessLoader.getHarness(IxInputHarness.with({ label: 'Search' }));
await input.setValue('Control2');
const matAutocomplete = await input.getMatAutoCompleteHarness();
const options = await matAutocomplete.getOptions();
const optionsText: string[] = [];
for (const option of options) {
optionsText.push(await option.getText());
}
expect(optionsText).toEqual(['Control2']);
expect(spectator.inject(NavigateAndHighlightService).scrollIntoView).toHaveBeenCalledWith(element);
});

it('shows sections as options', fakeAsync(() => {
spectator.detectChanges();
tick(100);
const sections = spectator.queryAll('.section');
expect(sections.map((section) => section.textContent)).toEqual([' Section ']);
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ export class IxFormGlossaryComponent implements OnInit {

private handleSectionUpdates(): void {
this.formService.controlSections$.pipe(
delay(0),
untilDestroyed(this),
).subscribe({
next: (sectionsWithControls) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { mockProvider, createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { IxFormSectionComponent } from 'app/modules/forms/ix-forms/components/ix-form-section/ix-form-section.component';
import { IxFormService } from 'app/modules/forms/ix-forms/services/ix-form.service';

describe('IxFormSectionComponent', () => {
let spectator: Spectator<IxFormSectionComponent>;
const createComponent = createComponentFactory({
component: IxFormSectionComponent,
providers: [
mockProvider(IxFormService),
],
});

beforeEach(() => {
spectator = createComponent({
props: {
label: 'Test Section',
help: 'Test Help',
},
});
});

it('calls registerSectionControl when created', () => {
expect(spectator.inject(IxFormService).registerSectionControl).toHaveBeenCalledWith(null, spectator.component);
});

it('calls unregisterSectionControl when destroyed', () => {
spectator.component.ngOnDestroy();
expect(spectator.inject(IxFormService).unregisterSectionControl).toHaveBeenCalledWith(spectator.component, null);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing';
import { MatInputHarness } from '@angular/material/input/testing';
import { IxLabelHarness } from 'app/modules/forms/ix-forms/components/ix-label/ix-label.harness';
import { IxFormControlHarness } from 'app/modules/forms/ix-forms/interfaces/ix-form-control-harness.interface';
Expand All @@ -17,6 +18,8 @@ export class IxInputHarness extends ComponentHarness implements IxFormControlHar
}

getMatInputHarness = this.locatorFor(MatInputHarness);
getMatAutoCompleteHarness = this.locatorFor(MatAutocompleteHarness);

getErrorText = getErrorText;

async getLabelText(): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,92 @@
import { ElementRef } from '@angular/core';
import { NgControl } from '@angular/forms';
import { createDirectiveFactory, mockProvider, SpectatorDirective } from '@ngneat/spectator/jest';
import { RegisteredControlDirective } from 'app/modules/forms/ix-forms/directives/registered-control.directive';
import {
ReactiveFormsModule, FormGroup, FormControl, NgControl,
} from '@angular/forms';
import { createDirectiveFactory, mockProvider } from '@ngneat/spectator/jest';
import { MockComponent } from 'ng-mocks';
import { IxFormSectionComponent } from 'app/modules/forms/ix-forms/components/ix-form-section/ix-form-section.component';
import { IxFormService } from 'app/modules/forms/ix-forms/services/ix-form.service';
import { RegisteredControlDirective } from './registered-control.directive';

// TODO: https://ixsystems.atlassian.net/browse/NAS-133118
describe.skip('RegisteredControlDirective', () => {
let spectator: SpectatorDirective<RegisteredControlDirective>;

describe('RegisteredControlDirective', () => {
function getGroupDiv(): HTMLDivElement {
const divElement = document.createElement('div');
divElement.setAttribute('ixRegisteredControl', '');
divElement.setAttribute('ix-label', 'Test Group');
divElement.setAttribute('ng-reflect-form-group-name', 'testGroup');
divElement.setAttribute('ng-reflect-label', 'Test Group');
divElement.setAttribute('ng-reflect-label', 'Test Group');
divElement.setAttribute('ng-reflect-name', 'testGroup');
divElement.classList.add('ng-untouched');
divElement.classList.add('ng-pristine');
divElement.classList.add('ng-valid');
const inputElement = document.createElement('input');
inputElement.classList.add('ng-untouched');
inputElement.setAttribute('ng-reflect-name', 'testControl');
inputElement.classList.add('ng-pristine');
inputElement.classList.add('ng-valid');
inputElement.setAttribute('formControlName', 'testControl');
divElement.appendChild(inputElement);
return divElement;
}
const testGroup = new FormGroup({
testControl: new FormControl(''),
});
const createDirective = createDirectiveFactory({
directive: RegisteredControlDirective,
imports: [ReactiveFormsModule, MockComponent(IxFormSectionComponent)],
providers: [
mockProvider(NgControl, {
name: 'testGroup',
control: testGroup,
}),
mockProvider(IxFormService),
mockProvider(NgControl, {}),
],
});

beforeEach(() => {
spectator = createDirective('<div ixRegisteredControl [label]="\'Test\'" [formGroupName]=\'test\'></div>');
it('registers control when control name is available', () => {
const spectator = createDirective(`
<div [formGroup]="fg"><div ixRegisteredControl [label]="'Test Group'" [formGroupName]="'testGroup'"><input formControlName="testControl"></div></div>
`, {
hostProps: {
fg: new FormGroup({
testGroup,
}),
},
});

expect(spectator.inject(IxFormService).registerControl).toHaveBeenCalled();
});

it('registers control and element ref of the element with form service', () => {
expect(spectator.inject(IxFormService).registerControl).toHaveBeenCalledWith(
spectator.inject(NgControl),
expect.any(ElementRef),
it('registers control and form section available', () => {
const spectator = createDirective(`
<div [formGroup]="fg"><ix-form-section [label]="'Test Section'"><div ixRegisteredControl [label]="'Test Group'" [formGroupName]="'testGroup'"><input formControlName="testControl"></div></ix-form-section></div>
`, {
hostProps: {
fg: new FormGroup({
testGroup,
}),
},
});
const formService = spectator.inject(IxFormService);
expect(
formService.registerControl,
).toHaveBeenCalledWith('testGroup', new ElementRef(getGroupDiv()));
const ixFormSection = document.createElement('ix-form-section');
ixFormSection.setAttribute('id', 'Test Section');
expect(formService.registerSectionControl).toHaveBeenCalledWith(
expect.objectContaining({ name: 'testGroup', control: testGroup }),
expect.objectContaining({
label: 'Test Section',
}),
);
spectator.directive.ngOnDestroy();
expect(formService.unregisterControl).toHaveBeenCalledWith('testGroup');
expect(formService.unregisterSectionControl).toHaveBeenCalledWith(
expect.objectContaining({
label: 'Test Section',
}),
expect.objectContaining({ name: 'testGroup', control: testGroup }),
);
});
});
7 changes: 1 addition & 6 deletions src/setup-jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
MissingTranslationHandler, TranslateCompiler, TranslateLoader, TranslateModule, TranslateFakeLoader,
} from '@ngx-translate/core';
import failOnConsole from 'jest-fail-on-console';
import { MockDirective, MockProvider } from 'ng-mocks';
import { MockProvider } from 'ng-mocks';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import {
Observable,
Expand Down Expand Up @@ -68,7 +68,6 @@ import {
} from 'app/modules/forms/ix-forms/components/ix-slide-toggle/ix-slide-toggle.component';
import { IxTextareaComponent } from 'app/modules/forms/ix-forms/components/ix-textarea/ix-textarea.component';
import { WarningComponent } from 'app/modules/forms/ix-forms/components/warning/warning.component';
import { RegisteredControlDirective } from 'app/modules/forms/ix-forms/directives/registered-control.directive';
import { IxIconRegistry } from 'app/modules/ix-icon/ix-icon-registry.service';
import { IxIconComponent } from 'app/modules/ix-icon/ix-icon.component';
import { IxTableComponent } from 'app/modules/ix-table/components/ix-table/ix-table.component';
Expand Down Expand Up @@ -99,9 +98,6 @@ failOnConsole({ silenceMessage: silenceJsDomCssParseError });
jest.setTimeout(30 * 1000);

defineGlobalsInjections({
declarations: [
MockDirective(RegisteredControlDirective),
],
imports: [
HttpClientModule,
MatCheckboxModule,
Expand Down Expand Up @@ -129,7 +125,6 @@ defineGlobalsInjections({
IxFieldsetComponent,
ModalHeaderComponent,
IxFormSectionComponent,
RegisteredControlDirective,
IxButtonGroupComponent,
IxExplorerComponent,
IxFileInputComponent,
Expand Down
Loading