AAE-22577 Improve DataTable widget to support single object reference (e.g. only 1st element from array) - Case 3 (#9690)

* AAE-22577 Add single object path reference support

* AAE-22577 Update

* AAE-22577 Fix unit tests
This commit is contained in:
Wiktor Danielewski
2024-05-21 15:25:28 +02:00
committed by GitHub
parent 5218e7e928
commit 07370d963f
6 changed files with 104 additions and 62 deletions

View File

@@ -196,18 +196,6 @@ describe('DataTableWidgetComponent', () => {
assertData(mockCountryColumns, mockEuropeCountriesRows); assertData(mockCountryColumns, mockEuropeCountriesRows);
}); });
it('should NOT display error if form is in preview state', () => {
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
fixture.detectChanges();
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
const previewDataTable = getPreview();
expect(failedErrorMsgElement).toBeNull();
expect(previewDataTable).toBeTruthy();
});
it('should NOT display data table with data source if form is in preview state', () => { it('should NOT display data table with data source if form is in preview state', () => {
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariable); widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariable);
spyOn(formCloudService, 'getPreviewState').and.returnValue(true); spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
@@ -220,53 +208,85 @@ describe('DataTableWidgetComponent', () => {
expect(dataTable).toBeNull(); expect(dataTable).toBeNull();
}); });
it('should display error if data source is not linked to every column', () => { describe('should NOT display error message if', () => {
widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData); it('form is in preview state', () => {
fixture.detectChanges(); widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
spyOn(formCloudService, 'getPreviewState').and.returnValue(true);
fixture.detectChanges();
checkDataTableErrorMessage(); const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
expect(widget.dataSource.getRows()).toEqual([]); const previewDataTable = getPreview();
expect(failedErrorMsgElement).toBeNull();
expect(previewDataTable).toBeTruthy();
});
it('path points to single object with appropriate schema definition', () => {
widget.field = getDataVariable({ ...mockVariableConfig, optionsPath: 'response.single-object' }, mockSchemaDefinition, [], []);
widget.field.value = mockJsonNestedResponseEuropeCountriesData;
fixture.detectChanges();
const failedErrorMsgElement = fixture.debugElement.query(By.css('.adf-data-table-widget-failed-message'));
assertData(mockCountryColumns, [mockEuropeCountriesRows[1]]);
expect(failedErrorMsgElement).toBeNull();
});
}); });
it('should display error if data source has invalid column structure', () => { describe('should display error message if', () => {
widget.field = getDataVariable(mockVariableConfig, mockInvalidSchemaDefinition, [], mockJsonFormVariableWithIncorrectData); it('data source is NOT linked to every column', () => {
fixture.detectChanges(); widget.field = getDataVariable(mockVariableConfig, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
fixture.detectChanges();
checkDataTableErrorMessage(); checkDataTableErrorMessage();
expect(widget.dataSource.getRows()).toEqual([]); expect(widget.dataSource.getRows()).toEqual([]);
}); });
it('should display error if data source is not found', () => { it('data source has invalid column structure', () => {
widget.field = getDataVariable({ variableName: 'not-found-data-source' }, mockSchemaDefinition, [], mockJsonFormVariableWithIncorrectData); widget.field = getDataVariable(mockVariableConfig, mockInvalidSchemaDefinition, [], mockJsonFormVariableWithIncorrectData);
fixture.detectChanges(); fixture.detectChanges();
checkDataTableErrorMessage(); checkDataTableErrorMessage();
expect(widget.dataSource).toBeUndefined(); expect(widget.dataSource.getRows()).toEqual([]);
}); });
it('should display error if path is incorrect', () => { it('data source is NOT found', () => {
widget.field = getDataVariable( widget.field = getDataVariable(
{ ...mockVariableConfig, optionsPath: 'wrong.path' }, { variableName: 'not-found-data-source' },
mockSchemaDefinition, mockSchemaDefinition,
mockJsonNestedResponseFormVariable, [],
[] mockJsonFormVariableWithIncorrectData
); );
fixture.detectChanges(); fixture.detectChanges();
checkDataTableErrorMessage(); checkDataTableErrorMessage();
expect(widget.dataSource).toBeUndefined(); expect(widget.dataSource).toBeUndefined();
}); });
it('should display error if provided data by path is not an array', () => { it('path is incorrect', () => {
widget.field = getDataVariable( widget.field = getDataVariable(
{ ...mockVariableConfig, optionsPath: 'response.no-array' }, { ...mockVariableConfig, optionsPath: 'wrong.path' },
mockSchemaDefinition, mockSchemaDefinition,
mockJsonNestedResponseFormVariable, mockJsonNestedResponseFormVariable,
[] []
); );
fixture.detectChanges(); fixture.detectChanges();
checkDataTableErrorMessage(); checkDataTableErrorMessage();
expect(widget.dataSource).toBeUndefined(); expect(widget.dataSource).toBeUndefined();
});
it('provided data by path is NOT an array or object', () => {
widget.field = getDataVariable(
{ ...mockVariableConfig, optionsPath: 'response.no-array-or-object' },
mockSchemaDefinition,
mockJsonNestedResponseFormVariable,
[]
);
fixture.detectChanges();
checkDataTableErrorMessage();
expect(widget.dataSource).toBeUndefined();
});
}); });
}); });

