2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 12:08:27 +00:00

test: schema builder

This commit is contained in:
18alantom 2022-03-25 18:02:37 +05:30
parent 74bfe7931c
commit 4800112ff4
3 changed files with 279 additions and 2 deletions

63
schemas/tests/helpers.ts Normal file
View File

@ -0,0 +1,63 @@
import Account from '../app/Account.json';
import Customer from '../app/Customer.json';
import JournalEntry from '../app/JournalEntry.json';
import JournalEntryAccount from '../app/JournalEntryAccount.json';
import Party from '../app/Party.json';
import PartyRegional from '../regional/in/Party.json';
import { Schema, SchemaStub, SchemaStubMap } from '../types';
interface AppSchemaMap extends SchemaStubMap {
Account: SchemaStub;
JournalEntry: SchemaStub;
JournalEntryAccount: SchemaStub;
Party: SchemaStub;
Customer: SchemaStub;
}
interface RegionalSchemaMap extends SchemaStubMap {
Party: SchemaStub;
}
export function getTestSchemaMap(): {
appSchemaMap: AppSchemaMap;
regionalSchemaMap: RegionalSchemaMap;
} {
const appSchemaMap = {
Account,
JournalEntry,
JournalEntryAccount,
Party,
Customer,
} as AppSchemaMap;
const regionalSchemaMap = { Party: PartyRegional } as RegionalSchemaMap;
return {
appSchemaMap,
regionalSchemaMap,
};
}
export function everyFieldExists(fieldList: string[], schema: Schema): boolean {
return fieldsExist(fieldList, schema, 'every');
}
export function someFieldExists(fieldList: string[], schema: Schema): boolean {
return fieldsExist(fieldList, schema, 'some');
}
function fieldsExist(
fieldList: string[],
schema: Schema,
type: 'every' | 'some'
): boolean {
const schemaFieldNames = schema.fields.map((f) => f.fieldname);
return fieldList.map((f) => schemaFieldNames.includes(f))[type](Boolean);
}
export function subtract(
targetList: string[],
...removalLists: string[][]
): string[] {
const removalList = removalLists.flat();
return targetList.filter((f) => !removalList.includes(f));
}

View File

