From 304c8aac1ac97b8ac67a88073929d4ed7bb31ae9 Mon Sep 17 00:00:00 2001 From: Kathleen Tuite Date: Wed, 1 Nov 2023 17:02:24 -0700 Subject: [PATCH] updated comment, added tests around submissionXmlToFieldStream --- lib/data/submission.js | 21 ++++++----- test/unit/data/submission.js | 67 +++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/lib/data/submission.js b/lib/data/submission.js index 9054144db..3619880d1 100644 --- a/lib/data/submission.js +++ b/lib/data/submission.js @@ -21,19 +21,22 @@ const { union, last, pluck } = require('ramda'); // field in the submission. does no processing at all to localize repeat groups, // etc. it's just a stream of found data values. // -// !!! !!! WARNING WARNING: -// right now this facility is used only by generateExpectedAttachments, which wants +// the original place this facility is used is by generateExpectedAttachments, which wants // to navigate the schema stack ignoring gaps so it can just deal w binary fields. +// +// the second place this is used is by parseSubmissionXml for parsing entity data from +// submissions. this scenario is similar to the one above in that we want to navigate to +// specific entity-property fields and the SchemaStack allowEmptyNavigation is true. +// includeStructuralAttrs and includeEmptyNodes are two flags specifically for reaching and +// returning data needed for entities including the element with attributes +// and empty elements like `` meant to blank out certain entity properties. +// +// leaving this old comment here (the second use of this for entities didn't need to do this, +// but the 3rd use might!) --- +// !!! !!! WARNING WARNING: // if you are reading this thinking to use it elsewhere, you'll almost certainly // need to work out a sensible way to flag the SchemaStack allowEmptyNavigation boolean // to false for whatever you are doing. -// -// actually this is also used to parse entity data out of submissions, a scenario -// in which we want to capture potentially empty nodes like that might -// mean the property should be set to blank. includeEmptyNodes allows that instead -// of skipping over outputting empty nodes. i think this is different from what the -// note above is talking about... -// allowEmptyNavigation and includeStructuralAttrs are already true. const submissionXmlToFieldStream = (fields, xml, includeStructuralAttrs = false, includeEmptyNodes = false) => { const outStream = new Readable({ objectMode: true, read: noop }); diff --git a/test/unit/data/submission.js b/test/unit/data/submission.js index 210297407..449894508 100644 --- a/test/unit/data/submission.js +++ b/test/unit/data/submission.js @@ -1,4 +1,4 @@ -require('should'); +const should = require('should'); const appRoot = require('app-root-path'); const { filter } = require('ramda'); const { toObjects } = require('streamtest').v2; @@ -57,6 +57,71 @@ describe('submission field streamer', () => { stream.on('end', done); // not hanging/timing out is the assertion here }); }); + + describe('entity flags includeStructuralAttrs and includeEmptyNodes', () => { + beforeEach(() => { + should.config.checkProtoEql = false; + }); + afterEach(() => { + should.config.checkProtoEql = true; + }); + + it('should include structural fields', (done) => { + fieldsFor(testData.forms.simpleEntity).then((fields) => + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, true).pipe(toObjects((error, result) => { + result.should.eql([ + { field: new MockField({ order: 4, name: 'entity', path: '/meta/entity', type: 'structure', attrs: { + create: '1', + dataset: 'people', + id: 'uuid:12345678-1234-4123-8234-123456789abc' + } }), text: null }, + { 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: '88' }, + { field: new MockField({ order: 2, name: 'hometown', path: '/hometown', type: 'string' }), text: 'Chicago' } + ]); + done(); + }))); + }); + + it('should not include structural fields', (done) => { + fieldsFor(testData.forms.simpleEntity).then((fields) => + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one, 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' }, + { field: new MockField({ order: 1, name: 'age', path: '/age', type: 'int', propertyName: 'age' }), text: '88' }, + { field: new MockField({ order: 2, name: 'hometown', path: '/hometown', type: 'string' }), text: 'Chicago' } + ]); + done(); + }))); + }); + + it('should include empty nodes if specified in fields', (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(); + }))); + }); + + it('should not include empty nodes', (done) => { + fieldsFor(testData.forms.simpleEntity).then((fields) => + submissionXmlToFieldStream(fields, testData.instances.simpleEntity.one.replace('88', ''), 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' }, + { field: new MockField({ order: 2, name: 'hometown', path: '/hometown', type: 'string' }), text: 'Chicago' } + ]); + done(); + }))); + }); + }); }); describe('getSelectMultipleResponses', () => {