Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not setup and configure with Vite / React / TS+SWC #1093

Closed
3 tasks done
mpavel opened this issue Sep 11, 2023 · 11 comments
Closed
3 tasks done

Can not setup and configure with Vite / React / TS+SWC #1093

mpavel opened this issue Sep 11, 2023 · 11 comments

Comments

@mpavel
Copy link

mpavel commented Sep 11, 2023

Current behavior

Unable to configure and run after creating new project with vite.

Desired behavior

The configuration should work for new projects created with vite.

Test code to reproduce

$ npm create vite
-> test
-> React
-> Typescript + SWC

$ npm i

$ npm i -D cypress # running, working, all good with the demo tests

$ npm i -D @badeball/cypress-cucumber-preprocessor

$ npm i -D @bahmutov/cypress-esbuild-preprocessor

Cypress configuration according to docs:

import { defineConfig } from "cypress";
import createBundler from "@bahmutov/cypress-esbuild-preprocessor";
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
import createEsbuildPlugin from "@badeball/cypress-cucumber-preprocessor/esbuild";

async function setupNodeEvents(
    on: Cypress.PluginEvents,
    config: Cypress.PluginConfigOptions
): Promise<Cypress.PluginConfigOptions> {
    // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
    await addCucumberPreprocessorPlugin(on, config);

    on(
        "file:preprocessor",
        createBundler({
            plugins: [createEsbuildPlugin(config)],
        })
    );

    // Make sure to return the config object as it might have been modified by the plugin.
    return config;
}

export default defineConfig({
    e2e: {
        baseUrl: "https://duckduckgo.com",
        specPattern: "**/*.feature",
        setupNodeEvents,
    },
});

When I start Cypress, there are two errors:

import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Named export 'addCucumberPreprocessorPlugin' not found.

This can be fixed easily by modifying the import as follows:

import preprocessor from "@badeball/cypress-cucumber-preprocessor";
const { addCucumberPreprocessorPlugin } = preprocessor

Once fixed, we move to the next error:

TypeError: createEsbuildPlugin is not a function
    at setupNodeEvents

Link to repository to reproduce: https://github.com/mpavel/vite-react-ts-swc-cypress-bdd

tsconfig has been updated to contain node16 and it didn't work.

    "module": "node16",
    "moduleResolution": "node16",

The original values coming from vite are:

    "module": "ESNext",
    "moduleResolution": "bundler",

I've added the "paths" to tsconfig and it didn't work:

    "paths": {
      "@badeball/cypress-cucumber-preprocessor/*": [
        "./node_modules/@badeball/cypress-cucumber-preprocessor/dist/subpath-entrypoints/*"
      ]
    }

I've renamed cypress.config.ts to cypress.config.js and it still didn't work.

Versions

  • Cypress version: ^13.1.0
  • Preprocessor version: ^18.0.5
  • Node version: v18.16.1

Checklist

  • I've read the FAQ.
  • I've read instructions for logging issues.
  • I'm not using cypress-cucumber-preprocessor@4.3.1 (package name has changed and it is no longer the most recent version, see #689).
@badeball
Copy link
Owner

The configuration should work for new projects created with vite.

This is not even remotely true, nor something I consider a requirement. Vite can create whatever TS configuration they want and it's not necessarily going to fit all. Your example works by applying the following patch. If you want to retain type: module, then you also need to understand the implications of it. However, I won't be your guide through this.

diff --git a/cypress.config.js b/cypress.config.ts
similarity index 86%
rename from cypress.config.js
rename to cypress.config.ts
index 24fa4f1..8d41b54 100644
--- a/cypress.config.js
+++ b/cypress.config.ts
@@ -1,9 +1,7 @@
 import { defineConfig } from 'cypress';
 import createBundler from '@bahmutov/cypress-esbuild-preprocessor';
 import createEsbuildPlugin from '@badeball/cypress-cucumber-preprocessor/esbuild';
