在Ember CLI Storybook中模拟使用ember-ajax的Ember服务以实现数据收发的最佳方法
Great question! When working with Ember CLI Storybook and components that depend on ember-ajax-powered services, you’ve got a few solid approaches to mock those network calls without hitting a real backend. Let’s break down the best methods tailored to your use case:
1. Mock the ember-ajax-backed Service Directly in Stories
The simplest approach is to leverage Ember’s dependency injection system to swap out your real service (whether it’s the raw ajax service or a custom service that uses ember-ajax) with a mocked version directly in your story. This lets you control exactly what data gets returned for each method.
For example, if your component relies on a custom data-service that uses ember-ajax under the hood:
// stories/my-component.stories.js import { hbs } from 'ember-cli-htmlbars'; import { module, story } from 'ember-cli-storybook'; import Service from '@ember/service'; // Define your mock service class MockDataService extends Service { // Simulate a GET request async fetchRecords() { return [ { id: 1, title: "Mocked Record 1" }, { id: 2, title: "Mocked Record 2" } ]; } // Simulate a POST request async submitRecord(payload) { return { success: true, message: `Successfully submitted: ${payload.title}` }; } } module('Components/MyComponent', function() { story('Default', function(book) { book.addParameters({ setup(owner) { // Register the mock service to replace the real one owner.register('service:data-service', MockDataService); } }); return { template: hbs`{{my-component}}` }; }); });
If your component uses the raw ajax service directly, you can mock that too:
class MockAjaxService extends Service { async request(url, options = {}) { // Return different data based on the request details if (url === '/api/records' && options.method === 'GET') { return { records: [{ id: 1, content: "Mocked content" }] }; } if (url === '/api/submit' && options.method === 'POST') { return { status: "success", data: options.data }; } return {}; } } // Register it in the setup hook owner.register('service:ajax', MockAjaxService);
2. Use Ember CLI Mirage for Network-Level Mocking
If you need more realistic network behavior (like handling HTTP status codes, query parameters, or route logic), Ember CLI Mirage is a fantastic choice. It intercepts all network requests made by ember-ajax at the network level, so you don’t need to modify your component or service code at all.
First, make sure Mirage is installed in your project:
ember install ember-cli-mirage
Then enable it in your Storybook setup by adding this to .storybook/preview.js:
// .storybook/preview.js import { startMirage } from '../mirage/config'; let server; export const previewAnnotations = { setup() { // Start Mirage when the story loads server = startMirage(); }, teardown() { // Shut down Mirage when the story unloads server.shutdown(); } };
Define your mock routes in mirage/config.js:
// mirage/config.js export default function() { this.namespace = '/api'; // Mock GET request for records this.get('/records', () => { return { records: [ { id: 1, title: "Mirage Mocked Record" }, { id: 2, title: "Another Mirage Mock" } ] }; }); // Mock POST request for submissions this.post('/submit', (schema, request) => { const payload = JSON.parse(request.requestBody); return { success: true, submittedData: payload }; }); }
Now all ember-ajax requests from your component will be intercepted by Mirage and return your predefined mock data.
3. Combine Storybook Args for Dynamic Mocking
If you want to tweak mock data on the fly (to test different edge cases or states), combine mocked services with Storybook Args. This lets you adjust response data directly from the Storybook sidebar.
// stories/my-component.stories.js import { hbs } from 'ember-cli-htmlbars'; import { module, story } from 'ember-cli-storybook'; import Service from '@ember/service'; module('Components/MyComponent', function() { story('Dynamic Mock Data', function(book) { book.addParameters({ // Define default args for your mock data args: { mockRecords: [{ id: 1, title: "Default Mock" }], mockSubmitResponse: { success: true, message: "Default success" } }, setup(owner, { args }) { class MockDataService extends Service { async fetchRecords() { // Use the dynamic args value return args.mockRecords; } async submitRecord() { return args.mockSubmitResponse; } } owner.register('service:data-service', MockDataService); } }); return { template: hbs`{{my-component}}` }; }); });
You’ll now see editable fields in the Storybook sidebar where you can modify the mock data and see the component update in real time.
Quick Recommendation
- Use Method 1 for simple, one-off mocks where you just need to replace specific service methods.
- Use Method 2 if you need realistic network behavior or already use Mirage in your project—no changes to your business code required.
- Use Method 3 when you want to dynamically test different data states without rewriting stories.
内容的提问来源于stack exchange,提问作者Randall Valenciano

