Skip to content

Commit

Permalink
[New] fields/forms .validate(): add Promise-accepting variant
Browse files Browse the repository at this point in the history
+ validatePastFirstError is respected
+ field.validate() now always returns an error and that is tested
  • Loading branch information
voxpelli authored and ljharb committed Mar 13, 2024
1 parent 2922dc3 commit 066f70a
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 4 deletions.
25 changes: 24 additions & 1 deletion lib/fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,28 @@ exports.string = function (options) {
var b = assign({}, f); // clone field object:
b.value = raw_data;
b.data = b.parse(raw_data);
b.validate = function (form, callback) {
b.validate = function (form, rawCallback) {
var callback = rawCallback;
var returnValue;

if (!callback) {
if (typeof Promise !== 'function') {
throw new Error('Callback is required when Promises are unsupported');
}
returnValue = new Promise(function (resolve) {
callback = function (err, bound_field) {
if (err) {
resolve({
error: true,
message: err,
field: bound_field
});
} else {
resolve({ error: false });
}
};
});
}
var forceValidation = some(b.validators || [], function (validator) {
return validator.forceValidation;
});
Expand Down Expand Up @@ -61,6 +82,8 @@ exports.string = function (options) {
callback(err, b);
});
}

return returnValue;
};
return b;
};
Expand Down
22 changes: 22 additions & 0 deletions lib/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ exports.create = function (fields, options) {
}, {});
b.validate = function () {
var callback = arguments.length > 1 ? arguments[1] : arguments[0];
var returnValue;

if (!callback) {
if (typeof Promise !== 'function') {
throw new Error('Callback is required when Promises are unsupported');
}
returnValue = new Promise(function (resolve) {
callback = function (err, form) {
if (form.isValid()) {
resolve({ error: false });
} else {
resolve({
error: true,
message: String(err || ''),
form: form
});
}
};
});
}

asyncForEach(keys(b.fields), function (k, asyncCallback) {
b.fields[k].validate(b, function (err, bound_field) {
Expand All @@ -58,6 +78,8 @@ exports.create = function (fields, options) {
}, function (err) {
callback(err, b);
});

return returnValue;
};
b.isValid = function () {
var form = this;
Expand Down
45 changes: 43 additions & 2 deletions test/test-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var testField = function (field) {
});

test(field + ' validate', function (t) {
t.plan(10);
t.plan(11);

var f = fields[field]({ label: 'test label' });
f.validators = [
Expand All @@ -79,6 +79,8 @@ var testField = function (field) {
return 'some data parsed';
};
f.bind('some data').validate('form', function (err, bound) {
t.equal(err, 'Error: validation error');

t.equal(bound.label, 'test label');
t.equal(bound.value, 'some data');
t.equal(bound.data, 'some data parsed');
Expand All @@ -88,6 +90,46 @@ var testField = function (field) {
});
});

test(field + ' promised validate', function (t) {
if (typeof Promise !== 'function') {
return t.end();
}

t.plan(13);

var f = fields[field]({ label: 'test label' });
f.validators = [
function (form, fieldObject, callback) {
t.equal(fieldObject.data, 'some data parsed');
t.equal(fieldObject.value, 'some data');
callback(null);
},
function (form, fieldObject, callback) {
t.equal(fieldObject.data, 'some data parsed');
t.equal(fieldObject.value, 'some data');
callback(new Error('validation error'));
}
];

f.parse = function (data) {
t.equal(data, 'some data');
return 'some data parsed';
};
return f.bind('some data').validate('form').then(function (result) {
t.ok(result, 'gets a result');
t.ok(result.error, 'is an error');
t.equal(result.message, 'Error: validation error');

var bound = result.field;

t.equal(bound.label, 'test label');
t.equal(bound.value, 'some data');
t.equal(bound.data, 'some data parsed');
t.equal(bound.error, 'Error: validation error');
t.notEqual(bound, f, 'bind returns a new field object');
});
});

test(field + ' validate multiple errors', function (t) {
t.plan(1);

Expand Down Expand Up @@ -144,7 +186,6 @@ var testField = function (field) {
t.equal(fieldObject.data, 'val');
t.notOk(fieldObject.error);
});
t.end();
});

test(field + ' validate no validators', function (t) {
Expand Down
41 changes: 40 additions & 1 deletion test/test-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test('bind with missing field in data keeps field in form', function (t) {
});

test('validate', function (t) {
t.plan(2 + 9);
t.plan(2 + 10);
var form = forms.create({
field1: forms.fields.string(),
field2: forms.fields.string({
Expand All @@ -81,6 +81,45 @@ test('validate', function (t) {
});
var data = { field1: 'data one', field2: 'data two' };
form.bind(data).validate(function (err, f) {
t.equal(err, 'validation error');

t.equal(f.fields.field1.value, 'data one');
t.equal(f.fields.field1.data, 'data one');
t.equal(f.fields.field1.error, undefined);
t.equal(f.fields.field2.value, 'data two');
t.equal(f.fields.field2.data, 'data two');
t.equal(f.fields.field2.error, 'validation error');

t.deepEqual(f.data, { field1: 'data one', field2: 'data two' });
t.notEqual(form, f, 'bind returns new form object');

t.notOk(f.isValid());
});
});

test('promised validate', function (t) {
if (typeof Promise !== 'function') {
return t.end();
}
t.plan(14);
var form = forms.create({
field1: forms.fields.string(),
field2: forms.fields.string({
validators: [function (formObject, field, callback) {
t.equal(field.data, 'data two');
t.equal(field.value, 'data two');
callback('validation error');
}]
})
});
var data = { field1: 'data one', field2: 'data two' };
return form.bind(data).validate().then(function (result) {
t.ok(result, 'gets a result');
t.ok(result.error, 'is an error');
t.equal(result.message, 'validation error');

var f = result.form;

t.equal(f.fields.field1.value, 'data one');
t.equal(f.fields.field1.data, 'data one');
t.equal(f.fields.field1.error, undefined);
Expand Down

0 comments on commit 066f70a

Please sign in to comment.