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

Feature request: Trigger onServerPrefetch from test #1321

Closed
ferencbeutel4711 opened this issue Feb 15, 2022 · 11 comments
Closed

Feature request: Trigger onServerPrefetch from test #1321

ferencbeutel4711 opened this issue Feb 15, 2022 · 11 comments
Labels
enhancement New feature or request

Comments

@ferencbeutel4711
Copy link

Is your feature request related to a problem? Please describe.
Currently, it seems that there is no way to test the behaviour of the function defined in onServerPrefetch

Describe the solution you'd like
It would be great if there was a way to trigger the serverPrefetch lifecycle hook from the tests

Additional context

Hey, maybe I am mistaken, but I cant see a way to test the behaviour I have defined in the onServerPrefetch lifecycle hook defined in a setup function in my component. With the options API, this was possible, using the following approach:

wrapper.vm.$options.serverPrefetch()

However, I can see no replacement that can be used for the composition api.

@ferencbeutel4711 ferencbeutel4711 changed the title Feature request: Feature request: Trigger onServerPrefetch from test Feb 15, 2022
@lmiller1990
Copy link
Member

Probably dup of #1218?

@lmiller1990 lmiller1990 added the enhancement New feature or request label Feb 16, 2022
@cexbrayat
Copy link
Member

@ferencbeutel4711 Thanks for the request. I agree with Lachlan, I think we need to add SSR support and then that should give you a way to test the onServerPrefetch function.

Would you like to give it a try?

as @lmiller1990 pointed out, the implementation should be fairly close towhat VTU v1 was doing here https://github.com/vuejs/vue-test-utils/blob/dev/packages/server-test-utils/src/renderToString.js

and you can also take inspiration in what vue core does https://github.com/vuejs/core/blob/9c304bfe7942a20264235865b4bb5f6e53fdee0d/packages/runtime-test/src/index.ts

We would gladly accept a PR!

@wobsoriano
Copy link
Contributor

wobsoriano commented May 25, 2022

Could something like this work?

import { createSSRApp, h } from 'vue'
import { renderToString as baseRenderToString } from '@vue/server-renderer'

function renderToString(component, options) {
  // Copy contents of mount function to get props, refs, slots
  const props = {}
  const refs = {}
  const slots = {}

  const Parent = createSSRApp({
    name: 'VTU_ROOT',
    render() {
      return h(component, { ...props, ...refs }, slots)
    }
  })
  
  return baseRenderToString(Parent)
}

@lmiller1990
Copy link
Member

I was expecting something like that @wobsoriano - would you like to make a PR and add a few tests? Likely this is something we will build incrementally and add features as needed, but this seems like a great starting point.

@wobsoriano
Copy link
Contributor

wobsoriano commented Jun 2, 2022

@lmiller1990 I'll try. Looking at the renderToString implementation in VTU 1, it's using a shared createInstance that's also used by mount function. In order to implement it, I think the logic here needs to be shared too?

Or maybe something like this would suffice?

import { mount } from '@vue/test-utils'
import { renderToString as baseRenderToString } from '@vue/server-renderer'

export function renderToString(...args: Parameters<typeof mount>) {
  const wrapper = mount(...args)
  return baseRenderToString(wrapper.getCurrentComponent().vnode)
}

wrapper.getCurrentComponent().vnode is the parent component if I'm correct

@lmiller1990
Copy link
Member

Yep, we likely want all the usual mounting options to work in the same way, so you might need to move some things around. Specifically, I guess we won't want the final mount() call here https://github.com/vuejs/test-utils/blob/main/src/mount.ts#L520, since we are not mounting the component. Instead, that will be the rendertoString call. You could either inject a function to be called there, or move that somewhere else, splitting it out of mount.

It'll be a bit of effort, I'm sure some other things will pop up, I'm here to lend a hand. This is a high impact feature, thanks for taking the time to look into it!

@wobsoriano
Copy link
Contributor

Thanks @lmiller1990! So without moving much stuff around, the easiest way to implement would be adding another property to the mount options I guess? Something like

const MOUNT_OPTIONS: Array<keyof MountingOptions<any>> = [
  // other options,
  'renderToString'
]

export function mount(componentOptions, options) {
  // ...
  if (options?.renderToString) {
    return renderToString(app)
  }

  // mount the app!
  const vm = app.mount(el)

  // ...
}

export const renderToString: typeof mount = (component: any, options?: any) => {
  return mount(component, { ...options, renderToString: true })
}

@lmiller1990
Copy link
Member

lmiller1990 commented Jun 2, 2022

Oh interesting, had not thought about doing it that way. It's better than what I had in mind. I like this - it follows the pattern we have for shallow:

export const shallowMount: typeof mount = (component: any, options?: any) => {
  return mount(component, { ...options, shallow: true })
}

I'm guessing one of the things we want to test is if the onServerPrefetch function is correctly called (I assume it should be, although I haven't actually used Vue 3's SSR yet).

@wobsoriano
Copy link
Contributor

I'll play around and do some tests!

@wobsoriano
Copy link
Contributor

Initial PR #1572

@cexbrayat
Copy link
Member

This should now be fixed with the latest VTU versions, as renderToString is now available!

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

No branches or pull requests

4 participants