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

Vite compatible Jest preset #1149

Closed
softbeehive opened this issue Nov 26, 2020 · 17 comments
Closed

Vite compatible Jest preset #1149

softbeehive opened this issue Nov 26, 2020 · 17 comments
Labels
enhancement New feature or request

Comments

@softbeehive
Copy link

Is your feature request related to a problem? Please describe.

I'm migrating a large codebase to Vue 3 + Vite. The project contains tests I'd like to reuse. But due to the limited ESM support Jest throws an error every time import.meta.env is used in components, vuex actions, api helpers. Apart from that experience is pretty smooth.

For example (in tests):

timeout: import.meta.env.VITE_API_CONFIG_TIMEOUT
                      ^^^^
SyntaxError: Cannot use 'import.meta' outside a module

Describe the solution you'd like

I'd like to use process.env until ESM support in Jest is complete. Allowing environment variables with VITE_ prefix. As far as I can see in config.ts, the choice is made in favour of import.meta. Would you consider adding a config flag that will allow env customization?

Describe alternatives you've considered

Snowpack, because similar issue has already been addressed
FredKSchott/create-snowpack-app#120

jest.config.js

module.exports = {
  coverageDirectory: 'coverage',
  moduleFileExtensions: ['vue', 'js', 'json'],
  moduleNameMapper: {
    '^/@/(.*)$': '<rootDir>/src/$1',
  },
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '^.+\\js$': 'babel-jest',
  },
}

babel.config.js

module.exports = {
  env: {
    test: {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: {
              node: 'current',
            },
          },
        ],
      ],
    },
  },
}

P.S. I'm happy to provide a reproduction if needed

@yyx990803
Copy link
Member

yyx990803 commented Jan 8, 2021

This is not really a Vite issue - since when running your Jest tests, Jest directly loads and processes your source code without Vite getting involved at all.

What you need is adding a babel plugin like this one (you may need to tweak it a bit) to your babel config.

Alternatively, open an issue at Jest to ask them to support this by default.

@yyx990803 yyx990803 changed the title Allow on-demand exposure of VITE_ prefixed variables to process.env Vite compatible Jest preset Jan 8, 2021
@yyx990803 yyx990803 reopened this Jan 8, 2021
@yyx990803
Copy link
Member

On another thought, there could probably be an official Jest preset to make Jest vite-compatible.

@yyx990803 yyx990803 added the enhancement New feature or request label Jan 8, 2021
@padcom
Copy link

padcom commented Jan 12, 2021

Honestly, the only thing stopping me from widely adopting Vite as the build tool is the lack of templates with unit tests and end to end tests. I've been trying to get something done myself but apparently I don't know the area good enough to accomplish that. I suppose I am not alone in it.

Having the option to scaffold a project with unit tests using either mocha+chai or jest and e2e tests with cypress or some selenium-based library would make it far easier to make Vite the choice for a new project.

@padcom
Copy link

padcom commented Jan 12, 2021

It'd be even cooler if those could be plugins that one would need to install and those plugins would then add functionality. I've been dying to get that kind of modularity for ages and nowadays it is only possible with vue-cli managed projects - hence I'm sticking to that.

@zxwild
Copy link

zxwild commented Feb 1, 2021

It seems I've found at last the plugin which is able to implement import.meta, it's babel-plugin-transform-import-meta.
So all is needed in my case is:

  1. npm install --save-dev babel-plugin-transform-import-meta
  2. babel.config.js modification
module.exports = {
  plugins: [
    'babel-plugin-transform-import-meta',
  ],
  // or to:
  // env: { test: plugins: [...] }
}

Previously I had:

ERROR: unknown: import.meta may appear only with 'sourceType: "module"' (110:20)
> 110 |   createWebHistory)(import.meta.env.BASE_URL),

Now all is ok.

@threepointone
Copy link
Contributor

Keeping an eye on this, feel like it's one of the last big pieces for vite to embrace. Happy to contribute too. I'll have a go at making a jest preset soon, including their fancy hoisting plugin.

@frandiox
Copy link
Contributor

frandiox commented Feb 8, 2021

I could make it work with the following inline plugin in babel.config.js:

