testcafe icon indicating copy to clipboard operation
testcafe copied to clipboard

Mocks added in before are preserved between quarantine runs

Open andrzej-woof opened this issue 3 years ago • 3 comments

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

  1. 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

andrzej-woof avatar May 16 '22 05:05 andrzej-woof

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);
            }
        }
    }
}

Aleksey28 avatar May 17 '22 10:05 Aleksey28

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)

andrzej-woof avatar May 17 '22 10:05 andrzej-woof

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.

Aleksey28 avatar May 18 '22 07:05 Aleksey28

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.

github-actions[bot] avatar Jul 30 '23 01:07 github-actions[bot]

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.

github-actions[bot] avatar Aug 09 '23 01:08 github-actions[bot]