Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fio-8316 invalid data submitted in nested form #94

Merged
merged 8 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.DS_Store
.vscode
node_modules
docs
lib
dist
.dccache
# ignore nyc output
.nyc_output
coverage
23 changes: 21 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"./dist/formio.core.min.js": "./dist/formio.core.min.js"
},
"scripts": {
"test": "TEST=1 mocha -r ts-node/register -r tsconfig-paths/register -r mock-local-storage -r jsdom-global/register -b -t 0 'src/**/__tests__/*.test.ts'",
"test": "TEST=1 nyc --reporter=lcov --reporter=text --reporter=text-summary mocha -r ts-node/register -r tsconfig-paths/register -r mock-local-storage -r jsdom-global/register -t 0 'src/**/__tests__/*.test.ts'",
Copy link
Contributor Author

@johnformio johnformio May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will run the test through the code coverage. It creates an HTML report to look at manually and file coverage and summary reports in the console.

I also removed the bail flag so all tests run. Not sure if that will cause and issue downstream or not.

"lib": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
"replace": "node -r tsconfig-paths/register -r ts-node/register ./lib/base/array/ArrayComponent.js",
"test:debug": "mocha -r ts-node/register -r tsconfig-paths/register -r mock-local-storage -r jsdom-global/register --debug-brk --inspect '**/*.spec.ts'",
Expand Down Expand Up @@ -72,6 +72,7 @@
"mocha": "^10.0.0",
"mocha-jsdom": "^2.0.0",
"mock-local-storage": "^1.1.20",
"nyc": "^15.1.0",
"power-assert": "^1.6.1",
"sinon": "^17.0.1",
"ts-loader": "^9.5.0",
Expand All @@ -97,5 +98,23 @@
"json-logic-js": "^2.0.2",
"lodash": "^4.17.21",
"moment": "^2.29.4"
},
"nyc": {
"check-coverage": true,
"statements": 62,
"branches": 52,
"functions": 57,
"lines": 60,
"include": [
"src/**/*.ts",
"src/**/*.js"
],
"exclude": [
"src/**/*.test.ts",
"src/**/__tests__/",
"src/experimental/**/*.ts",
"src/types/**/*.ts"
],
"all": true
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code coverage configuration. Some of the exclusions should be reviewed. the coverage thresholds are based on current value based on the entire project.

}
}
65 changes: 65 additions & 0 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,72 @@ describe('Process Tests', () => {
processSync(context);
assert.equal(context.scope.errors.length, 0);
});
it('should remove submission data not in a nested form definition', async function () {
const form = {
_id: {},
title: 'parent',
name: 'parent',
type: 'form',
components: [
{
type: "checkbox",
label: "A",
key: "A",
input: true,
},
{
type: "checkbox",
label: "B",
key: "B",
input: true,
},
{
key: 'child',
label: 'child',
form: 'child form',
type: 'form',
input: true,
reference: false,
clearOnHide: false,
components: [
{
label: "Input",
key: 'input',
type: 'textfield',
input: true
}
]
}
]
}
const submission = {
data: {
A: true,
B: true,
child: {
data: {
input: 'test',
invalid: 'invalid submission data'
}
}
}
}
const context = {
form,
submission,
data: submission.data,
components: form.components,
processors: ProcessTargets.submission,
scope: {},
config: {
server: true
}
};
processSync(context);
expect(context.data.child.data).to.not.have.property('invalid');


})
it('Should process nested form data correctly', async () => {
const submission = {
data: {
Expand Down
20 changes: 10 additions & 10 deletions src/process/filter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const filterProcessSync: ProcessorFnSync<FilterScope> = (context: FilterC
scope.filter[absolutePath] = {
compModelType: modelType,
include: true,
value: {data: {}}
value: { data: {} }
};
break;
case 'array':
Expand Down Expand Up @@ -47,19 +47,19 @@ export const filterProcess: ProcessorFn<FilterScope> = async (context: FilterCon
};

export const filterPostProcess: ProcessorFnSync<FilterScope> = (context: FilterContext) => {

const { scope, submission } = context;
const filtered = {};
for (const path in scope.filter) {
if (scope.filter[path].include) {
let value = get(submission?.data, path);
if (isObject(value) && isObject(scope.filter[path].value)) {
if (scope.filter[path].compModelType === 'dataObject') {
value = {...value, ...scope.filter[path].value, data: (value as any)?.data}
} else {
value = {...value, ...scope.filter[path].value}
}
const pathFilter = scope.filter[path];
if (pathFilter) {
let value = get(submission?.data, path) as any;

// dataObject types (nested form) paths are recursively added to the scope.filter
// excluding those from this and setting their components onto the submission directly
if (pathFilter.compModelType !== 'dataObject') {
set(filtered, path, value);
}
set(filtered, path, value);
}
}
context.data = filtered;
Expand Down
26 changes: 16 additions & 10 deletions src/process/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,24 @@ import { clearHiddenProcessInfo } from "./clearHidden";

export async function process<ProcessScope>(context: ProcessContext<ProcessScope>): Promise<ProcessScope> {
const { instances, components, data, scope, flat, processors } = context;


await eachComponentDataAsync(components, data, async (component, compData, row, path, components, index) => {
// Skip processing if row is null or undefined
if (!row) {
return;
}
await processOne<ProcessScope>({...context, ...{
data: compData,
component,
components,
path,
row,
index,
instance: instances ? instances[path] : undefined
}});
await processOne<ProcessScope>({
...context, ...{
data: compData,
component,
components,
path,
row,
index,
instance: instances ? instances[path] : undefined
}
});
if (flat) {
return true;
}
Expand All @@ -49,12 +53,14 @@ export async function process<ProcessScope>(context: ProcessContext<ProcessScope

export function processSync<ProcessScope>(context: ProcessContext<ProcessScope>): ProcessScope {
const { instances, components, data, scope, flat, processors } = context;

eachComponentData(components, data, (component, compData, row, path, components, index) => {
// Skip processing if row is null or undefined
if (!row) {
return;
}
processOneSync<ProcessScope>({...context,
processOneSync<ProcessScope>({
...context,
data: compData,
component,
components,
Expand Down
Loading
Loading