You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:28:46