cypress icon indicating copy to clipboard operation
cypress copied to clipboard

`after:run` task cwd changed after 9 -> 10

Open AriPerkkio opened this issue 2 years ago • 6 comments

Current behavior

In after:run task, Cypress 10 is using the location of configuration file as current working directory. In Cypress 9 it is the root of project, or where the actual cypress run command is run.

After migrating from Cypress 9 to 10 some plugins I'm using started failing. They are relying on Cypress 9's functionality when it comes to current working directory, e.g. when reading files from disk.

I keep my cypress.config.ts in a separate folder - not in the project root.

/workspaces/vite-everything
└── config
   └── cypress
      ├── component-index.html
      ├── cypress.config.ts
      ├── support.component.ts
      └── support.ts
cypress run --component --config-file config/cypress/cypress.config.ts
// config/cypress/cypress.config.ts
setupNodeEvents(on) {
    on('after:run', () => {
        console.log('[after:run] cwd is', process.cwd());
        // > [after:run] cwd is /workspaces/vite-everything/config/cypress
    });
},

Desired behavior

The current working directory should match with Cypress 9.

/workspaces/vite-everything
└── config
   └── cypress
      ├── cypress.json
      ├── plugins.ts
      └── support.ts
cypress run-ct --config-file config/cypress/cypress.json
// config/cypress/plugins.ts
on('after:run', () => {
    console.log('[after:run] cwd is', process.cwd());
    // [after:run] cwd is /workspaces/vite-everything
});

Test code to reproduce

I run into this error in separate closed source project but here is another project for reproducing the issue:

  • https://github.com/AriPerkkio/vite-everything
  • Branch test/cypress-9-after-run-cwd for previous functionality: https://github.com/AriPerkkio/vite-everything/commit/0e282c86eefa3766f25b374f5562518e6ecce3db
  • Branch test/cypress-10-after-run-cwd for current funcionality: https://github.com/AriPerkkio/vite-everything/commit/dbead4b1c90a107f2dbea6cbea454d3ccc89e5da
yarn # Install dependencies
yarn test:component # Run Cypress Component Test Runner

Cypress Version

10.3.0

Other

No response

AriPerkkio avatar Jul 06 '22 08:07 AriPerkkio

I've noticed the same incorrect working directory in before:run as well fwiw (in Cy 10).

larimer avatar Jul 12 '22 15:07 larimer

I was able to reproduce this with the example repository provided

astone123 avatar Jul 13 '22 19:07 astone123

Seeing this as well. It is impacting the use of @cypress/code-coverage, since it tries to read the nyc config from package.json, but is now looking for that within the Cypress config dir, rather than project root as before.

jhpedemonte avatar Aug 09 '22 16:08 jhpedemonte

I ran with DEBUG=cypress:* and here's what I see:

  • Initially, I see it passing the correct cwd:

    cypress:cli spawn args [ '--no-sandbox', '--', '--run-project', '/Users/pedemonte/projects/myproject/client', '--config-file', 'cypress/config/ci.config.ts', '--testing-type', 'e2e', '--cwd', '/Users/pedemonte/projects/myproject/client', '--userNodePath', '/Users/pedemonte/.nvm/versions/node/v16.13.1/bin/node', '--userNodeVersion', '16.13.1' ] { detached: false, stdio: [ 'inherit', 'inherit', 'pipe' ] } +7ms

  • Later, it switches to the config dir (although --projectRoot is correct):

    cypress:lifecycle:ProjectConfigIpc fork child process { CHILD_PROCESS_FILE_PATH: '/Users/pedemonte/Library/Caches/Cypress/10.4.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/require_async_child.js', configProcessArgs: [ '--projectRoot', '/Users/pedemonte/projects/myproject/client', '--file', '/Users/pedemonte/projects/myproject/client/cypress/config/ci.config.ts' ], childOptions: { stdio: 'pipe', cwd: '/Users/pedemonte/projects/myproject/client/cypress/config', execPath: '/Users/pedemonte/.nvm/versions/node/v16.13.1/bin/node' } } +0ms

  • Finally, a custom console.log in a cypress plugin shows:

    processWorkingDirectory = /Users/pedemonte/projects/myproject/client/cypress/config

