如何在Karma测试中加载aurelia-validation插件而不是自定义元素

时间:2016-12-20 14:51:52

标签: validation unit-testing aurelia aurelia-validation

使用aurelia-validation@^1.0.0-beta.1.0.0“,

下面的帖子讨论了使用aurelia验证测试自定义元素,以便在测试时加载插件。我已经尝试了很多解决方案,但没有任何作用(可能是因为我没有使用自定义元素)。我不想使用自定义元素,因为视图模型涉及动态组合。在成功发布表单后,我将“谢谢”视图模型替换为清除所有内容并显示表单已提交。

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

当我将我的视图模型导入我的测试时,我在很多帖子中收到相同的回复:

Error: (SystemJS) Did you forget to add ".plugin('aurelia-validation)" to your main.js?

这是我的视图模型src的缩写版本,如果它有帮助,则测试...

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());
  });
});

更新

我可能会到达某个地方?我做了@MartinMason的建议并将ValidationRules移到了视图模型的ctor中,而不是使用.on(Candidate)我做了.on(this.candidate)。这允许我的测试运行,但我的employment视图模型的每个测试都失败并显示相同的消息Did you forget to add ".plugin('aurelia-validation)" to your main.js?。然后我在本文开头的github链接中添加了jremy建议的beforeAll,我收到了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

这里是Canidate.js全名来自

export default class {
  fullName = '';
  age = null;
  city = '';
  phone = '';
  email = '';
  experience = '';
}

因此,如果我将ValidationRules.ensure(a => a.fullname)更改为ValidationRules.ensure('fullName'),则错误消失(我想我需要在测试中添加ValidationParser?...还没有那么远,我只是希望先前的测试先通过)

更新

将我的测试修复为aurelia-validation帐后,他们再次通过。因此,将ValidationRules移动到ctor,然后将aurelia-testing个对象添加回beforeAll函数,这样就可以了。我仍然可以在.on(Canidate)中执行.on(this.canidate)而不是ValidationRules,并且测试/网站运行良好,但不确定实际测试验证规则时这会产生什么影响。我想如果杰瑞米能告诉我们这是不是正确的话,那仍然会很好。

1 个答案:

答案 0 :(得分:3)

我已经分叉了骨架项目并修改了skeleton-typescript-aspnetcore项目,以在integ_validation分支中包含aurelia-validation集成。 https://github.com/SoftwareMasons/skeleton-navigation/tree/integrate_validation当ValidationRules应用于类构造函数中的实例时,我可以通过jasmine测试。但是,当规则应用于类时,我永远无法正确调用静态ValidateRules.initialize方法,这就是为什么在aurelia-validation的assertInitialized方法中抛出错误的原因。

我已经包含了我试图在registionForm.spec.ts文件中使用的所有内容以及我尝试过的简短描述。希望我的失败能帮助你找到成功之路。目前,这是一个可接受的解决方案,但如果你找到更好的方法,我很感激你让我们知道。