我们在应用程序中使用段,我需要实现端到端测试以验证段调用的数量,我必须确保每个事件仅被调用一次。 我找了好久,找到了这个验证api调用次数的
command
:
Cypress.Commands.add(`verifyCallCount`, (alias, expectedNumberOfCalls) => {
const resolvedAlias = alias[0] === `@` ? alias.substring(1) : alias;
cy.get(`${resolvedAlias}.all`, { timeout: 20000 }).then((calls) => {
cy.wrap(calls.length).should(`equal`, expectedNumberOfCalls);
});
});
我在等待api调用后使用这个命令:
cy.wait(`@${eventAlias}`, { timeout: 20000 })
.then((interception) => {
return JSON.parse(interception.request.body);
})
.then(() => cy.verifyCallCount(eventAlias, 1));
这也是我为 api 调用添加别名的地方:
beforeEach(() => {
cy.intercept('POST', 'https://api.segment.io/v1', (req) => {
const body = JSON.parse(req.body);
if (body.hasOwnProperty('type') && body.type === SampleEvent) {
req.alias = eventAlias;
}
});
});
使用这种方法,当我在本地环境中运行测试时,它通过了,没有任何问题。但同样的测试在 github 的操作上失败了。这是错误:
AssertionError: Timed out retrying after 10000ms: Expected to find element: `eventAlias.all`, but never found it.
我认为
.get()
命令在.wait()
之后没有被执行,我尝试更改命令的顺序,但没有帮助。
如何在 github actions 中解决这个问题?
还有其他方法可以验证cypress中的api调用次数吗?
感谢您的帮助,谢谢。
您在此处使用的答案验证提出请求的次数是错误的。
行
const resolvedAlias = alias[0] === '@' ? alias.substring(1) : alias
删除了最初的@
,但需要保留。
cy.get('${resolvedAlias}.all', { timeout: 20000 })
中的超时也没有效果,它不会等待 20 秒来让所有调用发生。
在您的测试场景中可能有 0、1 或 2 个调用。如果有 0 个调用或 2 个调用,您希望失败,如果恰好有 1 个调用,您希望通过。
如果有 0 次调用,这足以失败
cy.wait(`@${eventAlias}`, { timeout: 20000 })
如果有 2 个调用就会失败,您必须使用硬等待,然后验证调用计数
cy.wait(`@${eventAlias}`, { timeout: 20_000 })
cy.wait(2_000) // wait an interval for any extra call to occur
cy.get(`@${eventAlias}.all`)
.its('length')
.should(`equal`, 1); // if two calls happened in interval, fail here
您的目标是确保只有 1 次 API 调用。
您将需要测试来等待并查看是否发生第二次呼叫。
it('accurately test that only one API call happens', () => {
const numOfRequests = 1
cy.intercept('**/api/*', cy.spy().as('api-spy'))
cy.visit('/');
cy.wait(1000)
cy.get('@api-spy').its('callCount').should('equal', numOfRequests)
})
我用一个简单的页面进行了测试,故意调用两次,调用之间延迟100ms,
<script>
fetch('api/1')
setTimeout(() => fetch('api/2'), 100) // delayed 2nd fetch we want to test for
</script>
没有经过艰苦的等待,测试就给了我一个错误通过。
我也尝试过反转逻辑,但仍然需要等待才能正确测试
cy.intercept('**/api/*', cy.spy().as('api-spy'))
cy.visit('/');
cy.wait(1000)
cy.get('@api-spy').its('callCount')
.should('not.equal', 0)
.and('not.equal', 2) // false pass without hard wait
})
呼叫计数的第二个别名
before(() => {
cy.wrap(0).as('eventCount')
})
beforeEach(() => {
cy.intercept('POST', 'https://api.segment.io/v1', (req) => {
const body = JSON.parse(req.body);
if (body.hasOwnProperty('type') && body.type === SampleEvent) {
req.alias = eventAlias;
cy.get('@eventCount').then(count => {
cy.wrap(count + 1).as('eventCount')
})
}
});
});
});
it('checks the count', () => {
cy.visit('/');
cy.wait(1000)
cy.get('@eventCount')
.should('equal', 1)
})
增加全局
let eventCount = 0;
beforeEach(() => {
cy.intercept('POST', 'https://api.segment.io/v1', (req) => {
const body = JSON.parse(req.body);
if (body.hasOwnProperty('type') && body.type === SampleEvent) {
req.alias = eventAlias;
eventCount += 1
}
});
});
});
it('checks the count', () => {
cy.visit('/');
cy.wait(1000)
.then(() => {
cy.wrap(eventCount)
.should('equal', 1)
})
})
我注意到你提到了 github 操作。我在 CI 中测试 API 调用时遇到了类似的问题,测试运行速度慢得多并且导致不稳定。
我建议模拟响应,以便从测试中获得更好、更一致的性能。
参考:控制响应
作为奖励,不需要任何长时间的超时,因为你的模拟会立即回复。
beforeEach(() => {
cy.intercept('POST', 'https://api.segment.io/v1', (req) => {
const body = JSON.parse(req.body);
if (body.hasOwnProperty('type') && body.type === SampleEvent) {
req.alias = eventAlias;
// here send mock response without any network delay
req.reply({
headers: {
Set-Cookie: 'newUserName=Peter Pan;'
},
statusCode: 201,
body: {
name: 'Peter Pan'
}
})
}
});
});
})
it('tests there is only a single POST from app', () => {
cy.wait(`@${eventAlias}`)
cy.wait(100)
cy.get(`@${eventAlias}.all`).then((calls) => {
cy.wrap(calls.length).should(`equal`, 1);
});
})
当您想要获取所有别名调用时,您需要使用
@
来表示别名。因此自定义命令需要更新。
Cypress.Commands.add(`verifyCallCount`, (registeredAlias, expectedNumberOfCalls) => {
if(alias[0] !== '@') {
throw new Error ('alias does not start with '@')
}
cy.get(`${registeredAlias}.all`, { timeout: 20000 }).then((calls) => {
cy.wrap(calls.length).should(`equal`, expectedNumberOfCalls);
});
});
使用方法
cy.intercept('call').as('call')
// some action to trigger call
cy.wait('@call')
// some other actions
cy.verifyCallCount('@call')
还有其他方法可以验证cypress中的api调用次数吗?
这是一种统计 api 调用并等待它们完成的简洁方法。
您可以传递
cy.spy()
作为“响应”,您可以使用它来计算拦截被命中的次数。
在 Cypress 断言中使用
.should()
将等到预期的请求数量返回。
it('test', () => {
const numOfRequests = 5;
cy.intercept('https://api.segment.io/v1', cy.spy().as('api-spy'));
// Do something to trigger 5 requests
cy.get('@api-spy').its('callCount').should('equal', numOfRequests);
});
如果您正在等待一系列不同的端点,例如
/v1/login
后跟 /v1/getData
等,则 cy.intercept
中的 URL 可能需要使用通配符。
例如:
cy.intercept('https://api.segment.io/v1/**')