AndrewRoj
AndrewRoj

Reputation: 97

Testcafe V1.9.0 UnhandledPromiseRejectionWarning: TypeError: Cannot convert undefined or null to object

I am losing my marbles trying to figure out why testcafe is being such a pain. So here is my scenario: I have a runner which launches my tests against browserstack. fine. Once I bump my testcafe version from 1.6.1 to 1.9.0 the browserstack runner fails to launch. I get this error:

(node:12310) UnhandledPromiseRejectionWarning: TypeError: Cannot convert undefined or null to object
    at Function.entries (<anonymous>)
    at TestCafeConfiguration.mergeOptions (/Users/testcafe/node_modules/testcafe/lib/configuration/configuration-base.js:50:16)
    at TestCafeConfiguration.init (/Users/testcafe/node_modules/testcafe/lib/configuration/testcafe-configuration.js:48:14)
    at async getConfiguration (/Users/testcafe/node_modules/testcafe/lib/index.js:41:9)
    at async createTestCafe (/Users/testcafe/node_modules/testcafe/lib/index.js:57:27)
(node:12310) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:12310) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Weird enough if I were to bump my version to 1.7.0 I do not experience any issues. Any version 1.8.0 and up I get the above error.

Any one experienced this as well? Can someone shed some light on the issue?

Here is my runner SetupRunners.js file:

import getRunnerSrc from "./getRunnerSrc";
import getRunnerBrowsers from "./getRunnerBrowsers";


export default function setupRunner(runner, options = {}, cb) {
    let stream = false;

    const src = options.src || getRunnerSrc(options.breakpoint);

    if (src && src.length) {
        runner.src(src);

        runner.browsers(
            options.browsers || getRunnerBrowsers(options.breakpoint)
        );
  
        return cb(runner).then(data => {
            if (stream) {
                stream.end();
            }
            return data;
        });
    }
}

Here is the file that launches the tests against browserstack

import getArgs from "./getArgs";
import sanitizeArg from "./sanitizeArg";
import isBrowserStack from "./getIsBrowserStack";

const defaultBrowsers = {
    desktop: "Chrome:OS X",
    mobile: "Safari:iOS",
};
const browserStackPrefix = "browserstack:";

export default function getRunnerBrowsers(breakpoint) {
    const useBrowserStack = isBrowserStack();

    if (useBrowserStack && breakpoint) {
        return getBrowserstackDevices(breakpoint);
    }

    return `${useBrowserStack ? browserStackPrefix : ""}${sanitizeArg(
        getArgs("browsers") || defaultBrowsers.desktop
    )}`;
}

function getBrowserstackDevices(breakpoint) {
    return `${browserStackPrefix}${getArgs(`${breakpoint}_devices`) ||
        defaultBrowsers[breakpoint]}`;
}

here is the helper getArgs.js:

function getArgs(key) {
    if (process && process.argv && process.argv.length) {
        return process.argv.reduce((val, arg) => {
            const split = arg.split("=");
            if (split[0] === key || split[0] === "--" + key) {
                val = split[1];
            }
            return val;
        }, null);
    }
    return null;
}

module.exports = getArgs;

and santizeArgs.js

export default function sanitizeArg(ar) {
    return filterEmpty((ar || "").split(",").map(str => str.trim()));
}

export function filterEmpty(items) {
    return items.filter(item => item && item.length);
}

======= UPDATE ========

CREATE TESTCAFE FUNCTION at v1.7.0

async function createTestCafe(hostname, port1, port2, sslOptions, developmentMode, retryTestPages) {
    console.dir
    const configuration = new testcafe_configuration_1.default();
    await configuration.init({
        hostname,
        port1,
        port2,
        ssl: sslOptions,
        developmentMode,
        retryTestPages
    });

CREATE TESTCAFE FUNCTION AFTER UPDATING TESTCAFE TO v1.9.2

async function createTestCafe(...args) {
    const configuration = await getConfiguration(args); // HERE IS WHERE THE ERROR IS
    const [hostname, port1, port2] = await Promise.all([
        getValidHostname(configuration.getOption(option_names_1.default.hostname)),
        getValidPort(configuration.getOption(option_names_1.default.port1)),
        getValidPort(configuration.getOption(option_names_1.default.port2))
    ]);
    configuration.mergeOptions({ hostname, port1, port2 });
    const testcafe = new TestCafe(configuration);
    setupExitHook(cb => testcafe.close().then(cb));
    return testcafe;
}

Upvotes: 0

Views: 429

Answers (1)

mlosev
mlosev

Reputation: 5227

I reproduced the problem based on your information and created an issue in the TestCafe GitHub repository. As a workaround, you can correct parameter values passed to the 'createTestCafe' function.

According to the output you shared, you passed the 'null' value as the 'hostname' parameter. I guess the 'null' value means that the 'hostname' value is not specified. In this case, you need to return 'undefined' instead of 'null' to the 'createTestCafe' function.

Upvotes: 3

Related Questions