针对仅有效负载不同的相同 API 调用模拟不同的响应

问题描述 投票:0回答:1

我有一个 Lit 组件,它对外部 API 进行两次 AJAX 调用:

1

  • 终点:
    PUT /api/rest/books/
  • 有效负载:
    { view: "VIEW_1", properties: { a: "abcde" } }
  • 期望的响应:一个随机的 JSON,我们称之为
    mockResponse1

2

  • 终点:
    PUT /api/rest/books/
  • 有效负载:
    { view: "VIEW_2", properties: { b: "1234" } }
  • 期望的响应:一个随机的 JSON,我们称之为
    mockResponse2

然后,在 Storybook 中,我使用 @web/mocks,它在幕后使用 MSW

import { registerMockRoutes } from '@web/mocks/browser.js';
import { http } from '@web/mocks/http.js';
...

export const main = () => html`<my-dummy-component></my-dummy-component>`;

main.parameters = {
  ...
  mocks: [
    http.put('/api/rest/books/', () => Response.json(mockResponse1)),
    http.put('/api/rest/books/', () => Response.json(mockResponse2))  // <--- How to differentiate this call?
  ]
};

正如预期的那样,因为 HTTP 方法和端点相同,所以两个 API 调用返回相同的

mockResponse1
,但这不是我想要的。

我尝试了以下解决方案:创建一个请求处理程序来检查请求正文中的特定属性(例如,唯一标识符):

mocks: [
    http.put('/api/rest/books', async ({request}) => {
      const req = await request.json()
      if(req.requestId === 1) return Response.json(mockResponse1)
      if(req.requestId === 2) return Response.json(mockResponse2)
    })
]

问题:这可行,但我将向真实服务器发送一个仅用于测试的属性。

想法 1: 为我的 API 服务实现一个 HTTP 拦截器,用于查找自定义环境变量:

  • 如果
    isDev
    为true(表示开发或测试环境),则在payload中添加callId。
  • 如果
    isDev
    为 false(生产版本),则省略
    requestId

想法 2: 不要修改有效负载,而是观察我知道将始终存在的属性。例如,如果请求 1 在其有效负载中始终包含属性视图:“VIEW_1”,则将其用作模拟处理程序的基础。然而,我与有效负载紧密耦合。如果将来请求 1 不再需要发送

view: "VIEW_1"
怎么办?

您对这些方法有何看法?

javascript mocking storybook msw
1个回答
0
投票

最后我采用了第二种策略。可以分两步完成。见下图:

首先,看一下项目的结构:

+---mocks
|   |   index.js <---- HERE is all the logic for OUR handlers
|   |
|   \---responses
|           mock-response-1.js <---- Just a random JSON
|           mock-response-2.js
|
\---src
    \---components
        \---dumb-component
                DumbComponent.js
                DumbComponent.stories.js <---- HERE we tell Storybook to use our mocks

第1步。实现区分处理程序的逻辑。在 mocks/index.js:

import { http } from '@web/mocks/http.js';

import mockResponse1 from './responses/mock-response-1.js';
import mockResponse2 from './responses/mock-response-2.js';

function __createHandler(conditionsAndResponses) {
  return [
    http.put('/api/rest/books/', async ({ request }) => {
      const payload = await request.json();
      for (const { check, response } of conditionsAndResponses) {
        if (check(payload)) { // Check if the payload meets our requirements
          return Response.json(response); // Return appropriate response
        }
      }
    }),
  ];
}

const __dumbCompHandler = __createHandler([
  {
    check: ({ view }) => view === 'VIEW_1', // The handler will run this check looking for the property that we know will always be present in the payload
    response: mockResponse1, // If the check successes, we want the handler to return this response
  },
  {
    check: ({ view }) => view === 'VIEW_2',
    response: mockResponse2,
  },
]);


export default {
  dumbComp: __dumbCompHandler(),
};

第 2 步。 告诉 Storybook 模拟从我们的组件发出的 HTTP 调用。在 DumbComponent.stories.js:

import { html } from 'ing-web-es/lit-2.js';
import { DumbComponent } from './src/DumbComponent.js';
import mocks from '../../mocks/index.js';

customElements.define('dumb-component', DumbComponent);

export default {
  title: 'DumbComponent',
};

export const main= () => html`<dumb-component></dumb-component>`;

main.parameters = {
  mocks: [mocks.newPinSetup], // <---- THIS LINE DOES EVERYTHING
};

奖金

如果我想根据某个变量的值返回另一个响应怎么办?例如,如果

mockErrorResponse
,我想返回
isLibraryClosed = true
。 在 mocks/index.js:

function __createDumbCompHandler({ isLibraryClosed = false }) {
  return __createHandler([
    {
      check: ({ view }) => view === 'VIEW_1',
      response: isLibraryClosed ? mockErrorResponse : mockResponse1, // Your logic here
    },
    {
      check: ({ view }) => view === 'VIEW_2',
      response: mockResponse2,
    },
  ]);
}

export default {
  dumbComp: (config) => __createDumbCompHandler(config),
};

DumbComponent.stories.js:

main.parameters = {
  mocks: [mocks.newPinSetup({ isLibraryClosed: true })], <---- THIS LINE DOES EVERYTHING
};

就这些了!

© www.soinside.com 2019 - 2024. All rights reserved.