AAE-35668 Sending empty string instead of null after clearing value from numeric field (#10925)

* Handles null values in number widget

Ensures the number widget correctly handles null, undefined, and empty string values, setting the field value to null in these cases.

This change prevents unexpected behavior when the user clears the input field, ensuring data consistency.

* Adds test for readonly number widget

Adds a test case to verify the behavior of the number widget when it's in readonly mode.

The test checks if the displayValue is correctly set using the decimalNumberPipe when the readOnly property is true.

* Refactors number widget tests

Updates number widget tests to use `overrideComponent` for providing mocked dependencies. This approach ensures proper isolation and avoids potential issues with shared state between tests.
Additionally, it adds a test case to verify the `displayValue` is correctly set using the mocked `DecimalNumberPipe`.

---------

Co-authored-by: Eugenio Romano <eromano@users.noreply.github.com>
This commit is contained in:
Michaela 2025-06-11 11:53:56 +02:00 committed by GitHub
parent 5d9acaec0d
commit e2693f9304
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 89 additions and 4 deletions

View File

@ -21,7 +21,7 @@
[required]="isRequired()"
[value]="displayValue"
[(ngModel)]="field.value"
(ngModelChange)="onFieldChanged(field)"
(ngModelChange)="onNumberChange($event)"
[disabled]="field.readOnly"
[placeholder]="field.placeholder"
[title]="field.tooltip"

View File

@ -23,23 +23,100 @@ import { MatInputModule } from '@angular/material/input';
import { CoreTestingModule, UnitTestingUtils } from '../../../../testing';
import { FormFieldModel, FormFieldTypes, FormModel } from '../core';
import { NumberWidgetComponent } from './number.widget';
import { DecimalNumberPipe } from '../../../../pipes';
describe('NumberWidgetComponent', () => {
let loader: HarnessLoader;
let widget: NumberWidgetComponent;
let fixture: ComponentFixture<NumberWidgetComponent>;
let testingUtils: UnitTestingUtils;
let mockDecimalNumberPipe: jasmine.SpyObj<DecimalNumberPipe>;
beforeEach(() => {
TestBed.configureTestingModule({
beforeEach(async () => {
mockDecimalNumberPipe = jasmine.createSpyObj('DecimalNumberPipe', ['transform']);
await TestBed.configureTestingModule({
imports: [CoreTestingModule, MatInputModule, MatIconModule]
});
})
.overrideComponent(NumberWidgetComponent, {
set: {
providers: [{ provide: DecimalNumberPipe, useValue: mockDecimalNumberPipe }]
}
})
.compileComponents();
fixture = TestBed.createComponent(NumberWidgetComponent);
widget = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture);
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
});
it('should create', () => {
expect(widget).toBeTruthy();
});
describe('with readonly true', () => {
beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.NUMBER,
value: 123.45,
id: 'number-id',
readOnly: true
});
});
it('should set displayValue using decimalNumberPipe', () => {
const expectedValue = '2000';
mockDecimalNumberPipe.transform.and.returnValue(expectedValue);
fixture.detectChanges();
expect(mockDecimalNumberPipe.transform).toHaveBeenCalled();
expect(widget.displayValue).toBe(expectedValue);
});
});
describe('with default value', () => {
beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
type: FormFieldTypes.NUMBER,
value: 123,
id: 'number-id',
readOnly: false
});
fixture.detectChanges();
});
it('should display the value', async () => {
const input = await testingUtils.getMatInput();
expect(widget.displayValue).toBe(123);
expect(await input.getValue()).toBe('123');
expect(widget.field.value).toBe(123);
});
it('should have value null when field is cleared', async () => {
const input = await testingUtils.getMatInput();
await input.setValue('');
expect(widget.field.value).toBeNull();
});
it('should have value null when value is undefined', async () => {
const input = await testingUtils.getMatInput();
await input.setValue(undefined);
expect(widget.field.value).toBeNull();
});
it('should have value null when value is null', async () => {
const input = await testingUtils.getMatInput();
await input.setValue(null);
expect(widget.field.value).toBeNull();
});
});
describe('when tooltip is set', () => {
beforeEach(() => {
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {

View File

@ -62,4 +62,12 @@ export class NumberWidgetComponent extends WidgetComponent implements OnInit {
this.displayValue = this.field.value;
}
}
protected onNumberChange(value: string) {
if (value === null || value === undefined || value === '') {
this.field.value = null;
}
this.onFieldChanged(this.field);
}
}