我正在奥雷利亚项目中测试我的一个组件。我想在我的单元测试中访问我的组件的viewModel,但是到目前为止还没有任何进展。
我遵循了https://aurelia.io/docs/testing/components#manually-handling-lifecycle中可用的示例,但我一直得到component.viewModel
is undefined
。
下面是单元测试:
describe.only('some basic tests', function() {
let component, user;
before(() => {
user = new User({ id: 100, first_name: "Bob", last_name: "Schmoe", email: 'joe@schmoe.com'});
user.save();
});
beforeEach( () => {
component = StageComponent
.withResources('modules/users/user')
.inView('<user></user>')
.boundTo( user );
});
it('check for ', () => {
return component.create(bootstrap)
.then(() => {
expect(2).to.equal(2);
return component.viewModel.activate({user: user});
});
});
it('can manually handle lifecycle', () => {
return component.manuallyHandleLifecycle().create(bootstrap)
.then(() => component.bind({user: user}))
.then(() => component.attached())
.then(() => component.unbind() )
.then(() => {
expect(component.viewModel.name).toBe(null);
return Promise.resolve(true);
});
});
afterEach( () => {
component.dispose();
});
});
下面是我遇到的错误:
1) my aurelia tests
can manually handle lifecycle:
TypeError: Cannot read property 'name' of undefined
这里是定义component
对象上的viewModel
的行,但前提是设置了aurelia.root.controllers.length
。我不知道如何在我的aurelia代码中设置控制器,或者我是否需要这样做。
我想我的问题是:如何在单元测试中访问组件的viewModel?
发布于 2018-10-26 21:49:54
为了让它发挥作用,我不得不使用Container
import { UserCard } from '../../src/modules/users/user-card';
import { Container } from 'aurelia-dependency-injection';
describe.only('some basic tests', function() {
let component, user;
before(() => {
user = new User({ id: 100, first_name: "Bob", last_name: "Schmoe", email: 'joe@schmoe.com'});
user.save();
});
beforeEach(() => {
container = new Container();
userCard = container.get( UserCard );
component = StageComponent
.withResources('modules/users/user-card')
.inView('<user-card></user-card>')
.boundTo( user );
});
it('check for ', () => {
return component.create(bootstrap)
.then(() => {
expect(2).to.equal(2);
return userCard.activate({user: user});
});
});
});
发布于 2018-10-25 13:53:47
编辑2:
我还想指出,你自己的答案基本上与我在评论中首次提出的解决办法相同。这相当于直接实例化视图模型,而不是验证组件是否实际工作。
编辑:
我在本地尝试了karma+webpack+mocha设置(因为webpack是当今最受欢迎的选择),要让它正常工作有几个注意事项。我不知道你的设置的其他部分是什么,所以我不能准确地告诉你错误在哪里(如果你告诉我更多关于你的设置,我可能会指出这一点)。
无论如何,下面是一个使用karma+webpack+mocha正确验证绑定和呈现的工作设置:
https://github.com/fkleuver/aurelia-karma-webpack-testing
测试代码:
import './setup';
import { Greeter } from './../src/greeter';
import { bootstrap } from 'aurelia-bootstrapper';
import { StageComponent, ComponentTester } from 'aurelia-testing';
import { PLATFORM } from 'aurelia-framework';
import { assert } from 'chai';
describe('Greeter', () => {
let el: HTMLElement;
let tester: ComponentTester;
let sut: Greeter;
beforeEach(async () => {
tester = StageComponent
.withResources(PLATFORM.moduleName('greeter'))
.inView(`<greeter name.bind="name"></greeter>`)
.manuallyHandleLifecycle();
await tester.create(bootstrap);
el = <HTMLElement>tester.element;
sut = tester.viewModel;
});
it('binds correctly', async () => {
await tester.bind({ name: 'Bob' });
assert.equal(sut.name, 'Bob');
});
it('renders correctly', async () => {
await tester.bind({ name: 'Bob' });
await tester.attached();
assert.equal(el.innerText.trim(), 'Hello, Bob!');
});
});
greeter.html
<template>
Hello, ${name}!
</template>
greeter.ts
import { bindable } from 'aurelia-framework';
export class Greeter {
@bindable()
public name: string;
}
setup.ts
import 'aurelia-polyfills';
import 'aurelia-loader-webpack';
import { initialize } from 'aurelia-pal-browser';
initialize();
karma.conf.js
const { AureliaPlugin } = require('aurelia-webpack-plugin');
const { resolve } = require('path');
module.exports = function configure(config) {
const options = {
frameworks: ['source-map-support', 'mocha'],
files: ['test/**/*.ts'],
preprocessors: { ['test/**/*.ts']: ['webpack', 'sourcemap'] },
webpack: {
mode: 'development',
entry: { setup: './test/setup.ts' },
resolve: {
extensions: ['.ts', '.js'],
modules: [
resolve(__dirname, 'src'),
resolve(__dirname, 'node_modules')
]
},
devtool: 'inline-source-map',
module: {
rules: [{
test: /\.html$/i,
loader: 'html-loader'
}, {
test: /\.ts$/i,
loader: 'ts-loader',
exclude: /node_modules/
}]
},
plugins: [new AureliaPlugin()]
},
singleRun: false,
colors: true,
logLevel: config.browsers && config.browsers[0] === 'ChromeDebugging' ? config.LOG_DEBUG : config.LOG_INFO, // for troubleshooting mode
mime: { 'text/x-typescript': ['ts'] },
webpackMiddleware: { stats: 'errors-only' },
reporters: ['mocha'],
browsers: config.browsers || ['ChromeHeadless'],
customLaunchers: {
ChromeDebugging: {
base: 'Chrome',
flags: [ '--remote-debugging-port=9333' ]
}
}
};
config.set(options);
};
tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"importHelpers": true,
"lib": ["es2018", "dom"],
"module": "esnext",
"moduleResolution": "node",
"sourceMap": true,
"target": "es2018"
},
"include": ["src"]
}
package.json
{
"scripts": {
"test": "karma start --browsers=ChromeHeadless"
},
"dependencies": {
"aurelia-bootstrapper": "^2.3.0",
"aurelia-loader-webpack": "^2.2.1"
},
"devDependencies": {
"@types/chai": "^4.1.6",
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.0",
"aurelia-testing": "^1.0.0",
"aurelia-webpack-plugin": "^3.0.0",
"chai": "^4.2.0",
"html-loader": "^0.5.5",
"karma": "^3.1.1",
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-source-map-support": "^1.3.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^3.0.5",
"mocha": "^5.2.0",
"path": "^0.12.7",
"ts-loader": "^5.2.2",
"typescript": "^3.1.3",
"webpack": "^4.23.1",
"webpack-dev-server": "^3.1.10"
}
}
原始答案
如果您正在手动执行生命周期,则需要自己传递一个ViewModel,它可以绑定到:)
我不记得严格来说到底需要什么,所以我很确定会有一些冗余(例如,两个bindingContexts中的一个不应该是必需的)。但这是一个普遍的想法:
const view = "<div>${msg}</div>";
const bindingContext = { msg: "foo" };
StageComponent
.withResources(resources/*optional*/)
.inView(view)
.boundTo(bindingContext)
.manuallyHandleLifecycle()
.create(bootstrap)
.then(component => {
component.bind(bindingContext);
}
.then(component => {
component.attached();
}
.then(component => {
expect(component.host.textContent).toEqual("foo");
}
.then(component => {
bindingContext.msg = "bar";
}
.then(component => {
expect(component.host.textContent).toEqual("bar");
};
不用说,由于您自己创建了视图模型(本例中的变量bindingContext
),您可以简单地访问您声明的变量。
https://stackoverflow.com/questions/52975104
复制相似问题