cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.43k stars 3.14k forks source link

The "paths[1]" argument must be of type string #28997

Open petergaal91 opened 4 months ago

petergaal91 commented 4 months ago

Current behavior

Since angular 17 if we use an application builder the output folder will be "dist/path/browser". If you want to build into the "dist/path" folder - like in the previous version with browser builder - you need to update the outputPath to:

{
...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:application",
    "options": {
      "outputPath": {
        "base": "dist/path",
        "browser": ""
      }
      "index": "src/index.html",
      "browser": "src/main.ts"
    }
  }
}      
...
}

If I do this I get the following error at angular component test config initialization step:

TypeError [ERR_INVALID_ARG_TYPE]: The "paths[1]" argument must be of type string. Received an instance of Object
    at new NodeError (node:internal/errors:406:5)
    at validateString (node:internal/validators:162:11)
    at Object.resolve (node:path:1101:7)
    at getCommonConfig (/Users/xyz/project/node_modules/@angular-devkit/build-angular/src/tools/webpack/configs/common.js:275:24)
    at async Promise.all (index 0)
    at async generateWebpackConfig (/Users/xyz/project/node_modules/@angular-devkit/build-angular/src/utils/webpack-browser-config.js:60:22)
    at async generateBrowserWebpackConfigFromContext (/Users/xyz/project/node_modules/@angular-devkit/build-angular/src/utils/webpack-browser-config.js:117:20)
    at async getAngularCliWebpackConfig (/Users/xyz/Library/Caches/Cypress/13.6.4/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-dev-server/dist/helpers/angularHandler.js:165:24)
    at async angularHandler (/Users/xyz/Library/Caches/Cypress/13.6.4/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-dev-server/dist/helpers/angularHandler.js:205:27)
    at async getPreset (/Users/xyz/Library/Caches/Cypress/13.6.4/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-dev-server/dist/devServer.js:94:20)
    at async Function.devServer.create (/Users/xyz/Library/Caches/Cypress/13.6.4/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-dev-server/dist/devServer.js:111:61)
    at async /Users/xyz/Library/Caches/Cypress/13.6.4/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-dev-server/dist/devServer.js:26:24

I think outputPath as an object not handled correctly in this case.

Desired behavior

No response

Test code to reproduce

  1. Generate a fresh angular 17 project
  2. Update the angular.json build target outputPath to the following:
    "outputPath": {
    "base": "dist/path",
    "browser": ""
    }
  3. Configure angular component test in angular.json and use the updated build target:
    "component-test": {
      "executor": "@nx/cypress:cypress",
      "options": {
        "cypressConfig": "./cypress.config.ts",
        "devServerTarget": "project:build",
        "testingType": "component"
        "skipServe": true
      }
    }

Cypress Version

13.6.4

Node version

20.9.0

Operating System

macOS 14.3.1

Debug Logs

No response

Other

No response

bauerbua commented 3 months ago

What you can do as a workaround for now is to manually define the outputPath in devServer config in cypress.config.ts

devServer: {
    framework: 'angular',
    bundler: 'webpack',
    options: {
        projectConfig: {
            root: './',
            sourceRoot: 'src',
            buildOptions: {
              outputPath: 'dist/browser',
             /** other options **/
         }
    }
}
poveu commented 1 month ago

It's worth noting that those "other options" @bauerbua mentioned, are usually options from angular.json projects.*whatever*.architect.build.options (that could be automatically retrieved and appended to the buildOptions). In my case it's:

import { defineConfig } from 'cypress';
import * as fs from 'node:fs';

const angularConfig = fs.readFileSync('angular.json', 'utf8');
const angularJson = JSON.parse(angularConfig);
const buildOptions = angularJson.projects.ui.architect.build.options;

export default defineConfig({
    e2e: {
        projectId: 'ui',
        baseUrl: 'http://localhost:4200',
    },
    component: {
        devServer: {
            framework: 'angular',
            bundler: 'webpack',
            options: {
                projectConfig: {
                    root: '',
                    sourceRoot: 'src',
                    buildOptions: {
                        ...buildOptions,
                        outputPath: 'dist/ui',
                    },
                },
            },
        },
    },
});