运行 e2e 测试时在 cypress 中模拟特定的 graphql 请求
Mock specific graphql request in cypress when running e2e tests
当 运行 使用 Cypress 进行 e2e 测试时,我的目标是模拟特定的 graphql 查询。
目前,我可以像这样模拟所有请求:
cy.server();
cy.route('POST', '/graphql', {
data: {
foo: 'bar'
},
});
问题是这会模拟 所有 /graphql
查询。如果我能以某种方式说,那就太棒了:
cy.route('POST', '/graphql', 'fooQuery', {
data: {
foo: 'bar'
},
});
在我们的应用程序中,我们使用 Apollo Graphql - 因此所有查询都被命名。
一种解决方法是在一个夹具文件中为有问题的 graphql 操作提供模拟数据
cypress/support/commands.js
Cypress.Commands.add('stubGraphQL', (graphQlFixture) => {
cy.fixture(graphQlFixture).then((mockedData) => {
cy.on('window:before:load', (win) => {
function fetch(path, { body }) {
const { operationName } = JSON.parse(body)
return responseStub(mockedData[operationName])
}
cy.stub(win, 'fetch', fetch).withArgs("/graphql").as('graphql');
});
})
})
const responseStub = result => Promise.resolve({
json: () => Promise.resolve(result),
text: () => Promise.resolve(JSON.stringify(result)),
ok: true,
})
//TODO how to get it to stop listening and trying to stub once the list of operations provided in fixture have been stubbed?
example fixture file
cypress/fixtures/signInOperation.json(请注意,那里有 2 个操作,这就是您可以指定模拟哪个响应的方式)
{
"SIGNIN_MUTATION": {
"data":{"signin":{"id":"ck896k87jac8w09343gs9bl5h","email":"sams@automation.com","name":"Sam","__typename":"User"}}
},
"CURRENT_USER_QUERY" : {
"data":{"me":{"id":"ck896k87jac8w09343gs9bl5h","email":"sams@automation.com","name":"!!Sam's Mock","permissions":["USER"],"cart":[{"id":"ck89gebgvse9w0981bhh4a147","quantity":5,"item":{"id":"ck896py6sacox0934lqc8c4bx","price":62022,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585253000/sickfitz/ecgqu4i1wgcj41pdlbty.jpg","title":"MensShoes","description":"Men's Shoes","__typename":"Item"},"__typename":"CartItem"},{"id":"ck89gec6mb3ei0934lmyxne52","quantity":5,"item":{"id":"ck896os7oacl90934xczopgfa","price":70052,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585252932/sickfitz/i7ac6fqhsebxpmnyd2ui.jpg","title":"WomensShoes2","description":"Women's Shoes","__typename":"Item"},"__typename":"CartItem"},{"id":"ck89gl45psely0981b2bvk6q5","quantity":7,"item":{"id":"ck89ghqkpb3ng0934l67rzjxk","price":100000,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585269417/sickfitz/eecjz883y7ucshlwvsbw.jpg","title":"watch","description":"Fancy Watch","__typename":"Item"},"__typename":"CartItem"}],"__typename":"User"}}
}
}
在您的规范文件中
cy.stubGraphQL('signInOperation.json')
cy.visit(yourURL)
cy.get(loginButton).click()
使用 cypress 5.1,使用新的 route2
命令模拟 GraphQL 请求非常简单,例如:
cy.route2('/graphql', (req) => {
if(req.body.includes('operationName')){
req.reply({ fixture: 'mockData.json'});
}
});
我刚刚添加了一个 if 条件来评估 GraphQL 请求的主体是否包含特定字符串作为查询的一部分。
如果这是真的,那么我会回复一个从夹具加载的自定义主体。
cy.route2()
的文档:
https://docs.cypress.io/api/commands/route2.html
在 cypress 6.0 中,route
和 route2
已弃用,建议使用 intercept
。正如文档 (https://docs.cypress.io/api/commands/intercept.html#Aliasing-individual-GraphQL-requests) 中所写,您可以通过这种方式模拟 GraphQL 请求:
cy.intercept('POST', '/api', (req) => {
if (req.body.operationName === 'operationName') {
req.reply({ fixture: 'mockData.json'});
}
}
如果想使用 fixture 进行 graphql 响应,可以试试这个:
cy.intercept('POST', '/test_api/graphql', (req) => {
req.continue((res) => {
if (req.body.operationName === 'op_name') {
res.send({ fixture: 'MyFixture/xyz.json' }),
req.alias = 'graphql'
}
})
})
当 运行 使用 Cypress 进行 e2e 测试时,我的目标是模拟特定的 graphql 查询。
目前,我可以像这样模拟所有请求:
cy.server();
cy.route('POST', '/graphql', {
data: {
foo: 'bar'
},
});
问题是这会模拟 所有 /graphql
查询。如果我能以某种方式说,那就太棒了:
cy.route('POST', '/graphql', 'fooQuery', {
data: {
foo: 'bar'
},
});
在我们的应用程序中,我们使用 Apollo Graphql - 因此所有查询都被命名。
一种解决方法是在一个夹具文件中为有问题的 graphql 操作提供模拟数据
cypress/support/commands.js
Cypress.Commands.add('stubGraphQL', (graphQlFixture) => {
cy.fixture(graphQlFixture).then((mockedData) => {
cy.on('window:before:load', (win) => {
function fetch(path, { body }) {
const { operationName } = JSON.parse(body)
return responseStub(mockedData[operationName])
}
cy.stub(win, 'fetch', fetch).withArgs("/graphql").as('graphql');
});
})
})
const responseStub = result => Promise.resolve({
json: () => Promise.resolve(result),
text: () => Promise.resolve(JSON.stringify(result)),
ok: true,
})
//TODO how to get it to stop listening and trying to stub once the list of operations provided in fixture have been stubbed?
example fixture file
cypress/fixtures/signInOperation.json(请注意,那里有 2 个操作,这就是您可以指定模拟哪个响应的方式)
{
"SIGNIN_MUTATION": {
"data":{"signin":{"id":"ck896k87jac8w09343gs9bl5h","email":"sams@automation.com","name":"Sam","__typename":"User"}}
},
"CURRENT_USER_QUERY" : {
"data":{"me":{"id":"ck896k87jac8w09343gs9bl5h","email":"sams@automation.com","name":"!!Sam's Mock","permissions":["USER"],"cart":[{"id":"ck89gebgvse9w0981bhh4a147","quantity":5,"item":{"id":"ck896py6sacox0934lqc8c4bx","price":62022,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585253000/sickfitz/ecgqu4i1wgcj41pdlbty.jpg","title":"MensShoes","description":"Men's Shoes","__typename":"Item"},"__typename":"CartItem"},{"id":"ck89gec6mb3ei0934lmyxne52","quantity":5,"item":{"id":"ck896os7oacl90934xczopgfa","price":70052,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585252932/sickfitz/i7ac6fqhsebxpmnyd2ui.jpg","title":"WomensShoes2","description":"Women's Shoes","__typename":"Item"},"__typename":"CartItem"},{"id":"ck89gl45psely0981b2bvk6q5","quantity":7,"item":{"id":"ck89ghqkpb3ng0934l67rzjxk","price":100000,"image":"https://res.cloudinary.com/deadrobot/image/upload/v1585269417/sickfitz/eecjz883y7ucshlwvsbw.jpg","title":"watch","description":"Fancy Watch","__typename":"Item"},"__typename":"CartItem"}],"__typename":"User"}}
}
}
在您的规范文件中
cy.stubGraphQL('signInOperation.json')
cy.visit(yourURL)
cy.get(loginButton).click()
使用 cypress 5.1,使用新的 route2
命令模拟 GraphQL 请求非常简单,例如:
cy.route2('/graphql', (req) => {
if(req.body.includes('operationName')){
req.reply({ fixture: 'mockData.json'});
}
});
我刚刚添加了一个 if 条件来评估 GraphQL 请求的主体是否包含特定字符串作为查询的一部分。 如果这是真的,那么我会回复一个从夹具加载的自定义主体。
cy.route2()
的文档:
https://docs.cypress.io/api/commands/route2.html
在 cypress 6.0 中,route
和 route2
已弃用,建议使用 intercept
。正如文档 (https://docs.cypress.io/api/commands/intercept.html#Aliasing-individual-GraphQL-requests) 中所写,您可以通过这种方式模拟 GraphQL 请求:
cy.intercept('POST', '/api', (req) => {
if (req.body.operationName === 'operationName') {
req.reply({ fixture: 'mockData.json'});
}
}
如果想使用 fixture 进行 graphql 响应,可以试试这个:
cy.intercept('POST', '/test_api/graphql', (req) => {
req.continue((res) => {
if (req.body.operationName === 'op_name') {
res.send({ fixture: 'MyFixture/xyz.json' }),
req.alias = 'graphql'
}
})
})