Testing MongooseJs Validations - unit-testing

Does anyone know how to test Mongoose Validations?
Example, I have the following Schema (as an example):
var UserAccount = new Schema({
user_name : { type: String, required: true, lowercase: true, trim: true, index: { unique: true }, validate: [ validateEmail, "Email is not a valid email."] },
password : { type: String, required: true },
date_created : { type: Date, required: true, default: Date.now }
});
The validateEmail method is defined as such:
// Email Validator
function validateEmail (val) {
return /^[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(val);
}
I want to test the validations. The end result is that I want to be able to test the validations and depending on those things happening I can then write other tests which test the interactions between those pieces of code. Example: User attempts to sign up with the same username as one that is taken (email already in use). I need a test that I can actually intercept or see that the validation is working WITHOUT hitting the DB. I do NOT want to hit Mongo during these tests. These should be UNIT tests NOT integration tests. :)
Thanks!

I had the same problem recently.
First off I would recommend testing the validators on their own. Just move them to a separate file and export the validation functions that you have.
This easily allows your models to be split into separate files because you can share these validators across different models.
Here is an example of testing the validators on their own:
// validators.js
exports.validatePresenceOf = function(value){ ... }
exports.validateEmail = function(value){ ... }
Here is a sample test for this (using mocha+should):
// validators.tests.js
var validator = require('./validators')
// Example test
describe("validateEmail", function(){
it("should return false when invalid email", function(){
validator.validateEmail("asdsa").should.equal(false)
})
})
Now for the harder part :)
To test your models being valid without accessing the database there is a validate function that can be called directly on your model.
Here is an example of how I currently do it:
describe("validating user", function(){
it("should have errors when email is invalid", function(){
var user = new User();
user.email = "bad email!!"
user.validate(function(err){
err.errors.email.type.should.equal("Email is invalid")
})
})
it("should have no errors when email is valid", function(){
var user = new User();
user.email = "test123#email.com"
user.validate(function(err){
assert.equal(err, null)
})
})
})
The validator callback gets an error object back that looks something like this:
{ message: 'Validation failed',
name: 'ValidationError',
errors:
{ email:
{ message: 'Validator "Email is invalid" failed for path email',
name: 'ValidatorError',
path: 'email',
type: 'Email is invalid'
}
}
}
I'm still new to nodeJS and mongoose but this is how I'm testing my models + validators and it seems to be working out pretty well so far.

You should use validate() method as a promise and test it with a tool that makes asserts for async stuff (ex: Chai as Promised).
First of all, require a promise library and switch out to the promise provider (for example Q):
mongoose.Promise = require('q').Promise;
Afterwards just, use asserts about promises:
it('should show errors on wrong email', function() {
user = new UserModel({
email: 'wrong email adress'
});
return expect(user.validate()).to.be.rejected;
});
it('should not show errors on valid email adress', function() {
user = new UserModel({
email: 'test#test.io'
});
return expect(user.validate()).to.be.fulfilled;
});

Related

Unit testing a Vue 3 component that uses a ref for custom Yup validation message

I am using Vue 3 with the composition API, as well as Typescript. In <script setup lang="ts"> I am using Yup to validate the email and password fields for a user login form. This code looks like this:
yup.object({
email: yup.string().required(text.value.emailValidation).email(),
password: yup.string().required(text.value.passwordValidation),
})
Here text is:
const text = useLanguage('loginText')
useLanguage is a composable that returns a ref whose value is determined by whether English or Spanish is toggled as the interface language. If the chosen language in the store is English, loginText is:
{
emailValidation: 'Please enter a valid email address',
passwordValidation: 'Please enter a password',
},
If the chosen language is Spanish, the loginText object has the same keys, but values in Spanish language.
In order to access the appropriate text in the yup strings, I need to use text.value.
Here is the Jest unit test I started to test this component:
import { mount } from '#vue/test-utils'
import { createTestingPinia } from '#pinia/testing'
import LoginView from '#/components/LoginView.vue'
import useLanguage from '#/composables/useLanguage'
jest.mock('#/composables/useLanguage')
;(useLanguage as any).mockReturnValue({
emailValidation: 'emailValidation',
passwordValidation: 'passwordValidation',
})
const globals = {
global: {
plugins: [
createTestingPinia({
initialState: { language: { language: 'English' } },
}),
],
},
}
describe('LoginViewForm', () => {
it('LoginView form renders correctly', () => {
const wrapper = mount(LoginView, {
...globals,
})
expect(wrapper.exists()).toBe(true)
})
})
I get the following error when running this simple test:
TypeError: Cannot read properties of undefined (reading 'emailValidation')
yup.object({
email: yup.string().required(text.value.emailValidation).email(),
^
password: yup.string().required(text.value.passwordValidation),
})
If I remove value from text.value the test passes but the required text doesn't render. How can I fix this test so that I don't get this error?

