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

Testing server side code #427

Closed
wagerfield opened this issue Feb 12, 2018 · 2 comments
Closed

Testing server side code #427

wagerfield opened this issue Feb 12, 2018 · 2 comments

Comments

@wagerfield
Copy link

What problem does this feature solve?

This feature would solve the problem of testing Vue components in a server-side/node environment.

In cases where custom components, directives, mixins etc. need to perform different branches of logic depending on the environment in which they are run (browser or node) there is no way of testing the node branches currently.

Vue provides an $isServer instance property on each Vue component—this is useful for branching environment dependent logic:

const EnvText = {
  render(createElement) {
    const text = this.$isServer ? 'server' : 'client'
    return createElement('span', text)
  }
}

Though the example above is very contrived, there is currently no way of testing the server-side rendering branch of this component (that I know of).

The solution/hack I implemented to work around this problem overrides the prototype.$isServer for a localVue instance:

const setLocalVueEnv = (localVue, isServer) => {
  Object.defineProperty(localVue.prototype, '$isServer', {
    get: () => isServer
  })
}

test('server env', () => {
  const isServer = true
  const localVue = createLocalVue()

  setLocalVueEnv(localVue, isServer)

  const wrapper = mount(EnvText, { localVue })
  expect(wrapper.vm.$isServer).toBe(isServer)
  expect(wrapper.text()).toBe('server')
})

What does the proposed API look like?

Here are three API proposals I thought might work:

// Option 1: Pass options to createLocalVue
const localVue = createLocalVue({ isServer: true })

// Option 2: Pass a mounting option
const wrapper = mount(EnvText, { isServer: true })

// Option 3: Pass a mock property
const wrapper = mount(EnvText, {
  mocks: {
    $isServer: true
  }
})

NOTE: Assuming $isServer can be mocked/configured on the global Vue instance (I don't think it can) Option 1 would limit this feature to only working with localVue instances...that might be a good thing though?

@eddyerburgh
Copy link
Member

There's two problems here.

First, mount and shallow create DOM nodes, so they need a DOM environment. Instead, we could create a render function which would be a wrapper around 'vue-server-renderer' renderToString. This would return a string of the output, which you could load in cheerio to assert against.

Second, we should be able to mock $isServer. This might require a change to the code in Vue core for us to change the value on each mount/render.

@eddyerburgh
Copy link
Member

I've just published @vue/server-test-utils which includes the render and renderToSrtring methods. You run these in a node environment to test SSR code.

We're not going to add the ability to mock $isServer, since it requires a change to core. It would also make it possible for unit tests to pass, but fail in production, because you could run tests for SSR code in a client environment.

You can achieve the same thing by running your client-side and server-side unit tests in seperate processes.

If you use Jest, you can add this line to the top of the file:

/**
 * @jest-environment node
 */

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

No branches or pull requests

2 participants