Polymer 1.x组件单元测试咨询:替代WCT方案及validate函数测试
关于Polymer 1.x组件测试的问题与解答
用户问题
我有一个编写在.html文件中的Polymer 1.x组件,代码如下:
<dom-module id="create-layout"> <template> <input role="widget" name="years" value="" autofocus required> </nuxeo-input> <input role="widget" name="months" value="" autofocus required> </nuxeo-input> <input role="widget" name="days" value="" autofocus required> </nuxeo-input> </template> <script> Polymer({ is: 'create-layout', properties: { document: Object, }, validate() { const years = this.shadowRoot.querySelector('input[name="years"]'); const months = this.shadowRoot.querySelector('input[name="months"]'); const days = this.shadowRoot.querySelector('input[name="days"]'); if (parseInt(years.value, 10) === 0 && parseInt(months.value, 10) === 0 && parseInt(days.value, 10) === 0) { years.invalid = true; months.invalid = true; days.invalid = true; return false; } return true; } }); </script> </dom-module>
我想为其中的validate()函数编写单元测试。项目中已有Polymer 2.x组件,用mocha、chai和web-test-runner完成测试,但Polymer官方文档推荐用Web Component Tester(WCT)测试1.x组件,我有以下疑问:
- 将WCT与web-test-runner结合是否合理?
- WCT目前是否仍在使用?
- 除WCT外,还有哪些Polymer 1.x组件单元测试方案?
另外,我尝试在测试文件导入该html、通过id访问dom-module,但均未成功。
解答
1. WCT与web-test-runner结合是否合理?
不合理。WCT是一套完整的测试运行环境,内置对Polymer 1.x的深度适配,包括自动处理HTML导入、Shadow DOM测试访问等特性;而web-test-runner是基于现代ES模块的测试工具,两者运行机制、依赖环境差异极大,强行结合会导致配置复杂度飙升,还可能出现组件加载顺序、Shadow DOM访问逻辑冲突等兼容性问题。建议针对Polymer 1.x和2.x分别维护测试配置,或统一到其中一套可行方案。
2. WCT目前是否仍在使用?
WCT目前处于维护状态,不再开发新功能,但仍有大量遗留Polymer 1.x项目在继续使用。它的优势是对Polymer 1.x特性支持完善,比如自动处理组件生命周期钩子测试、HTML导入逻辑等,适合维护老项目;缺点是生态停滞,对现代浏览器、新测试工具的兼容性较差。
3. 除WCT外的Polymer 1.x测试方案
- mocha+chai+jsdom:用jsdom模拟浏览器环境,手动加载Polymer库和组件HTML文件,借助Polymer API完成组件注册后测试。需要自行处理组件加载、初始化逻辑,适合需要高度自定义测试环境的场景。
- Karma+mocha+chai:Karma可启动真实浏览器运行测试,配合Polymer的HTML导入机制,能更贴近真实运行环境。需配置Karma加载Polymer库、组件文件,并适配Shadow DOM访问方式。
- 社区遗留脚手架:部分社区维护的老项目脚手架(如Yeoman的Polymer脚手架)自带Polymer 1.x测试配置,可直接复用。
解决组件导入失败问题
Polymer 1.x依赖HTML Imports加载组件,现代测试工具默认不支持该特性,直接导入.html文件会失败,可按以下步骤处理:
- 加载Polymer核心库:在测试文件开头先加载Polymer 1.x的核心库(如
polymer.html),确保API可用。 - 手动注册组件:通过
HTMLImports.whenReady()等待HTML导入完成,或直接读取组件HTML内容、提取并执行<script>部分,完成<dom-module>注册。 - 初始化组件实例:组件注册完成后,创建实例并挂载到测试容器,等待初始化完成后再调用
validate()测试。
示例测试代码(mocha+chai):
const { expect } = require('chai'); const fs = require('fs'); const path = require('path'); describe('create-layout', () => { let component; before((done) => { // 加载Polymer库(假设已通过npm安装) const polymerScript = document.createElement('script'); polymerScript.src = path.resolve(__dirname, '../node_modules/polymer/polymer.html'); polymerScript.onload = () => { // 读取并加载组件文件 const componentHtml = fs.readFileSync(path.resolve(__dirname, '../src/create-layout.html'), 'utf8'); const tempDiv = document.createElement('div'); tempDiv.innerHTML = componentHtml; document.body.appendChild(tempDiv); // 等待Polymer完成组件注册 HTMLImports.whenReady(() => { // 创建组件实例并挂载 component = document.createElement('create-layout'); document.body.appendChild(component); // 等待组件初始化完成 setTimeout(done, 100); }); }; document.head.appendChild(polymerScript); }); after(() => { document.body.removeChild(component); }); describe('validate()', () => { it('返回false当所有输入值为0', () => { const yearsInput = component.shadowRoot.querySelector('input[name="years"]'); const monthsInput = component.shadowRoot.querySelector('input[name="months"]'); const daysInput = component.shadowRoot.querySelector('input[name="days"]'); yearsInput.value = '0'; monthsInput.value = '0'; daysInput.value = '0'; const result = component.validate(); expect(result).to.be.false; expect(yearsInput.invalid).to.be.true; expect(monthsInput.invalid).to.be.true; expect(daysInput.invalid).to.be.true; }); it('返回true当至少一个输入值非0', () => { const yearsInput = component.shadowRoot.querySelector('input[name="years"]'); yearsInput.value = '1'; const result = component.validate(); expect(result).to.be.true; }); }); });
内容的提问来源于stack exchange,提问作者Swarnadipa Choudhury
相关产品推荐
相关产品推荐

