Mukul Gupta
Mukul Gupta

Reputation: 2425

How to import relative source code in cypress using typescript for an ESM project?

My typescript project ("type":"module") is organised as follows:

app
  - src
    - utils
      - util.ts
    - other-code
  - cypress
    - e2e
      - spec.cy.ts
  package.json

I'm trying to import util.ts from spec.cy.ts using

import { utilA } from "../../src/utils/util.js";

and encounter a Webpack compilation error: Module not found. Note that this is NOT a typo but a deliberate fully qualified ESM import as is recommended by typescript. Assume that utilA can have recursive dependencies all using ESM-style imports. Therefore, modifying the import statement to import { utilA } from "../../src/utils/util.ts"; or (extensionless version) import { utilA } from "../../src/utils/util"; is not feasible.

I believe this is related to typescript compiler settings for cypress. How can I modify it? Modifying tsconfig.json inside the cypress folder to the following doesn't have effect.

{
    "compilerOptions": {
      "target": "es6",
      "lib": ["es6", "dom"],
      "types": ["cypress", "node"],
      "module": "NodeNext",
      "moduleResolution": "NodeNext"
    },
    "include": ["**/*.ts"]
}

I'm using typescript 5.2 and cypress 13.

EDIT 1: A sample project that reproduces the issue can be found here. Adding a tsconfig.json under cypress directory doesn't seem to take into account module compiler options.

Upvotes: 0

Views: 553

Answers (1)

Mukul Gupta
Mukul Gupta

Reputation: 2425

Apparently, this was a known issue which should have been solved after cypress upgraded to webpack v5. However, as of cypress 13.6.3, it continues to be a bug.

As suggested here, I used @cypress/webpack-preprocessor to resolve it.

import { defineConfig } from "cypress";
import webpackPreprocessor from "@cypress/webpack-preprocessor";
export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      let options = webpackPreprocessor.defaultOptions;
      const customOptions = {
        webpackOptions: {
          resolve: {
            extensionAlias: {
              '.js': ['.ts', '.js'],
            }
          }
        }
      };
      options.webpackOptions = {
        ...options.webpackOptions,
        ...customOptions.webpackOptions,
      }
      options.webpackOptions.module?.rules?.push({
          // every time webpack sees a TS file (except for node_modules)
          // webpack will use "ts-loader" to transpile it to JavaScript
          test: /\.ts$/,
          exclude: [/node_modules/],
          use: [
            {
              loader: 'ts-loader',
              options: {
                // skip typechecking for speed
                transpileOnly: true,
              },
            },
          ],
        });
      on('file:preprocessor', webpackPreprocessor(options));
    },
  },
});

Note that this also required installing webpack, ts-loader, @babel/core, @babel/preset-env as devDependencies.

Upvotes: 0

Related Questions