Cypress - Intercept GraphQL Request
By Benny Yen at
如何 intercept GraphQL 請求
如何 intercept GraphQL 在官方文件 Cypress - Intercept 寫得很清楚了,本文會著重分享平常如何簡化流程。
基本上和官方文件的做法沒有區別,主要針對實際測試需求做出了一些調整。因爲測試的 api 已經用名字區分 query/mutation,因此沒有再針對 query/mutation 做處理。
// utils/intercept-utils.ts
import type { CyHttpMessages } from "cypress/types/net-stubbing";
export const getAliasName = (operationName: string) => {
return `gql${operationName[0].toUpperCase()}${operationName.slice(1)}`;
};
export const hasOperationName = (
req: CyHttpMessages.IncomingRequest,
operationName: string,
) => {
const { body } = req;
return (
Object.hasOwn(body, "operationName") && body.operationName === operationName
);
};
// Alias query if operationName matches
export const aliasGql = (operationName: string) => {
return cy.intercept("POST", "/graphql", (req) => {
if (hasOperationName(req, operationName)) {
req.alias = getAliasName(operationName);
}
});
};
我寫了一個專門處理 intercept GraphQL 的 command,行爲和一般的 intercept
沒有差別,只是幫忙處理了
operationName
的檢查,以及前面重複的 route
。
// support/commands.ts
import { hasOperationName } from "./utils/intercept-utils";
Cypress.Commands.add("interceptGql", (operationName, response) => {
if (!response) return;
return cy.intercept("POST", "/graphql", (req) => {
if (hasOperationName(req, operationName)) {
switch (typeof response) {
case "function": {
response(req);
break;
}
default: {
req.reply(response);
break;
}
}
}
});
});
寫了 custom commands 就需要定義好 type,才能夠發揮出 typescript
+ IntelliSense 的好處。
// global.d.ts
declare namespace Cypress {
interface Chainable<Subject = any> {
interceptGql(
operationName: string,
response: import("cypress/types/net-stubbing").RouteHandler,
): Chainable<null>;
}
}
實際應用在測試上:
// e2e/spec.ts
import { aliasGql } from "./support/utils/intercept-utils";
describe("intercept gql", () => {
beforeEach(() => {
aliasGql("queryProjects");
});
it("query project and wait", () => {
cy.visit("/projects");
cy.wait("@gqlQueryProjects");
});
it("custom command", () => {
// 行為同 intercept,只是省去處理 graphql 的步驟
cy.interceptGql("queryProjects", {
data: {
queryProjects: {
projects: [
{
id: 1,
},
{
id: 2,
},
],
},
},
});
cy.interceptGql("queryProjects", (req) => {
req.reply({
data: {
queryProjects: {
projects: [
{
id: 1,
},
],
},
},
});
});
});
});
有了這些設置,基本上可以應付我絕大多數的場景,即使需要一些客制化的 intercept graphql 的内容,也可以利用 RouteHandler
實現,可以説是爲我在撰寫測試項目節省了相當多的時間。