open-vault/ui/tests/unit/decorators/model-validations-test.js
Jordan Reimer efe31ae32e
Model Validation Warnings (#19913)
* updates model validations to support warnings and adds alert to form field

* adds changelog entry

* updates model validations tests
2023-04-03 15:24:58 -06:00

137 lines
4.1 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { withModelValidations } from 'vault/decorators/model-validations';
import validators from 'vault/utils/validators';
import sinon from 'sinon';
import Model from '@ember-data/model';
// create class using decorator
const createClass = (validations) => {
@withModelValidations(validations)
class Foo extends Model {}
const foo = Foo.extend({
modelName: 'bar',
foo: null,
integer: null,
});
return new foo();
};
module('Unit | Decorators | ModelValidations', function (hooks) {
setupTest(hooks);
hooks.beforeEach(function () {
this.spy = sinon.spy(console, 'error');
});
hooks.afterEach(function () {
this.spy.restore();
});
test('it should throw error when validations object is not provided', function (assert) {
assert.expect(1);
try {
createClass();
} catch (e) {
assert.strictEqual(e.message, 'Validations object must be provided to constructor for setup');
}
});
test('it should log error to console when validations are not passed as array', function (assert) {
const validations = {
foo: { type: 'presence', message: 'Foo is required' },
};
const fooClass = createClass(validations);
fooClass.validate();
const message = 'Must provide validations as an array for property "foo" on bar model';
assert.ok(this.spy.calledWith(message));
});
test('it should log error for incorrect validator type', function (assert) {
const validations = {
foo: [{ type: 'bar', message: 'Foo is bar' }],
};
const fooClass = createClass(validations);
fooClass.validate();
const message = `Validator type: "bar" not found. Available validators: ${Object.keys(validators).join(
', '
)}`;
assert.ok(this.spy.calledWith(message));
});
test('it should validate', function (assert) {
const message = 'This field is required';
const validations = {
foo: [{ type: 'presence', message }],
};
const fooClass = createClass(validations);
const v1 = fooClass.validate();
assert.false(v1.isValid, 'isValid state is correct when errors exist');
assert.deepEqual(
v1.state,
{ foo: { isValid: false, errors: [message], warnings: [] } },
'Correct state returned when property is invalid'
);
fooClass.foo = true;
const v2 = fooClass.validate();
assert.true(v2.isValid, 'isValid state is correct when no errors exist');
assert.deepEqual(
v2.state,
{ foo: { isValid: true, errors: [], warnings: [] } },
'Correct state returned when property is valid'
);
});
test('invalid form message has correct error count', function (assert) {
const message = 'This field is required';
const messageII = 'This field must be a number';
const validations = {
foo: [{ type: 'presence', message }],
integer: [{ type: 'number', messageII }],
};
const fooClass = createClass(validations);
const v1 = fooClass.validate();
assert.strictEqual(
v1.invalidFormMessage,
'There are 2 errors with this form.',
'error message says form as 2 errors'
);
fooClass.integer = 9;
const v2 = fooClass.validate();
assert.strictEqual(
v2.invalidFormMessage,
'There is an error with this form.',
'error message says form has an error'
);
fooClass.foo = true;
const v3 = fooClass.validate();
assert.strictEqual(v3.invalidFormMessage, null, 'invalidFormMessage is null when form is valid');
});
test('it should validate warnings', function (assert) {
const message = 'Value contains whitespace.';
const validations = {
foo: [
{
type: 'containsWhiteSpace',
message,
level: 'warn',
},
],
};
const fooClass = createClass(validations);
fooClass.foo = 'foo bar';
const { state, isValid } = fooClass.validate();
assert.true(isValid, 'Model is considered valid when there are only warnings');
assert.strictEqual(state.foo.warnings.join(' '), message, 'Warnings are returned');
});
});