Skip to content

TypeScript + Fully-Specified ESM import fails in cy.task #20580

@karlhorky

Description

@karlhorky

Current behavior

Using cy.task fails when it is used along with TypeScript code which uses fully-specified ESM imports (imports using .js extension, where there is no matching .js file because all of the files are TypeScript files , see microsoft/TypeScript#41887 (comment)).

For example:

// website/cypress/plugins/index.ts
import { deleteUserByEmail } from '../../../database/queries/users';

export default function pluginConfig(on: Cypress.PluginEvents) {
  on('task', {
    async deleteUser(email) {
      return await deleteUserByEmail(email);
    },
  });
}
// database/queries/users.ts
import {sql} from '../util/connect.js'
// database/util/connect.ts
export async function sql() {}

Note the difference in file names above. As per microsoft/TypeScript#41887 (comment), this should work in TypeScript (already works when using tsc)

Error message:


  1) Employer sign up
       should sign up with new company and verify email:
     CypressError: `cy.task('deleteEmployer')` failed with the following error:

> Cannot find module '../util/connect.js'
Require stack:
- /Users/lukas/Documents/project/packages/database/queries/users.ts
- /Users/lukas/Documents/project/packages/website/cypress/plugins/index.ts
- /Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js
- /Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/index.js

https://on.cypress.io/api/task
      at http://localhost:3020/__cypress/runner/cypress_runner.js:162240:78
      at tryCatcher (http://localhost:3020/__cypress/runner/cypress_runner.js:13022:23)
      at Promise._settlePromiseFromHandler (http://localhost:3020/__cypress/runner/cypress_runner.js:10957:31)
      at Promise._settlePromise (http://localhost:3020/__cypress/runner/cypress_runner.js:11014:18)
      at Promise._settlePromise0 (http://localhost:3020/__cypress/runner/cypress_runner.js:11059:10)
      at Promise._settlePromises (http://localhost:3020/__cypress/runner/cypress_runner.js:11135:18)
      at _drainQueueStep (http://localhost:3020/__cypress/runner/cypress_runner.js:7729:12)
      at _drainQueue (http://localhost:3020/__cypress/runner/cypress_runner.js:7722:9)
      at Async.../../node_modules/bluebird/js/release/async.js.Async._drainQueues (http://localhost:3020/__cypress/runner/cypress_runner.js:7738:5)
      at Async.drainQueues (http://localhost:3020/__cypress/runner/cypress_runner.js:7608:14)
  From Your Spec Code:
      at Context.eval (http://localhost:3020/__cypress/tests?p=cypress/integration/employerSignUp.spec.ts:188:10)
  
  From Node.js Internals:
    Error: Cannot find module '../util/connect.js'
    Require stack:
    - /Users/lukas/Documents/project/packages/database/queries/users.ts
    - /Users/lukas/Documents/project/packages/website/cypress/plugins/index.ts
    - /Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js
    - /Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/index.js
        at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
        at Function.Module._load (node:internal/modules/cjs/loader:778:27)
        at Module.require (node:internal/modules/cjs/loader:999:19)
        at require (node:internal/modules/cjs/helpers:102:18)
        at Object.<anonymous> (/Users/lukas/Documents/project/packages/database/queries/users.ts:5:1)
        at Module._compile (node:internal/modules/cjs/loader:1097:14)
        at Module.m._compile (/Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/node_modules/ts-node/src/index.ts:607:4)
        at Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
        at Object.require.extensions.<computed> [as .ts] (/Users/lukas/Library/Caches/Cypress/9.5.1/Cypress.app/Contents/Resources/app/node_modules/ts-node/src/index.ts:610:10)
        at Module.load (node:internal/modules/cjs/loader:975:32)
        at Function.Module._load (node:internal/modules/cjs/loader:822:12)
        at Module.require (node:internal/modules/cjs/loader:999:19)
        at require (node:internal/modules/cjs/helpers:102:18)
        at /Users/lukas/Documents/project/packages/website/cypress/plugins/index.ts:30:37
        at processTicksAndRejections (node:internal/process/task_queues:96:5)
        at deleteEmployer (/Users/lukas/Documents/project/packages/website/cypress/plugins/index.ts:30:37)

Desired behavior

Fully-specified ESM imports using .js file extensions should work in TypeScript code

Two details:

  1. This will be fixed in one of the coming versions of ts-node feat(register): resolve .js to .ts in ts-node/register TypeStrong/ts-node#1361
  2. An old 8.5.4 version of ts-node is currently used in the macOS Cypress.app via the server package (apparently? I was surprised to find it there):
    "ts-node": "8.5.4",

Test code to reproduce

See above

Cypress Version

9.5.1

Other

It would be nice if Cypress also supported Node.js ESM code just generally, but I think there are other issues for that:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions