Skip to content

Unable to use absolute paths for includes in config file #1119

@mikecbrant

Description

@mikecbrant

What are you trying to achieve?

Use absolute path for defining includes in config file

What do you get instead?

Here is error I was getting when running either run or run-multiple:

[1.parallel:chunk1:Nightmare] Could not include object I from module 'C:\Users\a0225521\Documents\git\ticom-mobile\C:\Users\a0225521\Documents\git\ticom-mobile\test\codecept-ui\lib\actor.js'
Cannot find module 'C:\Users\a0225521\Documents\git\ticom-mobile\C:\Users\a0225521\Documents\git\ticom-mobile\test\codecept-ui\lib\actor.js'
[1.parallel:chunk1:Nightmare]
[1.parallel:chunk1:Nightmare] Error: 
    at loadSupportObject (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\container.js:203:11)
    at getSupportObject (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\container.js:191:12)
    at createSupportObjects (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\container.js:148:21)
    at Function.create (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\container.js:33:25)
    at Codecept.init (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\codecept.js:52:15)
    at Command.module.exports (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\codeceptjs\lib\command\run.js:35:14)
    at Command.listener (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\commander\index.js:315:8)
    at Command.emit (events.js:127:13)
    at Command.parseArgs (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\commander\index.js:651:12)
    at Command.parse (C:\Users\a0225521\Documents\git\ticom-mobile\node_modules\commander\index.js:474:21)

You will note the main working directory is prepended an extra time to the values derived from my config file below.

I was able to track this down to the following code in lib/step.php (from change introduced in PR #1094)

const support = Config.get('include', {});
if (support) {
  for (const name in support) {
    const file = support[name];
    support[name] = path.join(global.codecept_dir, file);
  }
}

This change seems to inadvertently change entire Codecept class config in that is directly modifies Codecept.config values for each include by blindly concatenating the global.codecept_dir value to the beginning of the existing values. Since a reference to the object itself is sent in Config.get() the config is modified in place as opposed to having the operation made against a copy of the configuration.

I had only noticed this change when updating npm to pull directly from this GitHub repo (so as to take on my recently merged change prior to next package release). So I wanted to make sure and raise this issue before this change gets into next package release.

I did not propose a fix here, as I am not sure whether it was intended for the config to actually be modified here, in which case perhaps the prepending logic probable needs to include path resolution, or whether your were strictly trying to work from a copy of the config, in which case perhaps Config.get() need to use Object.assign() or similar, our a Config.copy() method need to be introduced.

Details

  • CodeceptJS version: Latest repo master version
  • NodeJS Version: 9.6
  • Operating System: Windows 7
  • Protractor || WebDriverIO || Nightmare version (if related)
  • Configuration file:
'use strict';

process.on('unhandledRejection', () => {
    console.log('Suppressed unhandled promise rejection. This is probably because an assertion failed.');
});

const path = require('path');
const ROOT_DIR = path.resolve(__dirname).split(path.sep + 'test')[0];
const TEST_DIR = path.join(ROOT_DIR, 'test', 'codecept-ui');
const LIB_DIR = path.join(TEST_DIR, 'lib');
const FRAGMENT_DIR = path.join(TEST_DIR, 'fragments');
const PAGE_DIR = path.join(TEST_DIR, 'pages');
const OUTPUT_DIR = path.join(ROOT_DIR, 'test-output');
const testUrl = 'http://localhost:8080';
const appRunner = require(path.join(LIB_DIR, 'app-runner'));
const testPattern = path.relative(ROOT_DIR, path.join(TEST_DIR, '*-test.js'));
const timeout = 10000;

const getRunCommand = () => {
    let runCommandIsNext = false;
    const codeceptRegex = /codecept\.js$/;
    for (const arg of process.argv) {
        if (runCommandIsNext === true) {
            return arg;
        }

        if (codeceptRegex.test(arg)) {
            runCommandIsNext = true;
        }
    }
};

const runCommand = getRunCommand();

const noOp = () => {};

exports.config = {
    output: OUTPUT_DIR,
    helpers: {
        Nightmare: {
            url: testUrl,
            waitForTimeout: timeout
        },
        NightmareExtended: {
            require: path.join(LIB_DIR, 'nightmare-extended-helper.js')
        }
    },
    include: {
        I: path.join(LIB_DIR, 'actor.js'),
        desktopToggleFragment: path.join(FRAGMENT_DIR, 'desktop-toggle.js'),
        headFragment: path.join(FRAGMENT_DIR, 'head.js'),
        headerNavMenuFragment: path.join(FRAGMENT_DIR, 'header-nav-menu.js'),
        headerSearchFragment: path.join(FRAGMENT_DIR, 'header-search.js'),
        languageToggleFragment: path.join(FRAGMENT_DIR, 'language-toggle.js'),
        page404: path.join(PAGE_DIR, '404.js'),
        homePage: path.join(PAGE_DIR, 'homepage.js'),
        offlinePage: path.join(PAGE_DIR, 'offline.js'),
        productFamilyOverviewPage: path.join(PAGE_DIR, 'product-family-overview.js'),
        productFamilyProductsPage: path.join(PAGE_DIR, 'product-family-products.js'),
        productFolder: path.join(PAGE_DIR, 'product-folder.js'),
        productFolderDescription: path.join(PAGE_DIR, 'product-folder-description.js'),
        productFolderSamplebuy: path.join(PAGE_DIR, 'product-folder-samplebuy.js'),
        productFolderTechnicaldocuments: path.join(PAGE_DIR, 'product-folder-technicaldocuments.js'),
        productFolderToolssoftware: path.join(PAGE_DIR, 'product-folder-toolssoftware.js')
    },
    bootstrap: (runCommand === 'run') ? appRunner.startApp : noOp,
    teardown: (runCommand === 'run') ? appRunner.closeApp : noOp,
    bootstrapAll: appRunner.startApp,
    teardownAll: appRunner.closeApp,
    hooks: [],
    tests: testPattern,
    timeout: timeout,
    name: 'ticom-mobile',
    multiple: {
        parallel: {
            chunks: (files) => {
                return files[0].reduce(
                    (arr, file) => {
                        arr.push([ file ]);
                        return arr;
                    },
                    []
                );
            },
            browsers: ['Nightmare']
        }
    }
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions