Mocks added in before are preserved between quarantine runs
What is your Scenario?
I'm using testcafe runner API and I'm adding request mock in before
What is the Current behavior?
If test fails and quarantine mode is enabled next quarantine attempts use the initial request mock
What is the Expected behavior?
I'd expect mocks to be cleared between quarantine attempts
What is your public website URL? (or attach your complete example)
n/a
What is your TestCafe test code?
index.js
const createTestCafe = require('testcafe');
let runNumber = 0;
const config = {
hooks: {
test: {
before: async (browser) => {
const { RequestMock } = require('testcafe');
const staticMock = RequestMock()
.onRequestTo('http://getrunnumber.invalid/static')
.respond(`<html><body><div id="runNumberStatic">${runNumber}</div></body></html>`, 200);
const dynamicMock = RequestMock()
.onRequestTo(`http://getrunnumber.invalid/${runNumber}`)
.respond(`<html><body><div id="runNumber">${runNumber}</div></body></html>`, 200);
runNumber++;
await browser.addRequestHooks([staticMock, dynamicMock]);
}
}
}
}
new Promise(async (resolve) => {
const testcafe = await createTestCafe(config);
const runner = testcafe.createRunner();
await runner.src('test.js').browsers('chrome').run({ quarantineMode: true });
resolve();
});
test.js
const { Selector } = require('testcafe');
fixture('test');
let expectedRunNumber = -1;
let shouldFail = true;
test('test', async (browser) => {
++expectedRunNumber;
await browser.navigateTo(`http://getrunnumber.invalid/${expectedRunNumber}`);
await browser.expect(Selector('#runNumber').exists).ok();
const dynamicVal = await Selector('#runNumber').textContent;
await browser.navigateTo('http://getrunnumber.invalid/static');
await browser.expect(Selector('#runNumberStatic').exists).ok();
const staticVal = await Selector('#runNumberStatic').textContent;
console.log(`run: ${expectedRunNumber}, dynamic: ${dynamicVal}, static ${staticVal}`);
await browser.expect(dynamicVal).eql(`${expectedRunNumber}`);
await browser.expect(staticVal).eql(`${expectedRunNumber}`);
if (shouldFail) {
shouldFail = false;
await browser.expect(false).ok();
}
})
Your complete configuration file
No response
Your complete test report
node index.js Running tests in:
- Chrome 101.0.4951.64 / macOS 10.15.7
test run: 0, dynamic: 0, static 0 run: 1, dynamic: 1, static 0 run: 2, dynamic: 2, static 0 ✖ test
-
AssertionError: expected '0' to deeply equal '2'
- expected - actual
-0 +2
Browser: Chrome 101.0.4951.64 / macOS 10.15.7
13 | await browser.navigateTo('http://getrunnumber.invalid/static'); 14 | await browser.expect(Selector('#runNumberStatic').exists).ok(); 15 | const staticVal = await Selector('#runNumberStatic').textContent; 16 | console.log(
run: ${expectedRunNumber}, dynamic: ${dynamicVal}, static ${staticVal}); 17 | await browser.expect(dynamicVal).eql(${expectedRunNumber});18 | await browser.expect(staticVal).eql(
${expectedRunNumber}); 19 | if (shouldFail) { 20 | shouldFail = false; 21 | await browser.expect(false).ok(); 22 | } 23 |})at
(/Users/andrzej-kodify/projects/testcafe-before-request-hooks/test.js:18:37) at asyncGeneratorStep (/Users/andrzej-kodify/projects/testcafe-before-request-hooks/test.js:1:114) at _next (/Users/andrzej-kodify/projects/testcafe-before-request-hooks/test.js:1:452)
1/1 failed (1s)
Screenshots
No response
Steps to Reproduce
TestCafe version
1.18.6
Node.js version
v16.14.2
Command-line arguments
n/a
Browser name(s) and version(s)
No response
Platform(s) and version(s)
No response
Other
No response
Hi @andrzej-kodify,
Thank you for the example. I reproduced this behavior. It is by design. Every test keeps request hooks during all runs and uses the first one that meets conditions. At present, we don't have plans to implement clearing hooks for tests between quarantine iterations. We will consider this if we decide to enhance this behavior in the future.
As a workaround, you can delete request hooks in the after hook with the removeRequestHooks method, which deletes passed hooks. To send hooks between before and after hooks, you can use the test controller context. Example:
const config = {
hooks: {
test: {
before: async (t) => {
const { RequestMock } = require('testcafe');
const staticMock = RequestMock()
.onRequestTo('http://getrunnumber.invalid/static')
.respond(`<html><body><div id="runNumberStatic">${runNumber}</div></body></html>`, 200);
const dynamicMock = RequestMock()
.onRequestTo(`http://getrunnumber.invalid/${runNumber}`)
.respond(`<html><body><div id="runNumber">${runNumber}</div></body></html>`, 200);
runNumber++;
await t.addRequestHooks([staticMock, dynamicMock]);
t.ctx.hooks = [staticMock, dynamicMock];
},
after: async (t) => {
await t.removeRequestHooks(t.ctx.hooks);
}
}
}
}
Thanks for reply, I've used another workaround where URL contains test run ID, so it's unique per quarantine attempt (although removing mocks is probably better).
I just feel like the behaviour of keeping anything between test runs is inconsistent with the rest (as e.g. user session is cleared) so I wanted to point it out. Other than that all good, maybe worth adding this to documentation (if it's not there already)
Thanks for reply, I've used another workaround where URL contains test run ID, so it's unique per quarantine attempt (although removing mocks is probably better).
Thank you for sharing this workaround.
Other than that all good, maybe worth adding this to documentation (if it's not there already)
We will consider updating our documentation though we find this use case a very rare situation.
This issue has been automatically marked as stale because it has not had any activity for a long period. It will be closed and archived if no further activity occurs. However, we may return to this issue in the future. If it still affects you or you have any additional information regarding it, please leave a comment and we will keep it open.
We're closing this issue after a prolonged period of inactivity. If it still affects you, please add a comment to this issue with up-to-date information. Thank you.