Search code examples
javascriptunit-testingtestingwebpackcypress

Use alias imports in cypress component test for React typescript


We use alias imports in the application component folder, and in my component tests I need to use imports as well like this

import {InputField} from "@company/components/Input" 

But whenever I try to run cypress, it gives me this error

enter image description here

I have my folder structure like this

/project
  /cypress
    /plugins
      /index.js
    /components
      /input.component.tsx
      /input.cy.tsx
    tsconfig.json
  /src
    /components
       /input.tsx
       /button.tsx
       /form.tsx
  ...
  ...
  tsconfig.json
  tsconfig.paths.json

The tsconfig.paths.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@company/*": ["./src/*"]
    }
  }
}

The tsconfig.json in the project root folder has the below configuration

{
  "extends": "./tsconfig.paths.json",
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src", "cypress"],
  "exclude": []
}

The project/cypress/tsconfig.json

{
  "extends": "../tsconfig.json"
}

cypress.config.js

/* eslint-disable @typescript-eslint/no-var-requires */
import { defineConfig } from "cypress";

export default defineConfig({
  video: false,

  e2e: {
    // We've imported your old cypress plugins here.
    // You may want to clean this up later by importing these.
    setupNodeEvents(on, config) {
      return require("./cypress/plugins/index.js")(on, config);
    },
    baseUrl: "http://localhost:3000",
    experimentalSessionAndOrigin: true,
    watchForFileChanges: false,
  },

  viewportWidth: 1920,
  viewportHeight: 1080,

  component: {
    devServer: {
      framework: "create-react-app",
      bundler: "webpack",
    },
    setupNodeEvents(on, config) {
      return require("./cypress/plugins/index.js")(on, config);
    },
  },
});

cypress/plugins/index.js

const cypressTypeScriptPreprocessor = require('./cy-ts-preprocessor')

module.exports = on => {
  on('file:preprocessor', cypressTypeScriptPreprocessor)
}

And cypress/plugins/cy-ts-preprocessor.js

const wp = require("@cypress/webpack-preprocessor");
const path = require("path");
const webpackOptions = {
  resolve: {
    extensions: [".ts", ".js", ".tsx"],
    alias: {
      "@company": path.resolve(__dirname, "../../src"),
    },
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: [/node_modules/],
        use: [
          {
            loader: "ts-loader",
          },
        ],
      },
    ],
  },
};

const options = {
  webpackOptions,
};

module.exports = wp(options);


Solution

  • This tsconfig works in my own case.

    {
      "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "baseUrl": "src",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "isolatedModules": true,
        "jsx": "react-jsx",
        "lib": ["es6", "dom", "dom.iterable", "esnext"],
        "module": "esnext",
        "moduleResolution": "node",
        "noEmit": true,
        "noImplicitAny": true,
        "noImplicitThis": true,
        "noFallthroughCasesInSwitch": true,
        "paths": {
          "alias": ["./path/to-file.ts"]
        },
        "resolveJsonModule": true,
        "skipLibCheck": true,
        "strict": true,
        "strictNullChecks": true,
        "target": "ES2018"
      },
      "include": ["src", "cypress", "@testing-library/cypress"],
      "exclude": []
    }
    
    

    Switch to react-app-rewired and add a config-overrides.js file to the root of the project.

    const path = require("path");
    
    module.exports = {
      webpack: config => {
        config.resolve.alias["@company-alias"] = path.resolve(__dirname, "../../src");
        config.resolve.alias["@company-alias-components"] = path.resolve(__dirname, "src/components/index.ts");
    
        config.resolve.extensions.push(".ts", ".js", ".tsx");
    
        return config;
      }
    };