无法让 Cypress 和 Pact 一起工作
Cannot make Cypress and Pact work together
我已经有几个通过赛普拉斯测试的工作项目。
现在我正在尝试使用 Cypress + Pact
添加合同测试
在开发者控制台中,我可以看到该应用正在调用 /api/v1/document-service
,但我得到:
Pact verification failed - expected interactions did not match actual.
部分日志:
W, [2021-07-20T12:49:37.157389 #34805] WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
POST /api/v1/document-service
W, [2021-07-20T12:49:37.157489 #34805] WARN -- : Missing requests:
POST /api/v1/document-service
我正在使用:
cypress: 7.5.0
@pact-foundation/pact: 9.16.0
我完成的步骤:
添加了 cypress 插件(https://github.com/pactflow/example-consumer-cypress/blob/master/cypress/plugins/cypress-pact.js)
添加命令(https://github.com/pactflow/example-consumer-cypress/blob/master/cypress/support/commands.js)
已将配置添加到 cypress.json (https://github.com/pactflow/example-consumer-cypress/blob/master/cypress.json) - 如果我不想与真实服务器交互,则不确定要将什么放入 baseUrl。
添加测试:
let server;
describe('Simple', () => {
before(() => {
cy.mockServer({
consumer: 'example-cypress-consumer',
provider: 'pactflow-example-provider',
}).then(opts => {
cy.log(opts)
server = opts
})
});
beforeEach(() => {
cy.fakeLogin()
cy.addMockRoute({
server,
as: 'products',
state: 'products exist',
uponReceiving: 'a request to all products',
withRequest: {
method: 'POST',
path: '/api/v1/document-service',
},
willRespondWith: {
status: 200,
body: {
data: {
collections: [
{
id: '954',
name: 'paystubs',
},
{
id: '1607',
name: 'mystubs',
},
],
},
},
},
});
});
it('is ok?', () => {
cy.visit('/new/experiments/FirstProject/collections');
});
})
尝试使用已弃用的 cy.server()
/cy.route()
和新的 cy.intercept()
,但仍然验证失败。
在 Pactflow,我们花了大约 6 个月的时间一起使用 Cypress 和 Pact,按照 https://pactflow.io/blog/cypress-pact-front-end-testing-with-confidence/
中的建议,使用 Pact 模拟服务从我们的 Cypress 测试中生成契约
我们本周决定改变我们的方法,原因如下。
- 我们的 Cypress 测试比我们的单元测试慢得多(15 分钟以上),因此当我们从 Cypress 测试生成契约与我们的单元测试相比,生成契约,然后验证它需要更长的时间。
- 我们的 Cypress 测试可能会因为与 Pact 无关的原因而失败(例如布局更改、构建节点上的内存消耗问题、UI 库升级等),这会阻止来自 Pact 的协议正在生成。
- Cypress 的 intercept() 和 mock 服务不能很好地协同工作。任何没有针对 Cypress 的显式 intercept() 的请求最终都会在模拟服务处结束,并且每次页面使用新端点时,请求都会命中模拟服务,然后整体测试失败,即使该端点该特定测试不需要。
- 当 Cypress 测试失败时,Cypress 库提供了非常好的调试功能。当它由于与 Pact 有关的原因而失败时,目前很难确定原因,因为该信息不会显示在浏览器中(这可能会得到改进,但是,它不会缓解已经列出的问题)。
我们的新方法是从我们的单元测试(而不是我们的 Cypress 测试)生成我们的 Pacts,并使用剥离 Pact 匹配器的函数在单元测试和 Cypress 测试之间共享固定装置。例如
const SOME_INTERACTION = {
state: 'some state',
uponReceiving: "some request",
withRequest: {
method: "GET",
path: "/something"
},
willRespondWith: {
status: 200,
body: {
something: like("hello")
}
}
}
单元测试
describe('Something', () => {
let someProviderMockService
beforeAll(() => {
someProviderMockService = new Pact({
consumer: 'some-consumer',
provider: 'some-provider'
})
return someProviderMockService.setup()
})
afterAll(() => someProviderMockService.finalize())
afterEach(() => someProviderMockService.verify())
describe('loadSomething', () => {
beforeEach(() => {
return someProviderMockService.addInteraction(SOME_INTERACTION)
})
it('returns something', async () => {
const something = await loadSomething()
//expectations here
})
})
})
将 Pact 交互格式转换为 Cypress 路由格式并去除 Pact 匹配器的函数。
const Matchers = require('@pact-foundation/pact-web').Matchers
// TODO map the request body and query parameters too
const toCypressInteraction = (interaction) => {
return {
method: interaction.withRequest.method,
url: Matchers.extractPayload(interaction.withRequest.path),
status: interaction.willRespondWith.status,
headers: Matchers.extractPayload(interaction.willRespondWith.headers),
response: Matchers.extractPayload(interaction.willRespondWith.body)
}
}
在赛普拉斯测试中
cy.route(toCypressInteraction(SOME_INTERACTION))
这种方法有以下好处:
- 契约生成速度很快。
- 契约生成可靠。
- Cypress 测试更可靠且更易于调试。
- 赛普拉斯测试中使用的请求被验证是正确的。
- “交互膨胀”的可能性较小,其中添加交互只是为了测试 UI 功能,而不是因为它们提供了有价值的覆盖范围。
希望这些信息对您有所帮助。我们现在推荐这种方法,而不是在 Cypress 测试中直接使用模拟服务。
我已经有几个通过赛普拉斯测试的工作项目。 现在我正在尝试使用 Cypress + Pact
添加合同测试在开发者控制台中,我可以看到该应用正在调用 /api/v1/document-service
,但我得到:
Pact verification failed - expected interactions did not match actual.
部分日志:
W, [2021-07-20T12:49:37.157389 #34805] WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
POST /api/v1/document-service
W, [2021-07-20T12:49:37.157489 #34805] WARN -- : Missing requests:
POST /api/v1/document-service
我正在使用:
cypress: 7.5.0
@pact-foundation/pact: 9.16.0
我完成的步骤:
添加了 cypress 插件(https://github.com/pactflow/example-consumer-cypress/blob/master/cypress/plugins/cypress-pact.js)
添加命令(https://github.com/pactflow/example-consumer-cypress/blob/master/cypress/support/commands.js)
已将配置添加到 cypress.json (https://github.com/pactflow/example-consumer-cypress/blob/master/cypress.json) - 如果我不想与真实服务器交互,则不确定要将什么放入 baseUrl。
添加测试:
let server; describe('Simple', () => { before(() => { cy.mockServer({ consumer: 'example-cypress-consumer', provider: 'pactflow-example-provider', }).then(opts => { cy.log(opts) server = opts }) }); beforeEach(() => { cy.fakeLogin() cy.addMockRoute({ server, as: 'products', state: 'products exist', uponReceiving: 'a request to all products', withRequest: { method: 'POST', path: '/api/v1/document-service', }, willRespondWith: { status: 200, body: { data: { collections: [ { id: '954', name: 'paystubs', }, { id: '1607', name: 'mystubs', }, ], }, }, }, }); }); it('is ok?', () => { cy.visit('/new/experiments/FirstProject/collections'); }); })
尝试使用已弃用的 cy.server()
/cy.route()
和新的 cy.intercept()
,但仍然验证失败。
在 Pactflow,我们花了大约 6 个月的时间一起使用 Cypress 和 Pact,按照 https://pactflow.io/blog/cypress-pact-front-end-testing-with-confidence/
中的建议,使用 Pact 模拟服务从我们的 Cypress 测试中生成契约我们本周决定改变我们的方法,原因如下。
- 我们的 Cypress 测试比我们的单元测试慢得多(15 分钟以上),因此当我们从 Cypress 测试生成契约与我们的单元测试相比,生成契约,然后验证它需要更长的时间。
- 我们的 Cypress 测试可能会因为与 Pact 无关的原因而失败(例如布局更改、构建节点上的内存消耗问题、UI 库升级等),这会阻止来自 Pact 的协议正在生成。
- Cypress 的 intercept() 和 mock 服务不能很好地协同工作。任何没有针对 Cypress 的显式 intercept() 的请求最终都会在模拟服务处结束,并且每次页面使用新端点时,请求都会命中模拟服务,然后整体测试失败,即使该端点该特定测试不需要。
- 当 Cypress 测试失败时,Cypress 库提供了非常好的调试功能。当它由于与 Pact 有关的原因而失败时,目前很难确定原因,因为该信息不会显示在浏览器中(这可能会得到改进,但是,它不会缓解已经列出的问题)。
我们的新方法是从我们的单元测试(而不是我们的 Cypress 测试)生成我们的 Pacts,并使用剥离 Pact 匹配器的函数在单元测试和 Cypress 测试之间共享固定装置。例如
const SOME_INTERACTION = {
state: 'some state',
uponReceiving: "some request",
withRequest: {
method: "GET",
path: "/something"
},
willRespondWith: {
status: 200,
body: {
something: like("hello")
}
}
}
单元测试
describe('Something', () => {
let someProviderMockService
beforeAll(() => {
someProviderMockService = new Pact({
consumer: 'some-consumer',
provider: 'some-provider'
})
return someProviderMockService.setup()
})
afterAll(() => someProviderMockService.finalize())
afterEach(() => someProviderMockService.verify())
describe('loadSomething', () => {
beforeEach(() => {
return someProviderMockService.addInteraction(SOME_INTERACTION)
})
it('returns something', async () => {
const something = await loadSomething()
//expectations here
})
})
})
将 Pact 交互格式转换为 Cypress 路由格式并去除 Pact 匹配器的函数。
const Matchers = require('@pact-foundation/pact-web').Matchers
// TODO map the request body and query parameters too
const toCypressInteraction = (interaction) => {
return {
method: interaction.withRequest.method,
url: Matchers.extractPayload(interaction.withRequest.path),
status: interaction.willRespondWith.status,
headers: Matchers.extractPayload(interaction.willRespondWith.headers),
response: Matchers.extractPayload(interaction.willRespondWith.body)
}
}
在赛普拉斯测试中
cy.route(toCypressInteraction(SOME_INTERACTION))
这种方法有以下好处:
- 契约生成速度很快。
- 契约生成可靠。
- Cypress 测试更可靠且更易于调试。
- 赛普拉斯测试中使用的请求被验证是正确的。
- “交互膨胀”的可能性较小,其中添加交互只是为了测试 UI 功能,而不是因为它们提供了有价值的覆盖范围。
希望这些信息对您有所帮助。我们现在推荐这种方法,而不是在 Cypress 测试中直接使用模拟服务。