用openApi后端模拟service worker



我正在使用MSW和openapi后端包。我想模拟展台浏览器服务器和测试服务器。我有OpenAPI定义可用的形式与我生成生成。用于RTK查询(超出本问题的范围)。我想使用OpenAPI规范将其与OpenAPI后端一起使用,并为浏览器和测试生成MSW rest worker。

Setup is next:

index.tsx

import worker from './mocks/browser';
if (process.env.NODE_ENV === 'development') {
worker.start();
}

模拟/browser.ts

import { setupWorker, rest } from 'msw';
import { OpenAPIBackend } from 'openapi-backend';
import type { Document } from 'openapi-backend';
import definition from './api.json';

// create our mock backend with openapi-backend
const api = new OpenAPIBackend({ definition: definition as Document });
api.register('notFound', (c, res, ctx) => res(ctx.status(404)));
api.registerHandler('notImplemented', async (c, req, res) => {
const { status, mock } = await api.mockResponseForOperation(
c.operation.operationId as string
);
return res.status(status).json(mock);
});
api.register('validationFail', (c, res, ctx) =>
res(ctx.status(400), ctx.json({ error: c.validation.errors }))
);
const worker = setupWorker(
rest.get('/*', (req) =>
api.handleRequest({
...req,
path: req.url.pathname,
headers: req.headers.all(),
method: req.method,
body: req.body,
})
)
);

export default worker;

api。JSON

{
"openapi": "3.0.1",
"info": {
"title": "Fetch API",
"description": "Source of truth for Fetch dashboard",
"version": "0.1.5"
},
"paths": {
"/config": {
"get": {
"tags": [
"Configuration"
],
"summary": "Retreive configuration object",
"description": "Returns configuration object (map) containing configuration parameters for UI (Map<String, String>)",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Map serialized to json object.",
"example": {
"FA_COLOR": "red",
"FA_NAME": "fetch"
}
}
}
}
}
}
}
},
"/links": {
"get": {
"tags": [
"Notifications & Links",
"Walking Skeleton"
],
"summary": "List all defined links for hospital",
"description": "Retreives all defined links for hospital. Hospital ID is indirectly obtained from user identity.",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
}
}
}
}
},
"/kpis": {
"get": {
"tags": [
"KPIS"
],
"summary": "List all KPIs for hospital(s) that current user is managing.",
"description": "Retreives all KPIs available for hospitals that current user is managing.",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/KPI"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"KPI": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"revenue",
"labour"
]
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this KPI describes"
},
"goal": {
"type": "number",
"description": "full month goal"
},
"actual": {
"type": "number",
"description": "actual result"
},
"mtd_goal": {
"type": "number",
"description": "month to date goal, so that we can track projected fulfillment of goal."
},
"details": {
"type": "object",
"description": "Semi-structured way of describing details of calculation. Every KPI will potentialiy be described differently."
}
},
"required": [
"id",
"hospital_id",
"goal",
"actual",
"mtd_goal"
]
},
"Link": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "unique id of link"
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this Link is configured for"
},
"title": {
"type": "string",
"description": "human readable title for URL"
},
"description": {
"type": "string",
"description": "Description of current link (alt text , or tooltip)"
},
"url": {
"type": "string",
"description": "Location of external resource"
},
"urgent": {
"type": "boolean",
"description": "Is urgency of notification elevated?"
},
"count": {
"type": "number",
"description": "Actual notification value. How many 'tasks' are waiting manager in external system."
},
"updated_at": {
"type": "integer",
"description": "Date/time of last notification update",
"format": "int64"
},
"children": {
"type": "array",
"description": "Since notifications are possibly presented in hierarchy all children of this notification will be gathered here",
"items": {
"$ref": "#/components/schemas/Link"
}
}
},
"required": [
"id",
"hospital_id",
"title",
"url"
],
"example": [
{
"id": 1,
"hospital_id": "001",
"title": "Link1",
"description": "description of Link1",
"url": "https://www.example.com/link1",
"urgent": true,
"count": 1,
"updated_at": 1631113184221,
"children": [
{
"id": 2,
"hospital_id": "001",
"title": "Link2",
"description": "description of Link2",
"url": "https://www.example.com/link2",
"urgent": true,
"count": 1,
"updated_at": 1631113184221
}
]
},
{
"id": 3,
"hospital_id": "002",
"title": "Link3",
"description": "description of Link3",
"url": "https://www.example.com/link3",
"urgent": false,
"count": 2,
"updated_at": 1631113184221
}
]
}
}
}
}

component.tsx

const { data: links, error, isLoading } = useGetLinksQuery({});

