Skip to content

vm.$isServer returns false when using Jest in testEnvironment Node #9232

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

Closed
AlbertMarashi opened this issue Dec 20, 2018 · 9 comments
Closed

Comments

@AlbertMarashi
Copy link

AlbertMarashi commented Dec 20, 2018

Version

2.5.21

Reproduction link

https://github.com/futureaus/servue/tree/min-rep

Steps to reproduce

npm install --dev
jest

What is expected?

.vue file to render correctly

What is actually happening?

  × renders file correctly (2710ms)

  ● renders file correctly

    ReferenceError: head is not defined

      at Object.eval (eval at <anonymous> (node_modules/lodash.template/index.js:1089:12), <anonymous>:8:11)
      at TemplateRenderer.renderSync (node_modules/vue-server-renderer/build.js:8020:16)
      at RenderContext.done (node_modules/vue-server-renderer/build.js:8264:39)
      at RenderContext.next (node_modules/vue-server-renderer/build.js:2459:19)
      at RenderContext.cachedWrite [as write] (node_modules/vue-server-renderer/build.js:2323:9)
      at RenderContext.next (node_modules/vue-server-renderer/build.js:2473:25)
      at cachedWrite (node_modules/vue-server-renderer/build.js:2323:9)
      at renderStringNode$1 (node_modules/vue-server-renderer/build.js:7599:5)
      at RenderContext.renderNode (node_modules/vue-server-renderer/build.js:7402:5)
      at RenderContext.next (node_modules/vue-server-renderer/build.js:2469:23)
      at cachedWrite (node_modules/vue-server-renderer/build.js:2323:9)
      at renderElement (node_modules/vue-server-renderer/build.js:7642:5)
      at renderNode (node_modules/vue-server-renderer/build.js:7406:5)
      at renderComponentInner (node_modules/vue-server-renderer/build.js:7524:3)
      at renderComponent (node_modules/vue-server-renderer/build.js:7488:5)
      at renderNode (node_modules/vue-server-renderer/build.js:7404:5)

undefined
Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        4.839s, estimated 7s
Ran all test suites.

This only happens when using Jest, to test in a normal node environment use node tests/normal.js

Jest, or an error with the environment detection of Vue is causing global.process.env.VUE_ENV to return undefined instead of 'server'.

Jest is running in "testEnvironment" : "node"

The $isServer is being used in lib/imports/headify.js

@posva
Copy link
Member

posva commented Dec 20, 2018

Most of the tests in vue are written for front end, so it makes sense to have that variable to false by default. If you are interested in the check, it's done at src/core/util/env.js (search for isServerRendering). With vue test utils, you can change $isServer by using the mocks property in the options passed to mount and shallowMount

cc @eddyerburgh maybe you know something else I'm missing here

@posva posva closed this as completed Dec 20, 2018
@AlbertMarashi
Copy link
Author

AlbertMarashi commented Dec 21, 2018

@posva

vue-server-renderer sets VUE_ENV to server but it's not working on the node environment in Jest

Shouldn't vue respect Jest's node environment

@posva
Copy link
Member

posva commented Dec 21, 2018

no, because it would require people to explicitly mock $isServer to false which is the most common use case

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Dec 22, 2018

@posva it may be worth noting, I am using vue-server-renderer and creating a bundle renderer, i'm not looking to test vue files. How can I mock it this way, when vue-server-renderer is isolated?

There's no info anywhere about using vue-server-renderer and mocking a node environment anywhere for jest.

@LinusBorg
Copy link
Member

LinusBorg commented Dec 22, 2018

I think the issue is with docs, mainly., but the general ones for SSR, nothing jest-specific.

vue-server-renderer does set process.env.VUE_ENV = server. But you don't pass that environment variable into your app bundle, so inside of our bundle, it's not set, and consequently, $isServer returns false.

We need to update docs here: https://ssr.vuejs.org/guide/build-config.html#server-config

It's demonstrated in the hackernew repo (here) but shoul definitely be mentioned in the docs explicitly, of course..

@LinusBorg
Copy link
Member

See: vuejs/vue2-ssr-docs#218

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Dec 24, 2018

@LinusBorg thanks, this fixed my issue, however, I am still confused as to why this is required only in the jest environment, and not in normal node

@LinusBorg
Copy link
Member

LinusBorg commented Dec 25, 2018

I would assume it's because jest runs tests in individual sandboxed processes, so the code bundled by bundleRenderer, when run inside of a test, doesn't get the VUE_ENV variable that was assigned in another process during test setup.

The "normal node" code, on the other hand, runs the renderer in the same process, so it can access the env var that vue-server-renderer has set in that process.

My change to the webpack config will inject the env variable as a static string into the server bundle, so it doesn't really access global.process.env when rendering.

Bur for example, your jest test runs fine when setting the env variable externally:

VUE_ENV=server yarn jest

@loilo
Copy link

loilo commented Mar 29, 2019

I needed $isServer to be true just for one individual Vue instance in my tests. Temporarily overriding Vue.prototype.$isServer was not an option since it is not writable.

Eventually I've found a solution which might be interesting for others, therefore I'll share it here: I created a function which hotswaps a Vue instance's whole prototype and replaces it with a proxy of itself which returns true when asked for $isServer:

function enableSsr(vm) {
  Object.setPrototypeOf(
    vm,
    new Proxy(Object.getPrototypeOf(vm), {
      get: (target, key, receiver) => key === '$isServer'
        ? true
        : Reflect.get(target, key, receiver)
    })
  )
}

You can use it like this:

const vm = new Vue(...)

enableSsr(vm)

If you have to test mixins or similar stuff that relies on $isServer, you may need to run that function pretty early, in a beforeCreate hook:

new Vue({
  beforeCreate() {
    enableSsr(this)
  },

  // ...
})

Hope this helps. 🙂

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

4 participants