// Only used by Jest
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      { useBuiltIns: 'entry', corejs: '2', targets: { node: 'current' } },
    ],
    '@babel/preset-typescript',
  ],
  plugins: [
    function () {
      return {
        visitor: {
          MetaProperty(path) {
            path.replaceWithSourceString('process')
          },
        },
      }
    },
  ],
}

It basically replaces import.meta.env with process.env. Note it doesn't populate process.env.MODE.

Also, make sure to tell vue-jest to use Babel:

// jest.config.js
globals: {
  'vue-jest': {
    babelConfig: true,
  },
},

And, in case you are testing different configurations, run Jest with --no-cache parameter to avoid wasting hours 🤦

@aelbore
Copy link
Contributor

aelbore commented Feb 15, 2021

Honestly, the only thing stopping me from widely adopting Vite as the build tool is the lack of templates with unit tests and end to end tests. I've been trying to get something done myself but apparently I don't know the area good enough to accomplish that. I suppose I am not alone in it.

Having the option to scaffold a project with unit tests using either mocha+chai or jest and e2e tests with cypress or some selenium-based library would make it far easier to make Vite the choice for a new project.

@padcom i created a vite-plugin that can test your component with mocha+chai+puppeteer (its compatible with vue, react and lit-element component)
you can check this repo

https://github.com/aelbore/vite-plugin-test

hope you can give any feedback :)

@padcom
Copy link

padcom commented Feb 16, 2021

@aelbore Thanks! I've checked it and seems to be working! Thank you!

However, I am mostly using Jest for my tests. Would you be able to create a similar plugin just for use with Jest?

@bartenra
Copy link

I got it to work by just following the Jest docs.

I just had to install and configure Babel:

https://jestjs.io/docs/en/getting-started

For ESM module support, run with

NODE_OPTIONS=--experimental-vm-modules npx jest

as described here: https://jestjs.io/docs/en/ecmascript-modules

@patak-dev
Copy link
Member

Closing this one to keep discussions in a single issue #1955

@mariusa
Copy link

mariusa commented Apr 20, 2021

Unrelated to jest, I get the same error in vscode when editing .vue files:

<div v-if="import.meta.env.VITE_APP_USER_MODE != 'single'">test</div>

import.meta may appear only with 'sourceType: "module"'

and vite shows this error in console

[vite] Internal server error: avoid using JavaScript keyword as property name: "import"
  Raw expression: v-if="import.meta.env.VITE_APP_USER_MODE != 'single'"

I know the workaround is to declare a new variable in data() which has the value of VITE_APP_... . Would there be another way to use VITE_APP_ in templates directly?

@padcom
Copy link

padcom commented Apr 21, 2021

@mariusa Do a computed property that exposes the env variable:

computed: {
  mode() {
    return import.meta.env.VITE_APP_USER_MODE
  }
}

@mariusa
Copy link

mariusa commented Apr 21, 2021

Thanks @padcom . That works, setting it in data also works (less typing than computed).
Would have preferred to use directly the env var in template, as vue-cli used to work via process.env.VUE_APP_

@padcom
Copy link

padcom commented Apr 21, 2021

@mariusa The difference is that a computed property behaves the same as the meta import - it's read-only. A data item is reactive and read/write, which would have a different semantic that the meta import

@jongbelegen
Copy link

jongbelegen commented Jun 9, 2021

I'm using jest with react typescript. Making ts-jest compatible with meta.import seemed like a huge effort currently.

I choose to make Vite act 'backward compatible' by bringing process.env back to Vite. You can achieve this by making use of "define" in vite.config.ts. for example:

import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())

  // expose .env as process.env instead of import.meta since jest does not import meta yet
  const envWithProcessPrefix = Object.entries(env).reduce(
    (prev, [key, val]) => {
      return {
        ...prev,
        ['process.env.' + key]: `"${val}"`,
      }
    },
    {},
  )

  return {
    define: envWithProcessPrefix,
  }
})

At that point you can replace any import.meta.env.VITE_... to process.env.VITE_...

Note that with this approach object destructuring does not work in your build process:

// Works
const SOME_KEY = process.env.SOME_KEY

// Does not work
const {
  SOME_KEY,
} = process.env

@github-actions
Copy link

This issue has been locked since it has been closed for more than 14 days.

If you have found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest Vite version. If you have any other comments you should join the chat at Vite Land or create a new discussion.

@github-actions github-actions bot locked and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests