TestCafe how to share variables from a RequestHook

Viewed 1472

We want to automate testing for our analytics calls. I am currently evaluation front end test tools, that could be used for this. I found TestCafe Studio to be what we would need to create the tests, but first I need some proof of concept. Thus I try to code a simple test case first. But I struggle with what seems to be the most basic. I want to assert that some parameters in a request have a certain value. So what I did is to create a RequestHook according to the documentation: https://devexpress.github.io/testcafe/documentation/test-api/intercepting-http-requests/creating-a-custom-http-request-hook.html (what they omit is that you need to export your class if you place it in a separate file...) I have two problems now:

  1. How can I wait for this request to be executed? The await t is only for the page I am requesting, but the analytics call is then executed later.
  2. How do I provide the test with some data collected in the hook?

Here is how far I have gotten (I got the URL in the console):

import { RequestHook} from 'testcafe';

export class AnalyticsRequestHook extends RequestHook {
    constructor (requestFilterRules, responseEventConfigureOpts) {
        super(requestFilterRules, responseEventConfigureOpts);
    }
    async onRequest (event) {
        console.log(event.requestOptions.url);
    }
    async onResponse (event) {
    }
}

I then instantiate this class with:

const analyticsRequestHook = new AnalyticsRequestHook(/https:\/\/trackinghost.com\//);

In some other examples, they just import t as well and you should have access to it in the methods. But this seems not to work for RequestHooks, as I get the following error as soon as I try to access t:

Cannot implicitly resolve the test run in the context of which the test controller action should be executed. Use test function's 't' argument instead.

But in onRequest I can't pass other arguments.

So are my two questions even possible, if yes, please provide an example, as I am really a complete newbie with testcafe.

2 Answers

what they omit is that you need to export your class if you place it in a separate file...

It's not related to the TestCafe framework. It's part of the JavaScript standard (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).

How can I wait for this request to be executed? The await t is only for the page I am requesting, but the analytics call is then executed later. How do I provide the test with some data collected in the hook?

Use the way from described in the example from this documentation topic - https://devexpress.github.io/testcafe/documentation/test-api/intercepting-http-requests/logging-http-requests.html

fixture `Fixture`;

class AnalyticsRequestHook extends RequestHook {
    constructor (requestFilterRules, responseEventConfigureOpts) {
        super(requestFilterRules, responseEventConfigureOpts);
    }
    async onRequest (event) {
        console.log(event.requestOptions.url);
    }
    async onResponse (event) {
    }
}

const analyticsRequestHook = new AnalyticsRequestHook(/https:\/\/trackinghost.com\//);

test
    .requestHooks(analyticsRequestHook)
    ('test', async t => {
        // Ensure that the response has been received and that its status code is 200.
        await t.expect(analyticsRequestHook.contains(record => record.response.statusCode === 200)).ok();

        const logRecord = analyticsRequestHook.requests[0];

        await t.expect(logRecord.request.url).eql('expected value');
    });

Cannot implicitly resolve the test run in the context of which the test controller action should be executed. Use test function's 't' argument instead.

Could you please provide the test code that raises this error message?

After a day of try and error I found a solution based on the comments of the other answer. I was simply using the RequestLogger wrong as I tried to do my asserts in the first expect. So, the documentation is almost right. Here is my test case now:

import { AnalyticsUrlParser } from './AnalyticsUrlParser.js';

const analyticsLogger = RequestLogger(/https:\/\/trackingdomain.com\//);

fixture('Analytics Test')
    .page('https://testdomain.com/en.html')
    .requestHooks(analyticsLogger);

test('Page load', async t => {
    await t.expect(analyticsLogger.count(record => record.response.statusCode === 200)).eql(1);

    const urlParser = new AnalyticsUrlParser(analyticsLogger.requests[0].request);
    const messages = urlParser.assertAll({
        pageName: 'Homepage English',
        events: ['event1'],
    });
    await t.expect(messages.length === 0).ok(messages.join('\n'));
}

The AnalyticsUrlParser is my own class that parses the query parameter and with the assertAll checks if certain parameters match the value provided. If not it adds to an array of messages which are then printed out.

Related