-import preprocessor from '@badeball/cypress-cucumber-preprocessor';
-
-const { addCucumberPreprocessorPlugin } = preprocessor
+import { addCucumberPreprocessorPlugin }  from '@badeball/cypress-cucumber-preprocessor';
 
 async function setupNodeEvents(on, config) {
     // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
diff --git a/package.json b/package.json
index dc0044b..797e9ec 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,6 @@
   "name": "learn-vite-react-cypress",
   "private": true,
   "version": "0.0.0",
-  "type": "module",
   "scripts": {
     "dev": "vite",
     "build": "tsc && vite build",
diff --git a/tsconfig.json b/tsconfig.json
index 04139d1..03977b6 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,11 +3,11 @@
     "target": "ES2020",
     "useDefineForClassFields": true,
     "lib": ["ES2020", "DOM", "DOM.Iterable"],
-    "module": "ESNext",
+    "module": "nodenext",
+    "esModuleInterop": true,
     "skipLibCheck": true,
 
     /* Bundler mode */
-    "moduleResolution": "bundler",
     "allowImportingTsExtensions": true,
     "resolveJsonModule": true,
     "isolatedModules": true,

@badeball
Copy link
Owner

For the extremely curious - TS's output of named exports is sometimes not detected by Node's internal lexer (https://github.com/nodejs/cjs-module-lexer), ref. nodejs/cjs-module-lexer#76. This is (one of the reasons) why using type: module can sometimes be difficult.

@mpavel
Copy link
Author

mpavel commented Sep 13, 2023

Thank you very much for looking into this!

I agree that there are so many TS configurations out there and it's impossible to keep track of everything.

Since vite is gaining traction I was thinking it would be nice to have a more seamless DX when it comes to installing Cypress and setting up this plugin. That's the reason I opened up this issue. Also with the idea that it will help some future developer debug things if needed 😊

I will put below, for reference, the changes that made things work for me.

// cypress.config.ts
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
import createBundler from "@bahmutov/cypress-esbuild-preprocessor";
import { defineConfig } from "cypress";

// note: import had to be adjusted, compared to the ones in examples
const { createEsbuildPlugin } = require("@badeball/cypress-cucumber-preprocessor/esbuild");

async function setupNodeEvents(
  on: Cypress.PluginEvents,
  config: Cypress.PluginConfigOptions
): Promise<Cypress.PluginConfigOptions> {
  // This is required for the preprocessor to be able to generate JSON reports after each run, and more,
  await addCucumberPreprocessorPlugin(on, config);

  on(
    "file:preprocessor",
    createBundler({
      plugins: [createEsbuildPlugin(config)],
    })
  );

  // Make sure to return the config object as it might have been modified by the plugin.
  return config;
}

export default defineConfig({
  e2e: {
    baseUrl: "https://duckduckgo.com",
    specPattern: "**/*.feature",
    setupNodeEvents,
  },
});

In package.json, remove "type": "module" (which basically defaults to commonjs)

In tsconfig.json and tsconfig.node.js, remove "moduleResolution": "bundler" and add "esModuleInterop": true.

@badeball , should I open a PR to update the vite example? I'm especially looking at the import in the cypress.config.ts, but maybe also to include references to the other required changes.

badeball added a commit that referenced this issue Sep 13, 2023
This is kind of an internal example and currently exists merely to
ensure that this setup never breaks.

Related to #1093 [1].

[1] #1093
@badeball
Copy link
Owner

For reference - I've updated the default exports to play nicer with ESM (834b65b).

@badeball , should I open a PR to update the vite example? I'm especially looking at the import in the cypress.config.ts, but maybe also to include references to the other required changes.

I'm not sure what you think needs to be changed in the example.

@mpavel
Copy link
Author

mpavel commented Oct 23, 2023

@badeball , as written above in the code, the import doesn't work as it's in the example, but must be adjusted in the following way:

// note: import had to be adjusted, compared to the ones in examples
const { createEsbuildPlugin } = require("@badeball/cypress-cucumber-preprocessor/esbuild");

This happens after making the configuration changes I mentioned:

In package.json, remove "type": "module" (which basically defaults to commonjs)
In tsconfig.json and tsconfig.node.js, remove "moduleResolution": "bundler" and add "esModuleInterop": true.

This is something I wanted to highlight that might be worth changing in the documentation. Or in the source code 😄 This is the VSCode error:
image

From my side it's fine, I figured it out now and I know how to work around it, by changing the import. 😊

@badeball
Copy link
Owner

What example are you referring to?

@mpavel
Copy link
Author

mpavel commented Oct 23, 2023

The import above works, once "paths" are added like mentioned in the documentation, but it's just TS complaining about the imports.
I also found that this can be solved with creating a declarations file at root level:

// global.d.ts
declare module '@badeball/cypress-cucumber-preprocessor/esbuild';

@mpavel
Copy link
Author

mpavel commented Oct 23, 2023

@badeball
Copy link
Owner

Well, createEsbuildPlugin doesn't originate from @bahmutov/cypress-esbuild-preprocessor, nor does the example suggest so. So, what's the problem here?

@mpavel
Copy link
Author

mpavel commented Oct 23, 2023

The main problem I had was trying to find a configuration that works, especially with Vite. This is solved and your first comment helped with this. Thank you!

@stuaylward
Copy link

I ran into the same problem. "type":"module" in package.json was needed to run the project with Vite, but needed to be removed to run Cypress with the cucumber-preprocessor.

If you rename the vite.config.ts file to vite.config.mjs. You don't need to add "type":"module" to your package.json file and the project runs, and so does Cypress. (at least in my case, hopefully this helps someone!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants