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

createLocalVue errorHandler Option #1670

Merged

Conversation

AtofStryker
Copy link
Contributor

@AtofStryker AtofStryker commented Aug 28, 2020

The purpose of this PR is to allow an errorHandler option for createLocalVue. The goal is to support an interface to allow for support over time as needed for Vue Global Config options.

createLocalVue({
  errorHandler(err, vm, info) {
    // catch errors on local vue instance here
  }
})

createLocalVue used to take a private argument, which was a vue instance. The public API does not use this _vue instance argument, but server-test-utils and test-utils both do. The first step to supporting this signature was to move create-local-vue to the shared directory and use the semantic _createLocalVue when referencing internally. The "new" createLocalVue (part of the public api) just wraps this by passing through undefined to get the default behavior as well as the propagated VueConfig.

It is worth noting that the VTU behavior for disallowing a global error handler is still valid. The way this feature works is by invoking the registered errorHandler in the VTU global error handler before throwing the error. The function traverses the components $parent up the tree, finds if a localVue instance exists, and if so, invoke the errorHandler option if one is defined. That can be seen here. The user defined errorHandler passed into localVue can also throw an error if desired, but is not recommended.

What kind of change does this PR introduce? (check at least one)

  • Bugfix
  • Feature
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change? (check one)

  • Yes
  • No

If yes, please describe the impact and migration path for existing applications:

The PR fulfills these requirements:

If adding a new feature, the PR's description includes:

Other information:

Rename createLocalVue to _createLocalVue to indicate private use
Allow VueConfig to be passed in via createLocalVue to be registered on the created vue instance
add findAllParentInstances method to traverse a component's parent to find globally registered
properties via createLocalVue
Pass localVue into mounted createLocalVue to register localVue properties on component
Call the user defined errorHandler created on the localVue instance via createLocalVue. This is
called in the VTU global error handler
add tests to createLocalVue errorHandler to test invocation on sync and async throws
Wrap async error test for createLocalVue errorHandler in try/finally to prevent global errors
Add additional type safety to find and error for older versions of vue that might propagate a vm
value of null/undefined
const error =
typeof errorOrString === 'object' ? errorOrString : new Error(errorOrString)

// If a user defined errorHandler was register via createLocalVue
// find and call the user defined errorHandler
const instancedErrorHandlers = findAllParentInstances(vm)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just move this into line 21 that already has the conditional check? A lot of the type checking is for older versions of Vue