正在获取localhost:3000/links

得到的错误是:

mockServiceWorker.js:222 [MSW] Uncaught exception in the request handler for "GET http://localhost:3000/links":
Error: Unknown operation
at OpenAPIValidator.validateRequest (http://localhost:3000/static/js/vendors~main.chunk.js:63911:13)
at OpenAPIBackend.<anonymous> (http://localhost:3000/static/js/vendors~main.chunk.js:54246:45)
at async OpenAPIBackend.handleRequest (http://localhost:3000/static/js/vendors~main.chunk.js:54152:22)
This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses
getResponse @ mockServiceWorker.js:222
async function (async)
getResponse @ mockServiceWorker.js:175
handleRequest @ mockServiceWorker.js:113
async function (async)
handleRequest @ mockServiceWorker.js:112
(anonymous) @ mockServiceWorker.js:271

网络标签给出:

Request URL: http://localhost:3000/links
Request Method: GET
Status Code: 500  (from service worker)
Referrer Policy: strict-origin-when-cross-origin

所有与文章相关:https://dev.to/epilot/testing-react-with-jest-and-openapi-mocks-8gc和https://testing-library.com/docs/react-testing-library/example-intro/

谢谢。

在你的OpenApi你没有任何operationId。你需要通过路由设置一个唯一的Id。

{
"openapi": "3.0.1",
"info": {
"title": "Fetch API",
"description": "Source of truth for Fetch dashboard",
"version": "0.1.5"
},
"paths": {
"/config": {
"get": {
"tags": [
"Configuration"
],
"operationId": "config",
"summary": "Retreive configuration object",
"description": "Returns configuration object (map) containing configuration parameters for UI (Map<String, String>)",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Map serialized to json object.",
"example": {
"FA_COLOR": "red",
"FA_NAME": "fetch"
}
}
}
}
}
}
}
},
"/links": {
"get": {
"tags": [
"Notifications & Links",
"Walking Skeleton"
],
"operationId": "links",
"summary": "List all defined links for hospital",
"description": "Retreives all defined links for hospital. Hospital ID is indirectly obtained from user identity.",
"responses": {
"200": {
"description": "successfull operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
}
}
}
}
},
"/kpis": {
"get": {
"tags": [
"KPIS"
],
"summary": "List all KPIs for hospital(s) that current user is managing.",
"description": "Retreives all KPIs available for hospitals that current user is managing.",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/KPI"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"KPI": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"revenue",
"labour"
]
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this KPI describes"
},
"goal": {
"type": "number",
"description": "full month goal"
},
"actual": {
"type": "number",
"description": "actual result"
},
"mtd_goal": {
"type": "number",
"description": "month to date goal, so that we can track projected fulfillment of goal."
},
"details": {
"type": "object",
"description": "Semi-structured way of describing details of calculation. Every KPI will potentialiy be described differently."
}
},
"required": [
"id",
"hospital_id",
"goal",
"actual",
"mtd_goal"
]
},
"Link": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "unique id of link"
},
"hospital_id": {
"type": "string",
"description": "id of hospital that this Link is configured for"
},
"title": {
"type": "string",
"description": "human readable title for URL"
},
"description": {
"type": "string",
"description": "Description of current link (alt text , or tooltip)"
},
"url": {
"type": "string",
"description": "Location of external resource"
},
"urgent": {
"type": "boolean",
"description": "Is urgency of notification elevated?"
},
"count": {
"type": "number",
"description": "Actual notification value. How many 'tasks' are waiting manager in external system."
},
"updated_at": {
"type": "integer",
"description": "Date/time of last notification update",
"format": "int64"
},
"children": {
"type": "array",
"description": "Since notifications are possibly presented in hierarchy all children of this notification will be gathered here",
"items": {
"$ref": "#/components/schemas/Link"
}
}
},
"required": [
"id",
"hospital_id",
"title",
"url"
],
"example": [
{
"id": 1,
"hospital_id": "001",
"title": "Link1",
"description": "description of Link1",
"url": "https://www.example.com/link1",
"urgent": true,
"count": 1,
"updated_at": 1631113184221,
"children": [
{
"id": 2,
"hospital_id": "001",
"title": "Link2",
"description": "description of Link2",
"url": "https://www.example.com/link2",
"urgent": true,
"count": 1,
"updated_at": 1631113184221
}
]
},
{
"id": 3,
"hospital_id": "002",
"title": "Link3",
"description": "description of Link3",
"url": "https://www.example.com/link3",
"urgent": false,
"count": 2,
"updated_at": 1631113184221
}
]
}
}
}
}

最新更新