2.5.21
https://github.com/futureaus/servue/tree/min-rep
npm install --dev
jest
.vue file to render correctly
× 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
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
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
no, because it would require people to explicitly mock $isServer to false which is the most common use case
@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.
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 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
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
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. 🙂
Most helpful comment
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,$isServerreturns 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..