@nymphjs/nymph
Version:
Nymph.js - Nymph ORM
366 lines • 16 kB
JavaScript
import { jest } from '@jest/globals';
import { cloneDeep } from 'lodash-es';
import { MockNymph } from './testMocks.js';
import { TestBModel as TestBModelClass, TestModel as TestModelClass, } from './testArtifacts.js';
const nymph = new MockNymph();
jest.mock('./Nymph', () => ({
__esModule: true,
default: nymph,
}));
const TestModel = nymph.addEntityClass(TestModelClass);
const TestBModel = nymph.addEntityClass(TestBModelClass);
let testEntity = TestModel.factorySync();
let entityReferenceTest;
let entityReferenceGuid;
describe('Entity', () => {
it('instantiates correctly', () => {
expect(testEntity).toBeInstanceOf(TestModel);
expect(testEntity.$hasTag('test')).toEqual(true);
expect(testEntity.boolean).toEqual(true);
});
it('assignments work', async () => {
// Assign some variables.
testEntity.name = 'Entity Test';
testEntity.null = null;
testEntity.string = 'test';
testEntity.array = ['full', 'of', 'values', 500];
testEntity.number = 30;
expect(testEntity.name).toEqual('Entity Test');
expect(testEntity.null).toBeNull();
expect(testEntity.string).toEqual('test');
expect(testEntity.array).toEqual(['full', 'of', 'values', 500]);
expect(testEntity.number).toEqual(30);
expect(await testEntity.$save()).toEqual(true);
expect(typeof testEntity.guid).toEqual('string');
entityReferenceTest = await TestModel.factory();
entityReferenceTest.string = 'wrong';
expect(await entityReferenceTest.$save()).toEqual(true);
entityReferenceGuid = entityReferenceTest.guid;
testEntity.reference = entityReferenceTest;
testEntity.refArray = [entityReferenceTest];
testEntity.refObject = {
entity: entityReferenceTest,
};
expect(await testEntity.$save()).toEqual(true);
entityReferenceTest.test = 'good';
expect(await entityReferenceTest.$save()).toEqual(true);
});
it('comparisons work', async () => {
const compare = await TestModel.factory(testEntity.guid);
expect(testEntity.$is(compare)).toEqual(true);
await testEntity.$refresh();
await compare.$refresh();
expect(testEntity.$equals(compare)).toEqual(true);
compare.string = 'different';
expect(testEntity.$is(compare)).toEqual(true);
expect(testEntity.$equals(compare)).toEqual(false);
});
it('array searching work', async () => {
const testInArray = await TestModel.factory(testEntity.guid);
const array = [
'thing',
testInArray,
];
expect(testEntity.$inArray(array)).toEqual(true);
await testEntity.$refresh();
await testInArray.$refresh();
expect(testEntity.$inArray(array, true)).toEqual(true);
expect(testEntity.$inArray([0, 1, 2, 3, 4, 5])).toEqual(false);
expect(testEntity.$inArray([0, 1, 2, 3, 4, 5], true)).toEqual(false);
testInArray.string = 'different';
expect(testEntity.$inArray(array)).toEqual(true);
expect(testEntity.$inArray(array, true)).toEqual(false);
expect(testEntity.$arraySearch(array)).toEqual(1);
await testEntity.$refresh();
await testInArray.$refresh();
expect(testEntity.$arraySearch(array, true)).toEqual(1);
expect(testEntity.$arraySearch([0, 1, 2, 3, 4, 5])).toEqual(-1);
expect(testEntity.$arraySearch([0, 1, 2, 3, 4, 5], true)).toEqual(-1);
testInArray.string = 'different';
expect(testEntity.$arraySearch(array)).toEqual(1);
expect(testEntity.$arraySearch(array, true)).toEqual(-1);
});
it('refresh work', async () => {
testEntity.boolean = false;
expect(testEntity.boolean).toEqual(false);
expect(await testEntity.$refresh()).toEqual(true);
expect(testEntity.boolean).toEqual(true);
});
it('refresh updates', async () => {
expect(testEntity.string).toEqual('test');
testEntity.string = 'updated';
expect(await testEntity.$save()).toEqual(true);
await testEntity.$refresh();
expect(await testEntity.$save()).toEqual(true);
const retrieve = await TestModel.factory(testEntity.guid);
expect(retrieve.string).toEqual('updated');
retrieve.string = 'test';
expect(await retrieve.$save()).toBe(true);
await testEntity.$refresh();
expect(testEntity.string).toEqual('test');
});
it('conflict fails to save', async () => {
await new Promise((resolve) => setTimeout(resolve, 500));
const testEntityCopy = await TestModel.factory(testEntity.guid);
expect(await testEntityCopy.$save()).toEqual(true);
expect(testEntityCopy.mdate ?? 0).toBeGreaterThan(testEntity.mdate ?? 0);
await new Promise((resolve) => setTimeout(resolve, 500));
expect(await testEntity.$save()).toEqual(false);
await testEntity.$refresh();
expect(testEntityCopy.mdate ?? Infinity).toBeLessThanOrEqual(testEntity.mdate ?? 0);
});
it('toReference works', () => {
const reference = testEntity.$toReference();
expect(reference).toEqual([
'nymph_entity_reference',
testEntity.guid,
'TestModel',
]);
});
it('toReference works even on an unsaved entity', () => {
const unsavedEntity = TestModel.factorySync();
const reference = unsavedEntity.$toReference();
expect(unsavedEntity.guid).toBeNull();
expect(reference).toEqual([
'nymph_entity_reference',
unsavedEntity.$getGuaranteedGUID(),
'TestModel',
]);
});
it('tags work', async () => {
expect(testEntity.$hasTag('test')).toEqual(true);
testEntity.$addTag('test', 'test2');
expect(testEntity.$hasTag('test', 'test2')).toEqual(true);
testEntity.$addTag('test', 'test3', 'test4', 'test5', 'test6');
expect(testEntity.$hasTag('test', 'test3', 'test4', 'test5', 'test6')).toEqual(true);
testEntity.$removeTag('test2');
expect(testEntity.$hasTag('test2')).toEqual(false);
testEntity.$removeTag('test3', 'test4');
expect(testEntity.$hasTag('test3', 'test4')).toEqual(false);
testEntity.$removeTag('test5', 'test6');
expect(testEntity.$hasTag('test5', 'test6')).toEqual(false);
expect(testEntity.$getTags()).toEqual(['test']);
// Remove all tags.
testEntity.$removeTag('test');
expect(await testEntity.$save()).toEqual(true);
expect(await testEntity.$refresh()).toEqual(true);
expect(testEntity.$hasTag('test')).toEqual(false);
expect(testEntity.$getTags()).toEqual([]);
testEntity.$addTag('test');
expect(await testEntity.$save()).toEqual(true);
expect(testEntity.$hasTag('test')).toEqual(true);
});
it('references work', async () => {
await testEntity.$refresh();
await testEntity.reference?.$wake();
expect(testEntity.reference?.guid).toEqual(entityReferenceGuid);
await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []);
expect(testEntity.refArray?.[0].guid).toEqual(entityReferenceGuid);
await testEntity.refObject?.entity.$wake();
expect(testEntity.refObject?.entity.guid).toEqual(entityReferenceGuid);
const entity = await TestModel.factory(testEntity.guid);
await entity.reference?.$wake();
expect(entity.reference?.guid).toEqual(entityReferenceGuid);
await Promise.all(entity.refArray?.map((e) => e.$wake()) || []);
expect(entity.refArray?.[0].guid).toEqual(entityReferenceGuid);
await entity.refObject?.entity.$wake();
expect(entity.refObject?.entity.guid).toEqual(entityReferenceGuid);
});
it('sleeping references wake up', async () => {
const entity = TestModel.factoryReference([
'nymph_entity_reference',
testEntity.guid,
'TestModel',
]);
await entity.$wake();
expect(entity.guid).toEqual(testEntity.guid);
expect(entity.cdate).toEqual(testEntity.cdate);
expect(entity.mdate).toEqual(testEntity.mdate);
expect(entity.tags).toEqual(testEntity.tags);
expect(entity.name).toEqual('Entity Test');
expect(entity.null).toBeNull();
expect(entity.string).toEqual('test');
expect(entity.array).toEqual(['full', 'of', 'values', 500]);
expect(entity.number).toEqual(30);
await entity.reference?.$wake();
expect(entity.reference?.guid).toEqual(entityReferenceGuid);
await Promise.all(entity.refArray?.map((e) => e.$wake()) || []);
expect(entity.refArray?.[0].guid).toEqual(entityReferenceGuid);
await entity.refObject?.entity.$wake();
expect(entity.refObject?.entity.guid).toEqual(entityReferenceGuid);
});
it('JSON encoding works', () => {
const json = JSON.parse(JSON.stringify(testEntity));
expect(json).toEqual({
guid: testEntity.guid,
cdate: testEntity.cdate,
mdate: testEntity.mdate,
tags: ['test'],
data: {
reference: ['nymph_entity_reference', entityReferenceGuid, 'TestModel'],
refArray: [
['nymph_entity_reference', entityReferenceGuid, 'TestModel'],
],
refObject: {
entity: ['nymph_entity_reference', entityReferenceGuid, 'TestModel'],
},
name: 'Entity Test',
number: 30,
array: ['full', 'of', 'values', 500],
string: 'test',
null: null,
uniques: [],
},
class: 'TestModel',
});
});
it('incoming JSON works', async () => {
// Test that a property can be deleted.
let json = JSON.stringify(testEntity);
const entityDataDelete = JSON.parse(json);
entityDataDelete.mdate++;
delete entityDataDelete.data.string;
testEntity.$jsonAcceptData(cloneDeep(entityDataDelete));
expect(testEntity.string).toBeUndefined();
expect(await testEntity.$refresh()).toEqual(true);
// Test whitelisted data.
json = JSON.stringify(testEntity);
const entityData = JSON.parse(json);
testEntity.cdate = 13;
testEntity.mdate = 14;
entityData.cdate = 13;
entityData.mdate = 15;
entityData.tags = ['notag', 'newtag'];
entityData.data.name = 'bad';
entityData.data.string = 'good';
delete entityData.data.null;
entityData.data.array = ['imanarray'];
entityData.data.number = 4;
delete entityData.data.reference;
entityData.data.refArray = [];
entityData.data.refObject = {};
testEntity.$jsonAcceptData(cloneDeep(entityData));
expect(testEntity.$hasTag('notag')).toEqual(false);
expect(testEntity.$hasTag('test')).toEqual(true);
expect(testEntity.$hasTag('newtag')).toEqual(true);
expect(testEntity.cdate).toEqual(13.0);
expect(testEntity.mdate).toEqual(15);
expect(testEntity.name).toEqual('Entity Test');
expect(testEntity.null).toBeNull();
expect(testEntity.string).toEqual('good');
expect(testEntity.array).toEqual(['imanarray']);
expect(testEntity.number).toEqual(30);
await testEntity.reference?.$wake();
expect(testEntity.reference?.guid).toEqual(entityReferenceGuid);
await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []);
expect(testEntity.refArray?.[0].guid).toEqual(entityReferenceGuid);
await testEntity.refObject?.entity.$wake();
expect(testEntity.refObject?.entity.guid).toEqual(entityReferenceGuid);
expect(await testEntity.$refresh()).toEqual(true);
testEntity.cdate = 13;
testEntity.mdate = 14;
testEntity.$jsonAcceptPatch({
class: TestModel.class,
guid: testEntity.guid,
mdate: 15,
set: {
refArray: [],
},
unset: ['reference'],
addTags: ['notag', 'newtag'],
removeTags: ['test'],
});
expect(testEntity.$hasTag('notag')).toEqual(false);
expect(testEntity.$hasTag('test')).toEqual(true);
expect(testEntity.$hasTag('newtag')).toEqual(true);
await testEntity.reference?.$wake();
expect(testEntity.reference?.guid).toEqual(entityReferenceGuid);
await Promise.all(testEntity.refArray?.map((e) => e.$wake()) || []);
expect(testEntity.refArray?.[0].guid).toEqual(entityReferenceGuid);
expect(await testEntity.$refresh()).toEqual(true);
// Test no whitelist, but protected data instead.
const undo = testEntity.$useProtectedData();
testEntity.cdate = 13;
testEntity.mdate = 14;
testEntity.$jsonAcceptData(cloneDeep(entityData));
expect(testEntity.$hasTag('notag')).toEqual(true);
expect(testEntity.$hasTag('newtag')).toEqual(true);
expect(testEntity.cdate).toEqual(13.0);
expect(testEntity.mdate).toEqual(15);
expect(testEntity.name).toEqual('bad');
expect(testEntity.null).toBeUndefined();
expect(testEntity.string).toEqual('good');
expect(testEntity.array).toEqual(['imanarray']);
expect(testEntity.number).toEqual(30);
expect(testEntity.reference).toBeUndefined();
expect(testEntity.refArray).toEqual([]);
expect(testEntity.refObject).toEqual({});
expect(await testEntity.$refresh()).toEqual(true);
testEntity.cdate = 13;
testEntity.mdate = 14;
testEntity.$jsonAcceptPatch({
class: TestModel.class,
guid: testEntity.guid,
mdate: 15,
set: {
string: 'good',
},
unset: ['null'],
addTags: ['newtag'],
removeTags: ['test'],
});
expect(testEntity.$hasTag('test')).toEqual(false);
expect(testEntity.$hasTag('newtag')).toEqual(true);
expect(testEntity.string).toEqual('good');
expect(testEntity.null).toBeUndefined();
undo();
expect(await testEntity.$refresh()).toEqual(true);
});
it("conflicting JSON doesn't work", async () => {
// Test that an old JSON payload causes a conflict.
const json = JSON.stringify(testEntity);
expect(await testEntity.$save()).toEqual(true);
let thrown = false;
let thrownName = '';
const data = JSON.parse(json);
try {
testEntity.$jsonAcceptData(data);
}
catch (e) {
thrown = true;
thrownName = e?.name;
}
expect(thrown).toEqual(true);
expect(thrownName).toEqual('EntityConflictError');
thrown = false;
thrownName = '';
try {
testEntity.$jsonAcceptPatch({
class: TestModel.class,
guid: data.guid,
mdate: data.mdate,
set: {
string: 'good',
},
unset: [],
addTags: [],
removeTags: [],
});
}
catch (e) {
thrown = true;
thrownName = e?.name;
}
expect(thrown).toEqual(true);
});
it('JSON with new entities works', async () => {
testEntity.reference = await TestModel.factory();
// Test that an old JSON payload causes a conflict.
const json = JSON.stringify(testEntity);
const data = JSON.parse(json);
console.log(data.data.reference);
testEntity.$jsonAcceptData(data);
expect(testEntity.reference.guid).toBeNull();
});
});
//# sourceMappingURL=Entity.test.js.map