我最近将一个lit web组件转换为Typescript,似乎无法弄清楚为什么我的测试现在失败了..在转换之前一切都工作正常。
这些是我的测试依赖项:
"@open-wc/testing": "^3.1.2",
"@web/dev-server-esbuild": "^0.2.16",
"@web/test-runner": "^0.13.27"
所以我在
"test": "web-test-runner",
中使用以下配置运行 web-test-runner.config.mjs
(使用 tsc 转译代码也遇到了相同的错误):
import { esbuildPlugin } from '@web/dev-server-esbuild';
const filteredLogs = ['Running in dev mode', 'Lit is in dev mode'];
export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
files: 'lib/**/*.test.ts',
nodeResolve: {
exportConditions: ['browser', 'development'],
},
plugins: [esbuildPlugin({ ts: true })],
filterBrowserLogs(log) {
for (const arg of log.args) {
if (typeof arg === 'string' && filteredLogs.some(l => arg.includes(l))) {
return false;
}
}
return true;
}
});
并收到此错误:
components: > web-test-runner
components: Chrome: |██████████████████████████████| 0/1 test files | 0 passed, 0 failed
components: Running tests...
lib/MyElement/index.test.ts:
components: ❌ MyElement > has a default title "World" and count 0
components: AssertionError: expected undefined to equal 'World'
components: at o.<anonymous> (lib/MyElement/index.test.ts:11:23)
components: Chrome: |██████████████████████████████| 1/1 test files | 0 passed, 1 failed
components: Finished running tests in 2.7s with 1 failed tests.
components: npm ERR! code ELIFECYCLE
components: npm ERR! errno 1
components: npm ERR! [email protected] test: `web-test-runner`
components: npm ERR! Exit status 1
components: npm ERR!
components: npm ERR! Failed at the [email protected] test script.
components: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
components: npm ERR! A complete log of this run can be found in:
components: npm ERR! /Users/shawn/.npm/_logs/2022-03-21T22_11_54_084Z-debug.log
lerna ERR! npm run test exited 1 in 'components'
这是组件代码:
import {LitElement, html, css} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
:host {
display: block;
border: solid 1px gray;
padding: 16px;
max-width: 800px;
}
`;
@property() name: string = 'World';
@state() count: number = 0;
_onClick() {
this.count++;
this.dispatchEvent(new CustomEvent('count-changed'));
}
sayHello(name: string) {
return `Hello, ${name}`;
}
render() {
return html`
<h1>${this.sayHello(this.name)}!</h1>
<button @click=${this._onClick} part="button">
Click Count: ${this.count}
</button>
<slot></slot>
`;
}
}
最后是测试代码:
import { html, fixture, expect } from '@open-wc/testing';
import { MyElement } from '.';
describe('MyElement', () => {
it('has a default title "World" and count 0', async () => {
const el = await fixture<MyElement>(html`
<my-element></my-element>
`);
expect(el.name).to.equal('World');
expect(el.count).to.equal(0);
});
});
所以我相信这与转译打字稿有关,但我还没有成功地找出它到底是什么。有人注意到任何错误会导致这些属性现在未定义吗?
编辑:
这是原始的 JS 实现,以显示它与 TS 之间的差异。
import {LitElement, html, css} from 'lit';
export class MyElement extends LitElement {
static get styles() {
return css`
:host {
display: block;
border: solid 1px gray;
padding: 16px;
max-width: 800px;
}
`;
}
static get properties() {
return {
name: {type: String},
count: {type: Number},
};
}
constructor() {
super();
this.name = 'World';
this.count = 0;
}
render() {
return html`
<h1>${this.sayHello(this.name)}!</h1>
<button @click=${this._onClick} part="button">
Click Count: ${this.count}
</button>
<slot></slot>
`;
}
_onClick() {
this.count++;
this.dispatchEvent(new CustomEvent('count-changed'));
}
sayHello(name) {
return `Hello, ${name}`;
}
}
window.customElements.define('my-element', MyElement);
问题是您在测试文件中没有使用
MyElement
的实例,而仅使用其类型和标签。因此编译过程会抛出 import 语句import { MyElement } from '.';
。如果您使用 tsc 编译测试文件,您会发现 .js
输出中缺少导入语句。
通过在测试中导入整个文件来修复它:
import './index.js';
注意: 在 lit-element-starter-ts 存储库的测试文件中(在 here 找到它),这种情况没有出现,因为他们在第一个测试用例中使用了 Element 的实例,因此名为 import不会被 tsc/esbuild 删除:
import {MyElement} from '../my-element.js';
// ...
test('is defined', () => {
const el = document.createElement('my-element');
assert.instanceOf(el, MyElement);
});