@ -0,0 +1,213 @@
import * as assert from 'assert';
import { cloneDeep, isEqual } from 'lodash';
import { describe } from 'mocha';
import { getMapFromList } from '../helpers';
import {
addMetaFields,
cleanSchemas,
getAbstractCombinedSchemas,
getRegionalCombinedSchemas,
} from '../index';
import { metaSchemas } from '../schemas';
import {
everyFieldExists,
getTestSchemaMap,
someFieldExists,
subtract,
} from './helpers';
describe('Schema Builder', function () {
const { appSchemaMap, regionalSchemaMap } = getTestSchemaMap();
describe('Raw Schemas', function () {
specify('Meta Properties', function () {
assert.strictEqual(appSchemaMap.Party.isAbstract, true);
assert.strictEqual(appSchemaMap.Customer.extends, 'Party');
assert.strictEqual(appSchemaMap.Account.isTree, true);
assert.strictEqual(appSchemaMap.JournalEntryAccount.isChild, true);
});
specify('Field Counts', function () {
assert.strictEqual(appSchemaMap.Account.fields?.length, 6);
assert.strictEqual(appSchemaMap.JournalEntry.fields?.length, 8);
assert.strictEqual(appSchemaMap.JournalEntryAccount.fields?.length, 3);
assert.strictEqual(appSchemaMap.Party.fields?.length, 8);
assert.strictEqual(appSchemaMap.Customer.fields?.length, undefined);
assert.strictEqual(regionalSchemaMap.Party.fields?.length, 2);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(appSchemaMap.Party.quickEditFields?.length, 5);
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 7);
});
});
const regionalCombined = getRegionalCombinedSchemas(
appSchemaMap,
regionalSchemaMap
);
describe('Regional Combined Schemas', function () {
specify('Field Counts', function () {
assert.strictEqual(regionalCombined.Party.fields?.length, 10);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 7);
});
specify('Schema Equality with App Schemas', function () {
assert.strictEqual(
isEqual(regionalCombined.Account, appSchemaMap.Account),
true
);
assert.strictEqual(
isEqual(regionalCombined.JournalEntry, appSchemaMap.JournalEntry),
true
);
assert.strictEqual(
isEqual(
regionalCombined.JournalEntryAccount,
appSchemaMap.JournalEntryAccount
),
true
);
assert.strictEqual(
isEqual(regionalCombined.Customer, appSchemaMap.Customer),
true
);
assert.strictEqual(
isEqual(regionalCombined.Party, appSchemaMap.Party),
false
);
});
});
const abstractCombined = cleanSchemas(
getAbstractCombinedSchemas(regionalCombined)
);
describe('Abstract Combined Schemas', function () {
specify('Meta Properties', function () {
assert.strictEqual(abstractCombined.Customer.extends, undefined);
});
specify('Abstract Schema Existance', function () {
assert.strictEqual(abstractCombined.Party, undefined);
});
specify('Field Counts', function () {
assert.strictEqual(abstractCombined.Customer.fields?.length, 10);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(abstractCombined.Customer.quickEditFields?.length, 7);
});
specify('Schema Equality with App Schemas', function () {
assert.strictEqual(
isEqual(abstractCombined.Account, appSchemaMap.Account),
true
);
assert.strictEqual(
isEqual(abstractCombined.JournalEntry, appSchemaMap.JournalEntry),
true
);
assert.strictEqual(
isEqual(
abstractCombined.JournalEntryAccount,
appSchemaMap.JournalEntryAccount
),
true
);
assert.strictEqual(
isEqual(abstractCombined.Customer, appSchemaMap.Customer),
false
);
});
specify('Schema Field Existance', function () {
assert.strictEqual(
everyFieldExists(
regionalSchemaMap.Party.quickEditFields ?? [],
abstractCombined.Customer
),
true
);
});
});
const finalSchemas = addMetaFields(cloneDeep(abstractCombined));
const metaSchemaMap = getMapFromList(metaSchemas, 'name');
const baseFieldNames = metaSchemaMap.base.fields!.map((f) => f.fieldname);
const childFieldNames = metaSchemaMap.child.fields!.map((f) => f.fieldname);
const treeFieldNames = metaSchemaMap.tree.fields!.map((f) => f.fieldname);
const submittableFieldNames = metaSchemaMap.submittable.fields!.map(
(f) => f.fieldname
);
const allFieldNames = [
...baseFieldNames,
...childFieldNames,
...treeFieldNames,
...submittableFieldNames,
];
describe('Final Schemas', function () {
specify('Schema Field Existance', function () {
assert.strictEqual(
everyFieldExists(baseFieldNames, finalSchemas.Customer),
true
);
assert.strictEqual(
someFieldExists(
subtract(allFieldNames, baseFieldNames),
finalSchemas.Customer
),
false
);
assert.strictEqual(
everyFieldExists(
[...baseFieldNames, ...submittableFieldNames],
finalSchemas.JournalEntry
),
true
);
assert.strictEqual(
someFieldExists(
subtract(allFieldNames, baseFieldNames, submittableFieldNames),
finalSchemas.JournalEntry
),
false
);
assert.strictEqual(
everyFieldExists(childFieldNames, finalSchemas.JournalEntryAccount),
true
);
assert.strictEqual(
someFieldExists(
subtract(allFieldNames, childFieldNames),
finalSchemas.JournalEntryAccount
),
false
);
assert.strictEqual(
everyFieldExists(
[...treeFieldNames, ...baseFieldNames],
finalSchemas.Account
),
true
);
assert.strictEqual(
someFieldExists(
subtract(allFieldNames, treeFieldNames, baseFieldNames),
finalSchemas.Account
),
false
);
});
});
});

View File

@ -107,7 +107,7 @@ export type Field =
export type TreeSettings = { parentField: string }; export type TreeSettings = { parentField: string };
// prettier-ignore // @formattoer:off
export interface Schema { export interface Schema {
name: string; // Table PK name: string; // Table PK
label: string; // Translateable UI facing name label: string; // Translateable UI facing name
@ -118,7 +118,8 @@ export interface Schema {
isSingle?: boolean; // Fields will be values in SingleValue, i.e. an Entity Attr. Value isSingle?: boolean; // Fields will be values in SingleValue, i.e. an Entity Attr. Value
isAbstract?: boolean; // Not entered into db, used to extend a Subclass schema isAbstract?: boolean; // Not entered into db, used to extend a Subclass schema
isSubmittable?: boolean; // For transactional types, values considered only after submit isSubmittable?: boolean; // For transactional types, values considered only after submit
keywordFields?: string[]; // Used for fields that are to be used for search. keywordFields?: string[]; // Used to get fields that are to be used for search.
quickEditFields?: string[]; // Used to get fields for the quickEditForm
treeSettings?: TreeSettings; // Used to determine root nodes treeSettings?: TreeSettings; // Used to determine root nodes
} }