using aurelia-validation@^1.0.0-beta.1.0.0",
The posts below discuss testing a custom element with aurelia validation so the plugin is loaded during test time. I've tried many of the solutions, but nothing works (probably because i am not using a custom element). I do not want to use a custom element because the view-model is involved in dynamic composition. After the form is successfully posted i substitute a "thank you" view-model to clear everything out and show that the form was submitted.
How to load an Aurelia plugin in Karma
Load aurelia-validation plugin during Jasmine unit tests - with webpack
https://github.com/aurelia/validation/issues/377
I receive the same response in many of those posts when i import my view-model into my test:
Error: (SystemJS) Did you forget to add ".plugin('aurelia-validation)" to your main.js?
Here is an abbreviated version of my view-model src and test if it helps...
employment.html
<template>
<section class="au-animate">
<compose view.bind="view"></compose>
</section>
</template>
employment.js
import {inject} from 'aurelia-framework';
import {HttpClient, json} from 'aurelia-fetch-client';
import { sendto } from './env';
import Canidate from './canidate.js';
import 'fetch';
import { ValidationControllerFactory, ValidationRules } from 'aurelia-validation';
import {BootstrapFormRenderer} from './resources/renderers/bootstrap-form-renderer'
@inject(HttpClient, ValidationControllerFactory)
export class Employment {
constructor(http, controllerFactory) {
this.view = "./employment-form.html";
this.helpMsg = null
this.loading = false;
this.canidate = new Canidate();
this.controller = controllerFactory.createForCurrentScope();
this.controller.addRenderer(new BootstrapFormRenderer());
this._http = http;
}
submit() {
this.loading = true;
return this.controller.validate()
.then(result => {
if (result.isValid) {
return this._post();
}
})
.catch(error => {
this.canidate.error = error;
return this._post();
})
.then(() => this.loading = false);
}
_post() {
return this._http.fetch(sendto(), {
method: `POST`,
body: json(this.canidate)
}).then(response => response.json())
.then(() => {
this.helpMsg = null;
this.view = "./thanks.html";
}).catch(err => {
this.helpMsg = `there was an error submitting your form. ` +
`Please try again or contact us direct from the Contact Page`;
});
}
}
ValidationRules
.ensure(a => a.fullName).required()
.ensure(a => a.age).required()
.ensure(a => a.city).required()
.ensure(a => a.phone).required().matches(/\d{3}-\d{3}-\d{4}/)
.withMessage('Please format your phone number like ###-###-####')
.ensure(a => a.email).email()
.ensure(a => a.experience).required()
.on(Canidate);
employment.spec.js
import {Employment} from '../../src/employment';
import * as env from '../../src/env';
import Canidate from '../../src/canidate';
import {ValidationControllerFactory, ValidationController} from 'aurelia-validation';
import {StageComponent, ComponentTester} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper';
class HttpStub {
constructor() {
this.url = null;
this.config = null;
this.resolve = null;
this.reject = null;
}
fetch(url, blob) {
this.url = url;
this.blob = blob;
let promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
return promise;
}
configure(func) {
this.config = func;
}
}
describe('the Employment module', () => {
let sut;
let http;
let controller;
let component;
beforeAll(done => {
component = StageComponent.withResources().inView('<div></div>').boundTo({});
component.bootstrap(aurelia => aurelia.use.standardConfiguration().plugin('aurelia-validation'));
component.create(bootstrap).then(done);
});
afterAll(() => {
component.dispose();
});
beforeEach(() => {
const factory = jasmine.setupSpy('factory', ValidationControllerFactory.prototype);
controller = jasmine.setupSpy('controller', ValidationController.prototype);
http = new HttpStub();
factory.createForCurrentScope.and.returnValue(controller);
controller.validate.and.returnValue(Promise.resolve({valid: true}));
sut = new Employment(http, factory);
});
it('initiates the current view model variables', () => {
expect(sut.view).toEqual('./employment-form.html');
expect(sut.canidate).toEqual(new Canidate());
expect(sut.helpMsg).toEqual(null);
expect(sut.loading).toBeFalsy();
});
it('fetches with post data', done => {
const expectJson = '{"fullName":"tom","age":2,"city":"lex","phone":"1900",' +
'"email":"@.com",'"experience":"none"}';
sut.canidate.fullName = 'tom';
sut.canidate.age = 2;
sut.canidate.city = 'lex';
sut.canidate.phone = '1900';
sut.canidate.email = '@.com';
sut.canidate.experience = 'none';
spyOn(env, "sendto").and.returnValue('test');
http.itemStub = sut.canidate;
sut.submit().then(() => {
expect(http.url).toEqual('test');
expect(http.blob.method).toEqual('POST');
expect(sut.loading).toBeFalsy();
let fr = new FileReader();
fr.addEventListener('loadend', function() {
expect(fr.result).toEqual(expectJson);
done();
});
fr.readAsText(http.blob.body);
});
expect(sut.loading).toBeTruthy();
setTimeout(() => http.resolve({ json: () => sut.canidate }));
});
it('successfully posts the data', done => {
sut.submit().then(() => {
expect(sut.helpMsg).toEqual(null);
expect(sut.view).toEqual('./thanks.html');
done();
});
setTimeout(() => http.resolve({ json: () => {} }));
});
it('shows a help msg when posts fails', done => {
sut.submit().then(() => {
expect(sut.helpMsg).toContain('there was an error submitting your form');
expect(sut.view).toEqual('./employment-form.html');
done();
});
setTimeout(() => http.reject());
});
});
UPDATE
I might be getting somewhere? I did what @MartinMason suggested and moved my ValidationRules
into the ctor of the view-model and instead of using .on(Candidate)
i did .on(this.candidate)
. This allowed my tests to run, but every test for my employment
view-model failed with the same message Did you forget to add ".plugin('aurelia-validation)" to your main.js?
. Then I went to the github link at the beginning of this post and added in the beforeAll
that jeremy suggested and i received an error from what seems like the ValidationRules
.
Error: Unable to parse accessor function:
function (a) {
++cov_x4vangzdw.f[2];
++cov_x4vangzdw.s[10];
return a.fullName;
} (line 57)
getAccessorExpression
parseProperty
ensure
ensure
Employment
tryCatchReject@jspm_packages/system-polyfills.src.js:1188:34
runContinuation1@jspm_packages/system-polyfills.src.js:1147:18
when@jspm_packages/system-polyfills.src.js:935:20
run@jspm_packages/system-polyfills.src.js:826:17
_drain@jspm_packages/system-polyfills.src.js:102:22
drain@jspm_packages/system-polyfills.src.js:67:15
TypeError: undefined is not an object (evaluating 'sut.submit') (line 160)
tryCatchReject@jspm_packages/system-polyfills.src.js:1188:34
runContinuation1@jspm_packages/system-polyfills.src.js:1147:18
when@jspm_packages/system-polyfills.src.js:935:20
run@jspm_packages/system-polyfills.src.js:826:17
_drain@jspm_packages/system-polyfills.src.js:102:22
drain@jspm_packages/system-polyfills.src.js:67:15
and here is Canidate.js
where fullname is coming from
export default class {
fullName = '';
age = null;
city = '';
phone = '';
email = '';
experience = '';
}
So if i change ValidationRules.ensure(a => a.fullname)
to ValidationRules.ensure('fullName')
the error goes away (I guess I need to add the ValidationParser
in the test?...haven't gotten that far yet, I just want my prior tests to pass first)
UPDATE
After fixing my tests to account for aurelia-validation
they are passing again. So moving the ValidationRules
to the ctor and then adding the aurelia-testing
objects back into the beforeAll
function made it work. I can still do .on(Canidate)
instead of .on(this.canidate)
in the ValidationRules
and the tests/site run well, but not sure the impact this will have when actually testing the validation rules. I guess it would still be nice if jeremy can let us know if this is the correct.
employment.js
view-model. I have tried many things not shown that in those links i reference in the post, some of which you suggest like bootstrapping withComponentTester
to add the plugin in abeforeAll
. I also tried a globalbeforeEach
– jmzagorskiskeleton-esnext
and adding the two files above andaurelia-validation
fromjspm
. In theemployment
view-model i took out everything except theValidationControllerFactory
call in the ctor and theValidationRules
. In the test file i just left the first test. The tests ran fine when I initially cloned the repo, but then failed when i performed the above steps. – jmzagorski