@shko.online/componentframework-mock
Version:
Mocking library to help with testing PowerApps Component Framework Components
269 lines (268 loc) • 12.1 kB
JavaScript
/*
Copyright (c) 2022 Betim Beja and Shko Online LLC
Licensed under the MIT license.
*/
import { stub } from 'sinon';
import { parseOData } from '@shko.online/dataverse-odata';
import { AttributeType } from './PropertyTypes';
import { DelayedPromise } from '../utils/DelayedPromise';
export class WebApiMock {
constructor(db, formatting) {
this._Delay = 200;
this._ConvertRowToOData = void 0;
this.createRecord = void 0;
this.deleteRecord = void 0;
this.updateRecord = void 0;
this.retrieveMultipleRecords = void 0;
this.retrieveRecord = void 0;
this._ConvertRowToOData = stub();
this._ConvertRowToOData.callsFake((row, entityMetadata) => {
const oldRow = row;
if (entityMetadata.Attributes) {
entityMetadata.Attributes.forEach(attribute => {
const key = attribute.LogicalName;
if (/* attribute.AttributeType === AttributeType.Uniqueidentifier ||*/
attribute.AttributeType === AttributeType.Boolean) {
if (row[key] === undefined || row[key] === null) {
delete row[key];
}
} else if (attribute.AttributeType === AttributeType.Lookup) {
const key = `_${attribute.LogicalName}_value`;
const lookupValue = oldRow[key];
if (key in row) {
var _lookupValue$id;
row[key] = (_lookupValue$id = lookupValue === null || lookupValue === void 0 ? void 0 : lookupValue.id) !== null && _lookupValue$id !== void 0 ? _lookupValue$id : null;
if (lookupValue !== null && lookupValue !== void 0 && lookupValue.id) {
row[`${key}@Microsoft.Dynamics.CRM.lookuplogicalname`] = lookupValue.entityType;
if (lookupValue.name != null) {
row[`${key}@OData.Community.Display.V1.FormattedValue`] = lookupValue.name;
}
if (oldRow[`${attribute.LogicalName}navigation`]) {
row[`${key}@Microsoft.Dynamics.CRM.associatednavigationproperty`] = oldRow[`${attribute.LogicalName}navigation`];
}
}
}
delete row[`${attribute.LogicalName}type`];
delete row[`${attribute.LogicalName}navigation`];
} else if (attribute.AttributeType === AttributeType.DateTime) {
const dateValue = row[key];
if (dateValue) {
const YYYY = dateValue.getFullYear();
let MM = '0' + (dateValue.getMonth() + 1);
MM = MM.substring(MM.length - 2);
let DD = '0' + dateValue.getDate();
DD = DD.substring(DD.length - 2);
let HH = '0' + dateValue.getUTCHours();
HH = HH.substring(HH.length - 2);
let mm = '0' + dateValue.getMinutes();
mm = mm.substring(mm.length - 2);
let ss = '0' + dateValue.getSeconds();
ss = ss.substring(ss.length - 2);
row[key] = `${YYYY}-${MM}-${DD}T${HH}:${mm}:${ss}Z`;
row[`${key}@OData.Community.Display.V1.FormattedValue`] = `${dateValue.getUTCMonth() + 1}/${dateValue.getUTCDate()}/${dateValue.getUTCFullYear()} ${(dateValue.getUTCHours() - 1) % 12 + 1}:${dateValue.getUTCMinutes()} ${dateValue.getUTCHours() > 12 || dateValue.getUTCHours() == 12 && dateValue.getMinutes() > 0 ? 'PM' : 'AM'}`;
} else {
delete row[key];
}
} else if (attribute.AttributeType === AttributeType.Integer || attribute.AttributeType === AttributeType.BigInt) {
if (row[key] !== null && row[key] !== undefined) {
row[key + '@OData.Community.Display.V1.FormattedValue'] = formatting.formatInteger(row[key]);
}
}
if (!!attribute.AttributeOf) {
var _entityMetadata$Attri, _original$LogicalName, _original$LogicalName2;
const original = (_entityMetadata$Attri = entityMetadata.Attributes) === null || _entityMetadata$Attri === void 0 ? void 0 : _entityMetadata$Attri.find(att => att.LogicalName == attribute.AttributeOf);
if ((original === null || original === void 0 ? void 0 : original.AttributeType) !== AttributeType.Lookup && oldRow[(_original$LogicalName = original === null || original === void 0 ? void 0 : original.LogicalName) !== null && _original$LogicalName !== void 0 ? _original$LogicalName : ''] !== undefined && oldRow[(_original$LogicalName2 = original === null || original === void 0 ? void 0 : original.LogicalName) !== null && _original$LogicalName2 !== void 0 ? _original$LogicalName2 : ''] !== null && oldRow[key] !== null && oldRow[key] !== undefined && (original === null || original === void 0 ? void 0 : original.LogicalName) in row) {
row[(original === null || original === void 0 ? void 0 : original.LogicalName) + '@OData.Community.Display.V1.FormattedValue'] = oldRow[key];
}
delete row[key];
}
});
}
Object.getOwnPropertyNames(row).forEach(key => {
if (row[key] === undefined) {
row[key] = null;
}
});
});
this.createRecord = stub();
this.createRecord.callsFake((entityType, data) => {
const metadata = db.getTableMetadata(entityType);
if (!metadata) {
return DelayedPromise.rejectAfterDelay({
message: `Entity ${entityType} does not exist.`
}, this._Delay);
}
return DelayedPromise.resolveAfterDelay({
id: db.AddRow(entityType, data, metadata) || '',
name: data[metadata.PrimaryNameAttribute || 'name'],
entityType: entityType
}, this._Delay);
});
this.deleteRecord = stub();
this.deleteRecord.callsFake((entityType, id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
var _result$row;
const result = db.GetRow(entityType, id);
if (!result.entityMetadata) {
return reject({
message: `Entity ${entityType} does not exist.`
});
}
if (!result.row) {
return reject({
message: `Could not find record with id: '${id}' for entity: '${entityType}'.`
});
}
db.RemoveRow(entityType, id);
resolve({
id,
name: (_result$row = result.row) === null || _result$row === void 0 ? void 0 : _result$row[result.entityMetadata.PrimaryNameAttribute || 'name'],
entityType
});
}, this._Delay);
});
});
this.updateRecord = stub();
this.updateRecord.callsFake((entityType, id, data) => {
var _metadata$Attributes, _result$row2;
const attributeHandler = attribute => {
if (attribute.AttributeOf || attribute.AttributeType === AttributeType.Virtual) {
return;
}
const key = attribute.AttributeType === AttributeType.Lookup ? `_${attribute.LogicalName}_value` : attribute.LogicalName;
if (key in data) {
db.UpdateValue(data[key], entityType, key, id);
}
};
const metadata = db.getTableMetadata(entityType);
if (!metadata) {
return DelayedPromise.rejectAfterDelay(`Entity ${entityType} does not exist.`, this._Delay);
}
(_metadata$Attributes = metadata.Attributes) === null || _metadata$Attributes === void 0 || _metadata$Attributes.forEach(attributeHandler);
const result = db.GetRow(entityType, id);
return DelayedPromise.resolveAfterDelay({
id,
name: (_result$row2 = result.row) === null || _result$row2 === void 0 ? void 0 : _result$row2[metadata.PrimaryNameAttribute || 'name'],
entityType
}, this._Delay);
});
this.retrieveMultipleRecords = stub();
this.retrieveMultipleRecords.callsFake((entityType, options, maxPageSize) => {
return new Promise((resolve, reject) => {
const parsed = options ? parseOData(options) : {};
if (parsed.error) {
reject(parsed.error);
}
const entityMetadata = db.getTableMetadata(entityType);
if (!entityMetadata) {
reject(`Table ${entityType} does not exist`);
return;
}
if (parsed.userQuery) {
const userQuery = db.GetRow('userquery', parsed.userQuery);
if (!userQuery.row) {
reject({
code: '0x80040217',
message: `Entity 'userquery' With Id = ${parsed.userQuery} Does Not Exist`
});
return;
}
if (userQuery.row['returnedtypecode'] !== entityMetadata.LogicalName) {
reject({
code: '0x80060888',
message: 'No Query View exists with the Given Query Id on the Entity Set.'
});
return;
}
const parsedUserQuery = parseOData('?fetchXml=' + encodeURIComponent(userQuery.row['fetchxml']));
if (!parsedUserQuery.fetchXml) {
throw new Error(`User Query with id ${parsed.userQuery} contains wrong data`);
}
const entities = db.SelectUsingFetchXml(parsedUserQuery.fetchXml);
resolve({
entities,
nextLink: 'next'
});
return;
}
if (parsed.savedQuery) {
const savedQuery = db.GetRow('savedquery', parsed.savedQuery);
if (!savedQuery.row) {
reject({
code: '0x80040217',
message: `Entity 'savedquery' With Id = ${parsed.savedQuery} Does Not Exist`
});
return;
}
if (savedQuery.row['returnedtypecode'] !== entityMetadata.LogicalName) {
reject({
code: '0x80060888',
message: 'No Query View exists with the Given Query Id on the Entity Set.'
});
return;
}
const parsedSavedQuery = parseOData('?fetchXml=' + encodeURIComponent(savedQuery.row['fetchxml']));
if (!parsedSavedQuery.fetchXml) {
throw new Error(`Saved Query with id ${parsed.savedQuery} contains wrong data`);
}
const entities = db.SelectUsingFetchXml(parsedSavedQuery.fetchXml);
resolve({
entities,
nextLink: 'next'
});
return;
}
if (parsed.fetchXml) {
const entities = db.SelectUsingFetchXml(parsed.fetchXml);
resolve({
entities,
nextLink: 'next'
});
return;
}
const entities = db.SelectUsingOData(entityMetadata, parsed);
entities.forEach(row => {
this._ConvertRowToOData(row, entityMetadata);
});
resolve({
entities,
nextLink: 'string'
});
});
});
this.retrieveRecord = stub();
this.retrieveRecord.callsFake((entityType, id, options) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const result = db.GetRowForAPI(entityType, id);
if (!result.entityMetadata) {
return reject({
message: `Entity ${entityType} does not exist.`
});
}
if (!result.row) {
return reject({
message: `Could not find record with id: '${id}' for entity: '${entityType}'.`
});
}
if (options) {
var parsed = parseOData(options);
if (parsed.$select) {
const oldRow = result.row;
result.row = {};
parsed.$select.forEach(attribute => {
result.row[attribute] = oldRow[attribute];
});
if (result.entityMetadata.PrimaryIdAttribute !== undefined && !parsed.$select.includes(result.entityMetadata.PrimaryIdAttribute)) {
result.row[result.entityMetadata.PrimaryIdAttribute] = oldRow[result.entityMetadata.PrimaryIdAttribute];
}
}
}
this._ConvertRowToOData(result.row, result.entityMetadata);
resolve(result.row);
}, this._Delay);
});
});
}
}