Ember-data peekRecord returns null [duplicate]

A lot of the other posts on this topic are 2+ years old, so here goes a potentially simple question.
I am using Ember data relationships to have a 'bizinfo' record belong to a 'user' record. Seems simple, but I am having the worst time of it.
In app/models/bizinfo.js I have the line:
'ownedBy': DS.belongsTo('user')
And in my route, where I validate and then save the model, I have the following code:
user_id: Ember.computed(function(){
return `${this.get('session.data.authenticated.user_id')}`;
}),
user: Ember.computed(function(){
return this.store.findRecord('user', this.get('user_id'));
}),
model(params){
return this.store.createRecord('bizinfo', {'ownedBy': this.get('user')});
},
at this point if I go into the Ember inspector to look at the 'bizinfo' data object, I see the following under the belongsTo tab:
ownedBy : <(subclass of Ember.ObjectProxy):ember1053>
Here is the code from my submit action:
submit() {
let model = this.currentModel;
console.log(model.ownedBy);
console.log(`what does the model look like?`);
console.log(model.toJSON());
model.validate().then(({model, validations}) => {
if (validations.get('isValid')) {
this.setProperties({
showAlert: false,
isRegistered: true,
showCode: false
});
let success = (response) => {
console.log(`Server responded with ${response.toJSON()}`);
};
let failure = (response) => {
console.log(`Server responded with ${response}`);
};
model.save().then(success, failure);
} else {
this.set('showAlert', true);
}
this.set('didValidate', true);
}, (errors) => {
console.log(`errors from failed validation: ${errors}`);
});
},
So here is the result of the first console.log statement:
ComputedProperty {isDescriptor: true, _dependentKeys: undefined, _suspended: undefined, _meta: Object, _volatile: false…}
And when I look at the model.toJSON() log, I see
ownedBy: null
Can anyone see what's going wrong here? Is it the create record statement? I have tried a lot of different permutations (such as submitting just the id as the 'user' parameter.
findRecord will return a promise. A simple way to get around the issue is
model(params){
return this.store.findRecord('user', this.get('user_id')) .
then(ownedBy => this.store.createRecord('bizinfo', {ownedBy});
}
This will wait for the findRecord to resolve, then return a new record with the resolved value as the ownedBy property.

Ember data dependent keys undefined

A lot of the other posts on this topic are 2+ years old, so here goes a potentially simple question.
I am using Ember data relationships to have a 'bizinfo' record belong to a 'user' record. Seems simple, but I am having the worst time of it.
In app/models/bizinfo.js I have the line:
'ownedBy': DS.belongsTo('user')
And in my route, where I validate and then save the model, I have the following code:
user_id: Ember.computed(function(){
return `${this.get('session.data.authenticated.user_id')}`;
}),
user: Ember.computed(function(){
return this.store.findRecord('user', this.get('user_id'));
}),
model(params){
return this.store.createRecord('bizinfo', {'ownedBy': this.get('user')});
},
at this point if I go into the Ember inspector to look at the 'bizinfo' data object, I see the following under the belongsTo tab:
ownedBy : <(subclass of Ember.ObjectProxy):ember1053>
Here is the code from my submit action:
submit() {
let model = this.currentModel;
console.log(model.ownedBy);
console.log(`what does the model look like?`);
console.log(model.toJSON());
model.validate().then(({model, validations}) => {
if (validations.get('isValid')) {
this.setProperties({
showAlert: false,
isRegistered: true,
showCode: false
});
let success = (response) => {
console.log(`Server responded with ${response.toJSON()}`);
};
let failure = (response) => {
console.log(`Server responded with ${response}`);
};
model.save().then(success, failure);
} else {
this.set('showAlert', true);
}
this.set('didValidate', true);
}, (errors) => {
console.log(`errors from failed validation: ${errors}`);
});
},
So here is the result of the first console.log statement:
ComputedProperty {isDescriptor: true, _dependentKeys: undefined, _suspended: undefined, _meta: Object, _volatile: false…}
And when I look at the model.toJSON() log, I see
ownedBy: null
Can anyone see what's going wrong here? Is it the create record statement? I have tried a lot of different permutations (such as submitting just the id as the 'user' parameter.
findRecord will return a promise. A simple way to get around the issue is
model(params){
return this.store.findRecord('user', this.get('user_id')) .
then(ownedBy => this.store.createRecord('bizinfo', {ownedBy});
}
This will wait for the findRecord to resolve, then return a new record with the resolved value as the ownedBy property.

how do i use should with mocha and mongoose?

I keep getting an error in the save() method when I run the test.
var User = require('../../models/user')
, should = require('should');
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User({
username : 'User1'
, email : 'user1#example.com'
, password : 'foo'
});
user.save(function(err, user){
if (err) throw err;
it('should have a username', function(done){
user.should.have.property('username', 'User1');
done();
});
});
})
})
})
here is the error:
$ mocha test/unit/user.js
․
✖ 1 of 1 test failed:
1) User #save() should save without error:
Error: timeout of 2000ms exceeded
at Object.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:1
61:14)
at Timer.list.ontimeout (timers.js:101:19)
You can nest describes but not it tests. Each test is meant to be stand alone so when you are looking through your results you can see where it is failing - on the save or not having the username property. For example in your code above there is no way for it to fail the 'should save without error' test as there is no done(). Which is also the reason the code above is timing out: mocha cannot find the done() for the 'should save without error' test.
Being able to nest describes is very powerful though. Within each describe you can have a before, beforeEach, after and afterEach statement. With these you can achieve the nesting that you are attempting above. See the mocha docs for more information if you want to read up on these statements.
The way I would write what you are trying to achieve is as follows:
var User = require('../../models/user')
, should = require('should')
// this allows you to access fakeUser from each test
, fakeUser;
describe('User', function(){
beforeEach(function(done){
fakeUser = {
username : 'User1'
, email : 'user1#example.com'
, password : 'foo'
}
// this cleans out your database before each test
User.remove(done);
});
describe('#save()', function(){
var user;
// you can use beforeEach in each nested describe
beforeEach(function(done){
user = new User(fakeUser);
done();
}
// you are testing for errors when checking for properties
// no need for explicit save test
it('should have username property', function(done){
user.save(function(err, user){
// dont do this: if (err) throw err; - use a test
should.not.exist(err);
user.should.have.property('username', 'User1');
done();
});
});
// now try a negative test
it('should not save if username is not present', function(done){
user.username = '';
user.save(function(err, user){
should.exist(err);
should.not.exist(user.username);
done();
});
});
});
});

Emberjs and Validation

How are people handling client side validation and ember?
Is there anything out of the box or a plugin that handles validation or are people just rolling their own?
https://github.com/dockyard/ember-validations might be useful. It also hooks up to Ember-easy-form
I would extend Ember.TextField (or whatever input type your validating) and use classBinding with a computed property. Here is the sample: http://jsfiddle.net/caligoanimus/7UNRd/
template:
<script type="text/x-handlebars" >
{{view App.AlphaNumField
placeholder="alpha-numeric data only"
valueBinding="App.alphaNumInput"}}
</script>
application:
App = Ember.Application.create({
AlphaNumField: Ember.TextField.extend({
isValid: function() {
return /^[a-z0-9]+$/i.test(this.get('value'));
}.property('value'),
classNameBindings: 'isValid:valid:invalid'
})
});
Another fully supported option and very logical if you are using bootstrap is to use bootstrap-validation plugin. In ember (ember-cli) this should be installed using bower:
bower install --save bootstrap-validation
then in ember-cli-build you must import dependencies:
//bootstrap-validator
app.import('bower_components/bootstrap-validator/dist/validator.js');
app.import('bower_components/bootstrap-validator/dist/validator.min.js');
This solution allows you to validate at html level, letting bootstrap do the 'dirty' job. For standard validations this will do the job simple and effortless.
I have been handling it in a very similar way to #caligoanimus, but validating on the focus out of the text box and appending an error message.
code:
App.TextFieldEmpty = Ember.TextField.extend({
focusOut: function() {
var valid = this.get('value') ? valid = true : valid = false;
this.$().next(".err").remove();
if(!valid){
this.$().addClass("invalid").after("<span class='err'>This field is required</span>");
} else {
this.$().removeClass("invalid")
}
}
});
Template:
<script type="text/x-handlebars">
{{view App.TextFieldEmpty}}
</script>
JSBIN:
http://jsbin.com/uriroYO/6/edit?html,js,output
I've had a lot of success with jQuery Validate:
App.MyView = Ember.View.extend({
templateName: 'my-form-template',
didInsertElement: function(){
$("#myForm").validate({
rules:{
fname:{
required: true,
maxlength: 50,
},
lname:{
required: true,
maxlength: 50,
},
email: {
required: true,
email: true,
maxlength: 200,
},
},
messages: {
email: {
email: "Enter a valid email address.",
},
},
});
}
});
Just using the Ember input helper, it's made my form validation very clean. You can take your jQuery Validate script and place it in a .js file as a function and just call that on didInsertElement.
jQuery Validate adds error messages below your fields with the message relating to the rule, and also allows you to trigger validation from any of your actions or events through the .valid() method.
We have created our own text fields which raise validation errors on focus out, and other events and other text fields extend them:
App.PhoneNumberField = App.TextField.extend({
validate: function(value) {
var self = this.$('input');
var id = self.attr("id");
var e164PhoneNumber = formatE164("AU",value);
var valid = true;
if(self.val().trim().length == 0 ){
valid = true;
}else{
valid = isValidNumber(e164PhoneNumber);
}
if (!valid) {
self.trigger(Storm.invalidInputEvent(id));
this.setErrorMessage("error","Phone Number does not look right");
}else {
self.trigger(Storm.validInputEvent(id));
this.clearMessages();
}
},
keyUp: function(evt) {
if(evt.keyCode >= 37 && evt.keyCode <=40)
{
return;
}
var textValue = this.$("input").val();
var input = this.$().find('input');
var formattedNumber = this.formatInput(textValue);
input.val(formattedNumber);
this.set('data',formattedNumber);
},
value: function() {
var phoneNumber = this.get('data');
if (phoneNumber) {
return phoneNumber;
} else {
return "";
}
}.property('data'),
data: null,
placeholder: function() {
return "";
}.property('placeholder'),
formatInput: function(textValue){
var formattedPhoneNumber = formatLocal("AU",textValue);
return formattedPhoneNumber;
}
});
I would use a model / persistance layer which uses a conventional "errors" object to save validation errors on the model.
Since Ember shines when it comes to observing changes, I would observe the changing errors object to determine whether or not should there be shown a validation message.
In my current setup I'm using Tower.js as framework, because it uses Ember as the View layer, and has a strong model / persistance layer. This layer allows me to define validations on model level. Each time I try to persist a model, it is validated and an error is thrown. In my views, this error aborts the "ideal" path and does not keep executing the workflow, instead it renders the validation errors in the template.