Skip to content

Commit

Permalink
fix: Added support for dataset CUD operations
Browse files Browse the repository at this point in the history
  • Loading branch information
BetimBeja committed Nov 27, 2023
1 parent 5e2439d commit 80cdb09
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 29 deletions.
5 changes: 5 additions & 0 deletions __tests__/DataSetMock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ describe('DataSetMock', () => {
dataset.clearSelectedRecordIds();
expect(dataset.getSelectedRecordIds()).toEqual([]);
});

it('new record should work', () => {
var newRecord = dataset.newRecord();
expect(newRecord.getRecordId()).toEqual('Guid.NewGuid?');
});
});

describe('without id', () => {
Expand Down
12 changes: 10 additions & 2 deletions __tests__/EntityRecordMock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
import type { ShkoOnline } from '../src/ShkoOnline';
import { it, expect, describe, beforeEach } from '@jest/globals';
import { EntityRecordMock, MetadataDB } from '../src';
import { SinonStub, stub } from 'sinon';

describe('EntityRecordMock', () => {
let db: MetadataDB;
let entityRecord: EntityRecordMock;
let LogicalName: string;
let boundRow: string;
let updateView: SinonStub<[],void>;

beforeEach(() => {

db = new MetadataDB();
LogicalName = '!!test';
boundRow = 'TheRowId';

updateView = stub();
db.initMetadata([
{
LogicalName,
Expand Down Expand Up @@ -46,7 +49,7 @@ describe('EntityRecordMock', () => {
value: [{ id: boundRow, name: 'Betim Beja' }],
});

entityRecord = new EntityRecordMock(db, LogicalName, boundRow);
entityRecord = new EntityRecordMock(db, LogicalName, boundRow, updateView);
});

it('getNamedReference should return an entity reference', () => {
Expand All @@ -72,4 +75,9 @@ describe('EntityRecordMock', () => {
it('getRecordId should return the bound row id', () => {
expect(entityRecord.getRecordId()).toEqual(boundRow);
});

it('setValue should call updateView', async () => {
await entityRecord.setValue('name', 'Asllan Makaj');
expect(updateView.calledOnce).toEqual(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export class ComponentFrameworkMockGeneratorReact<
mockSetControlState(this);
}


ExecuteInit() {
this.RefreshParameters();
const state = this.state === undefined ? this.state : { ...this.state };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { mockSetControlState } from './mockSetControlState';
import { mockSetControlResource } from './mockSetControlResource';
import { mockRefreshParameters } from './mockRefreshParameters';
import { mockNotifyOutputChanged } from './mockNotifyOutputChanged';
import { ContextMock } from '../ComponentFramework-Mock';
import { ContextMock, DataSetMock } from '../ComponentFramework-Mock';
import { showBanner } from '../utils';
import { MockGenerator } from './MockGenerator';
import { mockRefreshDatasets } from './mockRefreshDatasets';
Expand Down Expand Up @@ -59,6 +59,13 @@ export class ComponentFrameworkMockGenerator<
else this.resizeObserver.unobserve(this.container);
});

Object.getOwnPropertyNames(this.context._parameters).forEach((p) => {
var parameter = this.context._parameters[p];
if (parameter instanceof DataSetMock) {
parameter._updateView = this.ExecuteUpdateView.bind(this);
}
});

mockGetEntityMetadata(this);
this.notifyOutputChanged = stub();
mockNotifyOutputChanged(this, this.control.getOutputs?.bind(this.control), this.ExecuteUpdateView.bind(this));
Expand Down
43 changes: 21 additions & 22 deletions src/ComponentFramework-Mock-Generator/ReactResizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import type { JSXElementConstructor, ReactElement } from 'react';
import type { ShkoOnline } from '../ShkoOnline';

import { createElement, Fragment, useEffect, useRef, useState } from 'react';
import { createElement, Fragment, useCallback, useEffect, useRef, useState } from 'react';
import { ComponentFrameworkMockGeneratorReact } from './ComponentFramework-Mock-Generator-React';
import { mockNotifyOutputChanged } from './mockNotifyOutputChanged';
import { mockRefreshDatasets } from './mockRefreshDatasets';
import { DataSetMock } from '../ComponentFramework-Mock/PropertyTypes';

export interface ReactResizeObserverProps<
TInputs extends ShkoOnline.PropertyTypes<TInputs>,
Expand All @@ -30,18 +31,26 @@ export const ReactResizeObserver = <
const [Component, setComponent] = useState<ReactElement<any, string | JSXElementConstructor<any>>>(
createElement(Fragment),
);
const updateView = useCallback(() => {
setComponent(
componentFrameworkMockGeneratorReact.control.updateView(componentFrameworkMockGeneratorReact.context),
);
}, [setComponent, componentFrameworkMockGeneratorReact]);
useEffect(() => {
Object.getOwnPropertyNames(componentFrameworkMockGeneratorReact.context._parameters).forEach((p) => {
var parameter = componentFrameworkMockGeneratorReact.context._parameters[p];
if (parameter instanceof DataSetMock) {
parameter._updateView = updateView;
}
});

mockNotifyOutputChanged(
componentFrameworkMockGeneratorReact,
componentFrameworkMockGeneratorReact.control.getOutputs?.bind(componentFrameworkMockGeneratorReact.control),
() => {
componentFrameworkMockGeneratorReact.RefreshParameters();
setComponent(
componentFrameworkMockGeneratorReact.control.updateView(
componentFrameworkMockGeneratorReact.context,
),
);
componentFrameworkMockGeneratorReact.RefreshDatasets();
updateView();
componentFrameworkMockGeneratorReact.RefreshDatasets();
},
);

Expand All @@ -50,39 +59,29 @@ export const ReactResizeObserver = <
componentFrameworkMockGeneratorReact.context.mode.allocatedHeight = size.contentRect.height;
componentFrameworkMockGeneratorReact.context.mode.allocatedWidth = size.contentRect.width;
componentFrameworkMockGeneratorReact.RefreshParameters();
setComponent(
componentFrameworkMockGeneratorReact.control.updateView(
componentFrameworkMockGeneratorReact.context,
),
);
updateView();
});

mockRefreshDatasets(componentFrameworkMockGeneratorReact, () => {
setComponent(
componentFrameworkMockGeneratorReact.control.updateView(componentFrameworkMockGeneratorReact.context),
);
});
mockRefreshDatasets(componentFrameworkMockGeneratorReact, updateView);

componentFrameworkMockGeneratorReact.context.mode.trackContainerResize.callsFake((value) => {
if (!containerRef.current) {
console.error('Container Ref is null');
return;
}

if (value) componentFrameworkMockGeneratorReact.resizeObserver.observe(containerRef.current);
else componentFrameworkMockGeneratorReact.resizeObserver.unobserve(containerRef.current);
});

if(componentFrameworkMockGeneratorReact.context.mode._TrackingContainerResize && containerRef.current){
if (componentFrameworkMockGeneratorReact.context.mode._TrackingContainerResize && containerRef.current) {
componentFrameworkMockGeneratorReact.resizeObserver.observe(containerRef.current);
}
}, []);

useEffect(() => {
componentFrameworkMockGeneratorReact.RefreshParameters();
setComponent(
componentFrameworkMockGeneratorReact.control.updateView(componentFrameworkMockGeneratorReact.context),
);
updateView();
componentFrameworkMockGeneratorReact.RefreshDatasets();
}, [circuitBreaker]);

Expand Down
2 changes: 1 addition & 1 deletion src/ComponentFramework-Mock/Context.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { SinonStub } from 'sinon';
import type { ShkoOnline } from '../ShkoOnline';
import type { MockToRaw, PropertyMap, PropertyToMock } from './PropertyTypes';

import Sinon, { stub } from 'sinon';
import { stub } from 'sinon';
import { ClientMock } from './Client.mock';
import { DeviceMock } from './Device.mock';
import { FactoryMock } from './Factory.mocks';
Expand Down
33 changes: 32 additions & 1 deletion src/ComponentFramework-Mock/PropertyTypes/DataSet.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
_boundColumn: string;
_boundTable: string;
_boundRow?: string;
_dataSetCapabilities: ComponentFramework.PropertyTypes.DataProviderCapabilities;
_db: MetadataDB;
_Bind: SinonStub<[boundTable: string, boundColumn: string, boundRow?: string], void>;
_Refresh: SinonStub<[], void>;
Expand All @@ -29,8 +30,10 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
_onLoaded: SinonStub<[], void>;
_delay: number;
_SelectedRecordIds: string[];
_updateView?: () => void;
addColumn?: SinonStub<[name: string, entityAlias?: string], void>;
columns: Column[];
delete: SinonStub<[ids: string[]], Promise<void>>;
error: boolean;
errorMessage: string;
filtering: FilteringMock;
Expand All @@ -43,19 +46,30 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
sortedRecordIds: string[];
sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[];
clearSelectedRecordIds: SinonStub<[], void>;
getDataSetCapabilities: SinonStub<[], ComponentFramework.PropertyTypes.DataProviderCapabilities>;
getSelectedRecordIds: SinonStub<[], string[]>;
getTargetEntityType: SinonStub<[], string>;
getTitle: SinonStub<[], string>;
getViewId: SinonStub<[], string>;
newRecord: SinonStub<[], ComponentFramework.PropertyHelper.DataSetApi.EntityRecord>;
openDatasetItem: SinonStub<[entityReference: ComponentFramework.EntityReference], void>;
refresh: SinonStub<[], void>;
setSelectedRecordIds: SinonStub<[ids: string[]], void>;
constructor(propertyName: string, db: MetadataDB) {
this._boundTable = `!!${propertyName}`;
this._boundColumn = propertyName;
this._dataSetCapabilities = {
canCreateNewRecords: true,
canPaginate: true,
hasCellImageInfo: true,
hasRecordNavigation: true,
isEditable: true,
isFilterable: true,
isSortable: true,
};
this._db = db;
this._SelectedRecordIds = [];
this._onLoaded = stub();
this._onLoaded = stub();
this.error = false;
this.errorMessage = '';
this.linking = new LinkingMock();
Expand Down Expand Up @@ -147,6 +161,7 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
db,
this._boundTable,
item[rows.entityMetadata?.PrimaryIdAttribute || 'id'],
this._updateView,
);
return row;
});
Expand Down Expand Up @@ -188,6 +203,12 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
this.clearSelectedRecordIds.callsFake(() => {
this._SelectedRecordIds = [];
});
this.delete = stub();
this.delete.callsFake((ids) => {
return new Promise((resolve) => resolve());
});
this.getDataSetCapabilities = stub();
this.getDataSetCapabilities.callsFake(() => ({ ...this._dataSetCapabilities }));
this.getSelectedRecordIds = stub();
this.getSelectedRecordIds.callsFake(() => [...this._SelectedRecordIds]);
this.addColumn = stub();
Expand All @@ -197,6 +218,16 @@ export class DataSetMock implements ComponentFramework.PropertyTypes.DataSet {
});
this.getTitle = stub();
this.getViewId = stub();
this.newRecord = stub();
this.newRecord.callsFake(() => {
const tableMetadata = this._db.getTableMetadata(`${this._boundTable}`);
if (!tableMetadata) {
throw new Error('Please initialize the metadata for this functionality');
}

const row = new EntityRecordMock(db, this._boundTable, 'Guid.NewGuid?', this._updateView);
return row;
});
this.openDatasetItem = stub();
this.refresh = stub();
this.setSelectedRecordIds = stub();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,24 @@ export class EntityRecordMock implements ComponentFramework.PropertyHelper.DataS
_db: MetadataDB;
_boundRow: string;
_boundTable: string;
_isDirty: boolean;
_isValid: boolean;
_updateView?: ()=>void;
getFormattedValue: SinonStub<[columnName: string], string>;
getRecordId: SinonStub<[], string>;
getValue: SinonStub<[columnName: string], ColumnReturnValue>;
getNamedReference: SinonStub<[], ComponentFramework.EntityReference>;
constructor(db: MetadataDB, etn: string, id: string) {
isDirty: SinonStub<[],boolean>;
isValid: SinonStub<[], boolean>;
save: SinonStub<[],Promise<void>>;
setValue: SinonStub<[columnName: string, value: ColumnReturnValue],Promise<void>>;
constructor(db: MetadataDB, etn: string, id: string, updateView?: ()=>void) {
this._updateView = updateView;
this._db = db;
this._boundTable = etn;
this._boundRow = id;
this._isDirty = false;
this._isValid = true;
this.getFormattedValue = stub();
this.getFormattedValue.callsFake((columnName) => {
const { value, attributeMetadata } = this._db.GetValueAndMetadata<ShkoOnline.DateTimeAttributeMetadata>(
Expand Down Expand Up @@ -64,5 +74,34 @@ export class EntityRecordMock implements ComponentFramework.PropertyHelper.DataS
);
return value;
});
this.isDirty = stub();
this.isDirty.callsFake(()=>this._isDirty);
this.isValid = stub();
this.isValid.callsFake(()=>this._isValid);
this.save = stub();
this.save.callsFake(()=>{
return new Promise((resolve)=>{
setTimeout(()=>{
this._isDirty = false;
if(this._updateView){
this._updateView();
}
resolve();
},10);
});
});
this.setValue = stub();
this.setValue.callsFake((columnName, value)=>{
return new Promise((resolve)=>{
setTimeout(()=>{
this._db.UpdateValue(value, this._boundTable, columnName, this._boundRow);
this._isDirty = true;
if(this._updateView){
this._updateView();
}
resolve();
},10);
});
});
}
}
Loading

0 comments on commit 80cdb09

Please sign in to comment.