View File

@@ -83,7 +83,7 @@ export class DataTableWidgetComponent extends WidgetComponent implements OnInit
this.handleError('Data source has corrupted model or structure'); this.handleError('Data source has corrupted model or structure');
} }
} else { } else {
this.handleError('Data source not found or it is not an array'); this.handleError('Data source not found or it is not an array/object');
} }
} }

View File

@@ -16,7 +16,7 @@
*/ */
import { DataTablePathParserHelper } from './data-table-path-parser.helper'; import { DataTablePathParserHelper } from './data-table-path-parser.helper';
import { mockResponseResultData, mockResponseResultDataWithNestedArray, mockResultData } from '../mocks/data-table-path-parser.helper.mock'; import { mockResponseResultData, mockResponseResultDataWithArrayInsideArray, mockResultData } from '../mocks/data-table-path-parser.helper.mock';
interface DataTablePathParserTestCase { interface DataTablePathParserTestCase {
description: string; description: string;
@@ -132,20 +132,32 @@ describe('DataTablePathParserHelper', () => {
description: 'with property followed by single index reference', description: 'with property followed by single index reference',
propertyName: 'users', propertyName: 'users',
path: 'response.users[0].data', path: 'response.users[0].data',
data: mockResponseResultDataWithNestedArray('users') data: mockResponseResultDataWithArrayInsideArray('users')
}, },
{ {
description: 'with property followed by multiple index references', description: 'with property followed by multiple index references',
propertyName: 'users:Array', propertyName: 'users:Array',
path: 'response.[users:Array][0][1][12].data', path: 'response.[users:Array][0][1][12].data',
data: mockResponseResultDataWithNestedArray('users:Array'), data: mockResponseResultDataWithArrayInsideArray('users:Array'),
expected: [] expected: []
}, },
{ {
description: 'when path does NOT point to array', description: 'when path points to array in the middle (incorrect path)',
propertyName: 'users', propertyName: 'users',
path: 'response.users[0]', path: 'response.users.incorrectPath',
data: mockResponseResultDataWithNestedArray('users'), data: mockResponseResultDataWithArrayInsideArray('users'),
expected: []
},
{
description: 'when path points to the particular element of the array',
propertyName: 'users',
path: 'response.users[1]',
expected: [mockResultData[1]]
},
{
description: 'when path points to the particular element of the array which does NOT exist',
propertyName: 'users',
path: 'response.users[100]',
expected: [] expected: []
} }
]; ];

View File

@@ -37,8 +37,10 @@ export class DataTablePathParserHelper {
const isPropertyWithSingleIndexReference = propertyIndexReferences.length === 1; const isPropertyWithSingleIndexReference = propertyIndexReferences.length === 1;
const nestedData = isPropertyWithSingleIndexReference ? data[purePropertyName]?.[propertyIndexReferences[0]] : data[purePropertyName]; const nestedData = isPropertyWithSingleIndexReference ? data[purePropertyName]?.[propertyIndexReferences[0]] : data[purePropertyName];
if (Array.isArray(nestedData)) { if (nestedData && properties.length === 0) {
return nestedData; if (this.isDataArrayOrObject(nestedData)) {
return Array.isArray(nestedData) ? nestedData : [nestedData];
}
} }
return this.retrieveDataFromPath(nestedData, properties.join('.')); return this.retrieveDataFromPath(nestedData, properties.join('.'));
@@ -127,4 +129,11 @@ export class DataTablePathParserHelper {
private isPropertyExistsInData(data: any, property: string): boolean { private isPropertyExistsInData(data: any, property: string): boolean {
return Object.prototype.hasOwnProperty.call(data, property); return Object.prototype.hasOwnProperty.call(data, property);
} }
private isDataArrayOrObject(data: any): boolean {
if (data == null) {
return false;
}
return Array.isArray(data) || typeof data === 'object';
}
} }

View File

@@ -44,7 +44,7 @@ export const mockResponseResultData = (propertyName?: string) => ({
} }
}); });
export const mockResponseResultDataWithNestedArray = (propertyName?: string) => ({ export const mockResponseResultDataWithArrayInsideArray = (propertyName?: string) => ({
response: { response: {
[propertyName]: [ [propertyName]: [
{ {

View File

@@ -114,13 +114,14 @@ export const mockJsonNestedResponseEuropeCountriesData = {
response: { response: {
empty: [], empty: [],
'my-data': mockEuropeCountriesData, 'my-data': mockEuropeCountriesData,
'single-object': mockEuropeCountriesData[0],
'no-array-or-object': 'string-value',
data: [ data: [
{ {
id: 'HR', id: 'HR',
name: 'Croatia' name: 'Croatia'
} }
], ]
'no-array': {}
} }
}; };