export function findAllParentInstances(childVm: any) {
const instances = [childVm]

function getParent(_vm) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any ideas on how to avoid the closure here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to find the highest Vue with the custom errorHandler right? I somehow thought it would "just work" and we wouldn't need to reverse-traverse all the way up. I don't have another way to do this.

I think having the conditional is fine, no problem from my point of view

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmiller1990 correct. I thought it would work straight out of the box as well, but not exactly for reasons I am having trouble remembering. I want to say it has to do with how the vue instances behave on the component, but don't take my word for it 😅

instance.config = cloneDeep(Vue.config)

// if a user defined errorHandler is defined by a localVue instance via createLocalVue, register it
instance.config.errorHandler = config.errorHandler || Vue.config.errorHandler
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only line that has changed within the logic, IE adding config.errorHandler. If we do not feel confortable reviewing this due to scope of change, we can break out the shared move in a separate PR to more clearly see the change set

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shared is private anyway, this should be fine

*/
function _createLocalVue(
_Vue: Component = Vue,
config: VueConfig = {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added argument config: VueConfig = {}

@lmiller1990
Copy link
Member

Hi! This is a pretty large PR, please give me the weekend to review. I am excited for this feature.

@lmiller1990 lmiller1990 self-requested a review August 29, 2020 10:09
@AtofStryker
Copy link
Contributor Author

Hi! This is a pretty large PR, please give me the weekend to review. I am excited for this feature.

@lmiller1990 sure thing! I am excited about it too. Definitely no rush on review as we want to be thorough.

What we can do, since this is a fairly large PR where the change set is a bit difficult to determine, is break this out into 2 separate PRs:

1st PR (break out createLocalVue to shared and wrap the functionality around the new createLocalVue)

48f1c14
808fe89
fc3be6c
0dca580

2nd (implement the errorHandler)
everything else

I think this would be much easier to review as well as add confidence to what we are doing. What do you think?

@lmiller1990
Copy link
Member

I am happy to review a big PR, no dramas there.

@AtofStryker
Copy link
Contributor Author

@lmiller1990 OK cool! I just want to make it as easy as possible and willing to accommodate 😃

@lmiller1990
Copy link
Member

Sorry about the wait, I have a day off work this week to work on OSS (mainly VTU stuff).

I will review/merge and plan release 1.1 for this weekend.

@AtofStryker
Copy link
Contributor Author

@lmiller1990 no worries! Let me know if there is anything I can do to help.

Copy link
Member

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me - this was a ton of work! Great job. I wonder if this will be easier to do in VTU next. I was not expecting this to be so complicated (I don't think you were, either).

// e.g. router-link are created using the correct base constructor
instance.options._base = instance

// compat for vue-router < 2.7.1 where it does not allow multiple installs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice job, this must have been a huge pain to figure out

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, it was moved here from somewhere else - even better, that means it's been battle tested

instance.config = cloneDeep(Vue.config)

// if a user defined errorHandler is defined by a localVue instance via createLocalVue, register it
instance.config.errorHandler = config.errorHandler || Vue.config.errorHandler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shared is private anyway, this should be fine

export function findAllParentInstances(childVm: any) {
const instances = [childVm]

function getParent(_vm) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to find the highest Vue with the custom errorHandler right? I somehow thought it would "just work" and we wouldn't need to reverse-traverse all the way up. I don't have another way to do this.

I think having the conditional is fine, no problem from my point of view

@lmiller1990 lmiller1990 merged commit e91effe into vuejs:dev Sep 10, 2020
@AtofStryker
Copy link
Contributor Author

Looks fine to me - this was a ton of work! Great job. I wonder if this will be easier to do in VTU next. I was not expecting this to be so complicated (I don't think you were, either).

@lmiller1990 Thanks! Yeah... this was a lot more involved than I thought it would be 😅 . The first approach I took failed miserably 😆 . This seemed to be the way to get the behavior we need with the least amount of change (even though significant change was needed). I will say this is WAYYYY easier with VTU Next. This is what it looks like in VTU Next, which works exactly like you would expect it to 🙂 .

@lmiller1990
Copy link
Member

Oh yeah. Forgot about that thread in VTU next.

Anyway, I released 1.1.0, thanks for your help! Pretty significant release.

@thibaut-lo
Copy link

Shouldn't export declare function createLocalVue (): typeof Vue be updated (https://github.com/vuejs/vue-test-utils/blob/dev/packages/test-utils/types/index.d.ts#L172) ?

@coolboy0961
Copy link
Contributor

Shouldn't export declare function createLocalVue (): typeof Vue be updated (https://github.com/vuejs/vue-test-utils/blob/dev/packages/test-utils/types/index.d.ts#L172) ?

Because this, I can not test errorHandler by Typescript.

@lmiller1990
Copy link
Member

lmiller1990 commented Jul 7, 2021

I don't know what you mean, but if you'd like to improve the types, please make a PR. Alternatively, if you don't know how to fix them, you can open an issue sharing the problem you are having. Thanks!

@coolboy0961
Copy link
Contributor

@lmiller1990
Thank you for the response. I added a issue.
#1872

I think it just need to fix the type file, I wanted to make a PR,
but I do not have the permission to push the fix branch.

@coolboy0961
Copy link
Contributor

@lmiller1990
I made a PR
#1873

It turned out to be Fork first and then create a pull request.

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

Successfully merging this pull request may close these issues.

None yet

4 participants