Ember测试:如何在Store Stub中返回RecordArray?
解决Ember组件测试中存根store返回RecordArray的问题
嘿,我之前做Ember组件验收测试时也碰到过一模一样的问题!用普通Ember.Object数组确实能让组件展示数据,但因为不是原生的RecordArray,那些依赖Ember Data特性的方法(比如save、响应式的set/get)就会直接失效。下面给你两种靠谱的解决办法:
方法一:手动创建原生RecordArray实例
Ember Data提供了RecordArray类,我们可以直接实例化它,这样存根返回的就是真正的RecordArray,所有原生方法都能正常工作:
import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { sinon } from 'ember-sinon'; import RecordArray from '@ember-data/store/-private/record-array'; import { run } from '@ember/runloop'; module('Integration | Component | your-component', function(hooks) { setupRenderingTest(hooks); test('renders records with working Ember Data methods', async function(assert) { const store = this.owner.lookup('service:store'); // 1. 创建测试用的模型记录(用store.createRecord保证是Ember Data的实例) const testRecords = run(() => [ store.createRecord('your-model', { id: 1, title: 'Test Record 1' }), store.createRecord('your-model', { id: 2, title: 'Test Record 2' }) ]); // 2. 实例化原生RecordArray,传入必要参数 const recordArray = run(() => RecordArray.create({ store, modelName: 'your-model', content: testRecords })); // 3. 存根store的peekAll方法,返回这个RecordArray const peekAllStub = sinon.stub(store, 'peekAll').returns(recordArray); // 渲染组件 await render(hbs`<YourComponent />`); // 你的断言逻辑,比如检查记录数量、内容 assert.dom('.record-title').exists({ count: 2 }); assert.dom('.record-title:first-child').hasText('Test Record 1'); // 测试save方法是否正常工作 await run(() => testRecords[0].save()); assert.ok(testRecords[0].hasDirtyAttributes === false, 'Record saved successfully'); // 别忘了恢复存根 peekAllStub.restore(); }); });
方法二:利用store的原生push方法(更省心)
如果你不想手动实例化RecordArray,还有个更简单的办法:先把测试数据push到store里,然后让存根的peekAll调用原生实现,这样返回的就是自动生成的RecordArray:
import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { sinon } from 'ember-sinon'; import { run } from '@ember/runloop'; module('Integration | Component | your-component', function(hooks) { setupRenderingTest(hooks); test('renders records with working Ember Data methods', async function(assert) { const store = this.owner.lookup('service:store'); // 1. 把测试数据push到store中 run(() => { store.push({ data: [ { id: 1, type: 'your-model', attributes: { title: 'Test Record 1' } }, { id: 2, type: 'your-model', attributes: { title: 'Test Record 2' } } ] }); }); // 2. 存根peekAll,调用原生的_peekAll方法(或者直接返回store.peekAll的结果) const peekAllStub = sinon.stub(store, 'peekAll').callsFake((modelName) => { return store._peekAll(modelName); // 或者直接 return store.peekAll(modelName); }); // 渲染组件 await render(hbs`<YourComponent />`); // 断言逻辑 assert.dom('.record-title').exists({ count: 2 }); // 测试set和save run(() => store.peekRecord('your-model', 1).set('title', 'Updated Title')); assert.dom('.record-title:first-child').hasText('Updated Title'); await run(() => store.peekRecord('your-model', 1).save()); assert.ok(store.peekRecord('your-model', 1).hasDirtyAttributes === false); peekAllStub.restore(); }); });
为什么之前的方法不行?
普通的Ember.Object数组只是简单的Ember对象集合,而RecordArray是Ember Data专门封装的类,它内置了和store交互的方法(比如save、rollback)、响应式数据更新、以及Ember Data特有的查询能力,所以只有返回真正的RecordArray,那些依赖这些特性的方法才能正常工作。
内容的提问来源于stack exchange,提问作者karthikaruna
相关产品推荐
相关产品推荐