jhpedemonte avatar Aug 09 '22 16:08 jhpedemonte

It appears that this is an intentional (but undocumented?) change in 10.0 (see app-lifecycle.md), wherein the config file is now run in a separate process, with cwd changed to the config file's parent directory (rather than the project root). That would mean that plugins such as @cypress/code-coverage which expect to run within the project root will need to be updated.

jhpedemonte avatar Aug 09 '22 18:08 jhpedemonte

@jhpedemonte I also run into this issue when using @cypress/code-coverage. But this also came up with cypress-sonarqube-reporter. In both cases I was able to add work-arounds by prefixing all configurable paths with ../../.

I'm not familiar with internals of Cypress but I think this is not intentional. A simple process.chdir() on Cypress's side could fix this.

AriPerkkio avatar Aug 10 '22 05:08 AriPerkkio

As per #23209 one of the issue in this ticket indicates that this behavior is probably not intended. ie. the default value for config component.indexHtmlFile is broken as cypress will try to resolve cypress/cypress/support/component-index.html rather than just cypress/support/component-index.html (cypress dir added twice in the path).

gsouf avatar Aug 10 '22 08:08 gsouf

FYI, my current workaround (until this is fixed either here or by plugins) is the following:

function requirePluginWithProjectRoot(pluginPath, on, config) {
  if (config.projectRoot) {
    const cwd = process.cwd();
    process.chdir(config.projectRoot);
    require(pluginPath)(on, config);

    // revert to previous cwd
    process.chdir(cwd);
    return;
  }

  throw Error("config.projectRoot doesn't exist");
}

I only invoke this for @cypress/code-coverage, which is the only plugin I use that is affected by this:

requirePluginWithProjectRoot('@cypress/code-coverage/task', on, config);

jhpedemonte avatar Aug 10 '22 15:08 jhpedemonte

@jhpedemonte maybe it is simpler to keep the config file at the root until this is fixed?

gsouf avatar Aug 11 '22 08:08 gsouf

@gsouf that's best solution for now.

I really want to keep Cypress configuration file under a sub directory config/ since that's where I store configuration files for all sorts of tooling. So as a work-around I'm now using a separate configuration file in project root which simply imports the actual config. This way I don't need to apply any other work-arounds, e.g. prefixing all paths with .../../ or running process.chdir() anywhere.

<project-root>
├── cypress.config.ts
└── config
   └── cypress
      └── cypress.config.ts
// TODO: Remove when https://github.com/cypress-io/cypress/issues/22689 is fixed
export { default } from './config/cypress/cypress.config';

AriPerkkio avatar Aug 11 '22 09:08 AriPerkkio

any updates?

MorisR avatar Jul 23 '23 20:07 MorisR

@MorisR nope, whole --config-file is still broken in latest 13.3.0 release. I've found another work-around which does not require creating root level cypress config as in https://github.com/cypress-io/cypress/issues/22689#issuecomment-1211732120.

NPM adds INIT_CWD environment variable which can be used to fix this bug:

// Work-around for https://github.com/cypress-io/cypress/issues/22689
if (!process.env.INIT_CWD) throw new Error('Missing INIT_CWD from npm');
process.chdir(process.env.INIT_CWD);

I've been adding these lines to every single cypress.config.ts that are not in the root of the project:

<root>
├── package.json
├── src
└── test
   |
   ├── component
   |  ├── component-index.html
   |  ├── cypress.config.ts    # Work-around added here
   |  └── support.ts
   |
   ├── end-to-end
   |  ├── cypress.config.ts   # also here
   |  ├── some-tests-1
   |  └── some-tests-2
   |
   ├── integration
   |  ├── cypress.config.ts   # and here
   |  ├── some-tests-1
   |  └── some-tests-1
   |
   └── unit
      └── vitest.setup.ts

AriPerkkio avatar Sep 29 '23 09:09 AriPerkkio