diff --git a/test/integration/api/datasets.js b/test/integration/api/datasets.js index 067dd4926..8f2b2ec73 100644 --- a/test/integration/api/datasets.js +++ b/test/integration/api/datasets.js @@ -2865,7 +2865,7 @@ describe('datasets and entities', () => { }); })); - // cb#551 issue, tag has no children + // c#551 issue, tag has no children it('should allow update where no label or no properties are updated', testService(async (service, container) => { const asAlice = await service.login('alice'); @@ -2930,7 +2930,7 @@ describe('datasets and entities', () => { }); })); - // cb#552 issue, can't add label to entity update form that previously didnt have label + // c#552 issue, can't add label to entity update form that previously didnt have label it('should allow update where no label or no properties are updated', testService(async (service) => { const asAlice = await service.login('alice'); @@ -2981,8 +2981,8 @@ describe('datasets and entities', () => { .expect(200); })); - // cb#553 issue, forms with and without entity label show different fields - // (because entity has type 'unknown' instead of 'structure') + // c#553 issue, forms with and without entity label show different fields + // (because entity was previously type 'unknown' instead of 'structure') it('should allow update where no label or no properties are updated', testService(async (service) => { const asAlice = await service.login('alice'); diff --git a/test/unit/data/dataset.js b/test/unit/data/dataset.js index 81c5c95dd..32285cbce 100644 --- a/test/unit/data/dataset.js +++ b/test/unit/data/dataset.js @@ -211,7 +211,7 @@ describe('parsing dataset from entity block', () => { should.not.exist(fields[2].propertyName); })); - it('should figure out type of entity block from form def', async () => { + it('should alawys parse entity field as type structure', async () => { const form = (entityBlock) => ` @@ -229,72 +229,51 @@ describe('parsing dataset from entity block', () => { `; + // Entity block has no children const noChildEntity = ''; await getFormFields(form(noChildEntity)).then((fields) => { - fields[0].name.should.equal('age'); - fields[0].path.should.equal('/age'); - fields[0].type.should.equal('int'); - - fields[1].name.should.equal('meta'); - fields[1].path.should.equal('/meta'); - fields[1].type.should.equal('structure'); - fields[2].name.should.equal('entity'); fields[2].path.should.equal('/meta/entity'); fields[2].type.should.equal('structure'); }); + // Entity block has no children const emptyEntity = ''; await getFormFields(form(emptyEntity)).then((fields) => { - fields[0].name.should.equal('age'); - fields[0].path.should.equal('/age'); - fields[0].type.should.equal('int'); - - fields[1].name.should.equal('meta'); - fields[1].path.should.equal('/meta'); - fields[1].type.should.equal('structure'); + fields[2].name.should.equal('entity'); + fields[2].path.should.equal('/meta/entity'); + fields[2].type.should.equal('structure'); + }); + // Entity block has whitespace + const emptyEntityWhitespace = ' '; + await getFormFields(form(emptyEntityWhitespace)).then((fields) => { fields[2].name.should.equal('entity'); fields[2].path.should.equal('/meta/entity'); fields[2].type.should.equal('structure'); }); + // Entity block is not empty (most common case) const nonEmptyEntity = ''; await getFormFields(form(nonEmptyEntity)).then((fields) => { - fields[0].name.should.equal('age'); - fields[0].path.should.equal('/age'); - fields[0].type.should.equal('int'); - - fields[1].name.should.equal('meta'); - fields[1].path.should.equal('/meta'); - fields[1].type.should.equal('structure'); - fields[2].name.should.equal('entity'); fields[2].path.should.equal('/meta/entity'); - fields[2].type.should.equal('structure'); // is type structure because it contains a child + fields[2].type.should.equal('structure'); fields[3].name.should.equal('label'); fields[3].path.should.equal('/meta/entity/label'); - fields[3].type.should.equal('unknown'); // should possibly be something other than unknown (unknown bc no binding) + fields[3].type.should.equal('unknown'); // label is unknown because there is no child and no bind }); - const nonEmptyLabel = ''; + const nonEmptyLabel = ''; await getFormFields(form(nonEmptyLabel)).then((fields) => { - fields[0].name.should.equal('age'); - fields[0].path.should.equal('/age'); - fields[0].type.should.equal('int'); - - fields[1].name.should.equal('meta'); - fields[1].path.should.equal('/meta'); - fields[1].type.should.equal('structure'); - fields[2].name.should.equal('entity'); fields[2].path.should.equal('/meta/entity'); fields[2].type.should.equal('structure'); // is type structure because it contains a child fields[3].name.should.equal('label'); fields[3].path.should.equal('/meta/entity/label'); - fields[3].type.should.equal('unknown'); // should possibly be something other than unknown (unknown bc no children and no binding) + fields[3].type.should.equal('unknown'); // type unknown because no child node and no bind }); }); }); diff --git a/test/unit/data/submission.js b/test/unit/data/submission.js index f342aa8f6..986f8869b 100644 --- a/test/unit/data/submission.js +++ b/test/unit/data/submission.js @@ -66,9 +66,10 @@ describe('submission field streamer', () => { should.config.checkProtoEql = true; }); + // true, false (entity has attributes and is included. other fields like /meta is structural but has no attributes so it is not included) it('should include structural fields with attributes', (done) => { fieldsFor(testData.forms.simpleEntity).then((fields) => - submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, true).pipe(toObjects((error, result) => { + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, true, false).pipe(toObjects((error, result) => { result.should.eql([ { field: new MockField({ order: 4, name: 'entity', path: '/meta/entity', type: 'structure', attrs: { create: '1', @@ -84,9 +85,10 @@ describe('submission field streamer', () => { }))); }); + // false, false (entity has attributes but it is structural so not included) it('should not include structural fields', (done) => { fieldsFor(testData.forms.simpleEntity).then((fields) => - submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, false).pipe(toObjects((error, result) => { + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, false, false).pipe(toObjects((error, result) => { result.should.eql([ { field: new MockField({ order: 5, name: 'label', path: '/meta/entity/label', type: 'unknown' }), text: 'Alice (88)' }, { field: new MockField({ order: 0, name: 'name', path: '/name', type: 'string', propertyName: 'first_name' }), text: 'Alice' }, @@ -97,6 +99,7 @@ describe('submission field streamer', () => { }))); }); + // true, true (entity has attributes, age is empty) it('should include structural elements with attributes and empty nodes', (done) => { fieldsFor(testData.forms.simpleEntity).then((fields) => submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one.replace('88', ''), true, true).pipe(toObjects((error, result) => { @@ -115,57 +118,21 @@ describe('submission field streamer', () => { }))); }); - it('should not return structural nodes when they have no attributes', async () => { - const form = ` - - - - - - - - - - - - - - - - - - - `; - - const fields = await fieldsFor(form); - fields.length.should.equal(5); - - const sub = ` - - one - one - - - - - - 88 - - `; - - await submissionXmlToFieldStream(fields, sub, true, true).pipe(toObjects((error, result) => { - result.should.eql([ - // /meta/entity field is not present because it has no attribtues, which means it isn't used later by parseSubmissionXml - // which is good, because it wont try to access non-existent entity attributes. - // the entity system data stuff will be set to null and will log an appropriate error. - { field: new MockField({ order: 4, name: 'label', path: '/meta/entity/label', type: 'unknown' }), text: 'foo' }, - // /person is also not included because it is a structural node with no attributes. but it's child is included. - { field: new MockField({ order: 1, name: 'age', path: '/person/age', type: 'int', propertyName: 'age' }), text: '88' }, - ]); - })); + // false, true (age is empty here. other fields like name and hometown are not empty and are returned as normal.) + it('should include empty nodes but no structural nodes', (done) => { + fieldsFor(testData.forms.simpleEntity).then((fields) => + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one.replace('88', ''), false, true).pipe(toObjects((error, result) => { + result.should.eql([ + { field: new MockField({ order: 5, name: 'label', path: '/meta/entity/label', type: 'unknown' }), text: 'Alice (88)' }, + { field: new MockField({ order: 0, name: 'name', path: '/name', type: 'string', propertyName: 'first_name' }), text: 'Alice' }, + { field: new MockField({ order: 1, name: 'age', path: '/age', type: 'int', propertyName: 'age' }), text: '' }, + { field: new MockField({ order: 2, name: 'hometown', path: '/hometown', type: 'string' }), text: 'Chicago' } + ]); + done(); + }))); }); + // related to issue c#551 where block had no children so extracting the attributes was breaking. it('should handle attributes on entity tag with no children', async () => { const form = ` @@ -174,6 +141,9 @@ describe('submission field streamer', () => { + + + @@ -181,13 +151,15 @@ describe('submission field streamer', () => { + `; + // This is all the fields in the form including structural fields const fields = await fieldsFor(form); - fields.map(f => f.name).should.eql(['age', 'meta', 'entity']); - fields.map(f => f.type).should.eql(['int', 'structure', 'structure']); + fields.map(f => f.name).should.eql(['age', 'location', 'hometown', 'meta', 'entity']); + fields.map(f => f.type).should.eql(['int', 'structure', 'string', 'structure', 'structure']); const sub = ` @@ -196,17 +168,24 @@ describe('submission field streamer', () => { 88 + + + `; + // This is where we use the full field list above to pull out only the fields that are relevant to entity parsing + // - with its attribuets + // - all leaf nodes even if they are empty await submissionXmlToFieldStream(fields, sub, true, true).pipe(toObjects((error, result) => { result.should.eql([ - { field: new MockField({ order: 2, name: 'entity', path: '/meta/entity', type: 'structure', attrs: { + { field: new MockField({ order: 4, name: 'entity', path: '/meta/entity', type: 'structure', attrs: { update: '1', baseVersion: '1', dataset: 'people', id: '12345678-1234-4123-8234-123456789abc' } }), text: null }, { field: new MockField({ order: 0, name: 'age', path: '/age', type: 'int', propertyName: 'age' }), text: '88' }, + { field: new MockField({ order: 2, name: 'hometown', path: '/location/hometown', type: 'string', propertyName: 'hometown' }), text: '' }, ]); })); });