Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e91effe

Browse filesBrowse files
authored
createLocalVue errorHandler Option (#1670)
* refactor(createlocalvue): move createLocalVue to shared utils * refactor(createlocalvue): rename createLocalVue to _createLocalVue Rename createLocalVue to _createLocalVue to indicate private use * improvement(components): add Sync and Async components for testing * improvement(flow): add VueConfig to Flow * improvement(index): export new createLocalVue as default in Index * improvement(_createlocalvue): allow registration of user defined config Allow VueConfig to be passed in via createLocalVue to be registered on the created vue instance * improvement(find): add findAllParentInstances to the find API add findAllParentInstances method to traverse a component's parent to find globally registered properties via createLocalVue * improvement(mount): pass localVue into mounted createLocalVue Pass localVue into mounted createLocalVue to register localVue properties on component * improvement(error): call user defined errorHandler if defined Call the user defined errorHandler created on the localVue instance via createLocalVue. This is called in the VTU global error handler * improvement(createlocalvue): add tests to createLocalVue errorHandler add tests to createLocalVue errorHandler to test invocation on sync and async throws * docs(createlocalvue): document public createLocalVue API * docs(createlocalvue): document the createLocalVue internal API * docs(createlocalvue): document the errorHandler option in createLocalVue * fix(createlocalvue tests): wrap createLocalVue async test in try/finally Wrap async error test for createLocalVue errorHandler in try/finally to prevent global errors * fix(createlocalvue): skip async component throws for vue < 2.6 * improvement(find and error): add additional type safety to find & error Add additional type safety to find and error for older versions of vue that might propagate a vm value of null/undefined * fix(createlocalvue): only run sync error tests for vue versions < 2.4
1 parent 085ef2a commit e91effe
Copy full SHA for e91effe

File tree

14 files changed

+309
-59
lines changed
Filter options

14 files changed

+309
-59
lines changed

‎docs/api/createLocalVue.md

Copy file name to clipboardExpand all lines: docs/api/createLocalVue.md
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## createLocalVue()
22

3+
- **Arguments:**
4+
5+
- `{Object} options`
6+
- `{Function} errorHandler`
7+
38
- **Returns:**
49

510
- `{Component}`
@@ -8,8 +13,12 @@
813

914
`createLocalVue` returns a Vue class for you to add components, mixins and install plugins without polluting the global Vue class.
1015

16+
The `errorHandler` option can be used to handle uncaught errors during component render function and watchers.
17+
1118
Use it with `options.localVue`:
1219

20+
**Without options:**
21+
1322
```js
1423
import { createLocalVue, shallowMount } from '@vue/test-utils'
1524
import MyPlugin from 'my-plugin'
@@ -27,4 +36,24 @@ const freshWrapper = shallowMount(Foo)
2736
expect(freshWrapper.vm.foo).toBe(false)
2837
```
2938

39+
**With the [`errorHandler`](https://vuejs.org/v2/api/#errorHandler) option:**
40+
41+
```js
42+
import { createLocalVue, shallowMount } from '@vue/test-utils'
43+
import Foo from './Foo.vue'
44+
45+
const errorHandler = (err, vm, info) => {
46+
expect(err).toBeInstanceOf(Error)
47+
}
48+
49+
const localVue = createLocalVue({
50+
errorHandler
51+
})
52+
53+
// Foo throws an error inside a lifecycle hook
54+
const wrapper = shallowMount(Foo, {
55+
localVue
56+
})
57+
```
58+
3059
- **See also:** [Common Tips](../guides/common-tips.md#applying-global-plugins-and-mixins)

‎docs/ja/api/createLocalVue.md

Copy file name to clipboardExpand all lines: docs/ja/api/createLocalVue.md
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## createLocalVue()
22

3+
- **引数:**
4+
5+
- `{Object} options`
6+
- `{Function} errorHandler`
7+
38
- **戻り値:**
49

510
- `{Component}`
@@ -8,8 +13,12 @@
813

914
`createLocalVue` は、グローバル Vue クラスを汚染することなくコンポーネント、ミックスイン、プラグインを追加するための Vue クラスを返します。
1015

16+
[errorHandler](https://jp.vuejs.org/v2/api/index.html#errorHandler)オプションを使用すると、コンポーネントのレンダー機能とウォッチャー中にキャッチされなかったエラーを処理できます。
17+
1118
`options.localVue` と一緒に使用してください。
1219

20+
**オプションなし:**
21+
1322
```js
1423
import { createLocalVue, shallowMount } from '@vue/test-utils'
1524
import Foo from './Foo.vue'
@@ -25,4 +34,24 @@ const freshWrapper = shallowMount(Foo)
2534
expect(freshWrapper.vm.foo).toBe(false)
2635
```
2736

37+
**[errorHandler](https://jp.vuejs.org/v2/api/index.html#errorHandler)オプションを使用:**
38+
39+
```js
40+
import { createLocalVue, shallowMount } from '@vue/test-utils'
41+
import Foo from './Foo.vue'
42+
43+
const errorHandler = (err, vm, info) => {
44+
expect(err).toBeInstanceOf(Error)
45+
}
46+
47+
const localVue = createLocalVue({
48+
errorHandler
49+
})
50+
51+
// Fooがライフサイクルフック内でエラーをスローする
52+
const wrapper = shallowMount(Foo, {
53+
localVue
54+
})
55+
```
56+
2857
- **参照:** [一般的なヒント](../guides/common-tips.md#グローバルプラグインとミックスインの適用)

‎docs/ru/api/createLocalVue.md

Copy file name to clipboardExpand all lines: docs/ru/api/createLocalVue.md
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## createLocalVue()
22

3+
- **Аргументы:**
4+
5+
- `{Object} options`
6+
- `{Function} errorHandler`
7+
38
- **Возвращает:**
49

510
- `{Component}`
@@ -8,8 +13,12 @@
813

914
`createLocalVue` возвращает класс Vue, чтобы вы могли добавлять компоненты, примеси и устанавливать плагины без загрязнения глобального класса Vue.
1015

16+
Опция [errorHandler](https://ru.vuejs.org/v2/api/index.html#errorHandler) может использоваться для обработки неперехваченных ошибок во время функции визуализации компонента и наблюдателей.
17+
1118
Используйте вместе с `options.localVue`:
1219

20+
**Без опций:**
21+
1322
```js
1423
import { createLocalVue, shallowMount } from '@vue/test-utils'
1524
import Foo from './Foo.vue'
@@ -25,4 +34,24 @@ const freshWrapper = shallowMount(Foo)
2534
expect(freshWrapper.vm.foo).toBe(false)
2635
```
2736

37+
**С опцией [errorHandler](https://ru.vuejs.org/v2/api/index.html#errorHandler):**
38+
39+
```js
40+
import { createLocalVue, shallowMount } from '@vue/test-utils'
41+
import Foo from './Foo.vue'
42+
43+
const errorHandler = (err, vm, info) => {
44+
expect(err).toBeInstanceOf(Error)
45+
}
46+
47+
const localVue = createLocalVue({
48+
errorHandler
49+
})
50+
51+
// Foo выдает ошибку внутри ловушки жизненного цикла
52+
const wrapper = shallowMount(Foo, {
53+
localVue
54+
})
55+
```
56+
2857
- **См. также:** [Общие советы](../guides/common-tips.md#добавnение-гnобаnьных-пnагинов-и-примесей)

‎docs/zh/api/createLocalVue.md

Copy file name to clipboardExpand all lines: docs/zh/api/createLocalVue.md
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## createLocalVue()
22

3+
- **参数:**
4+
5+
- `{Object} options`
6+
- `{Function} errorHandler`
7+
38
- **返回值:**
49

510
- `{Component}`
@@ -8,8 +13,12 @@
813

914
`createLocalVue` 返回一个 Vue 的类供你添加组件、混入和安装插件而不会污染全局的 Vue 类。
1015

16+
在组件渲染功能和观察者期间,[`errorHandler`](https://cn.vuejs.org/v2/api/index.html#errorHandler)选项可用于处理未捕获的错误。
17+
1118
可通过 `options.localVue` 来使用:
1219

20+
**Without options:**
21+
1322
```js
1423
import { createLocalVue, shallowMount } from '@vue/test-utils'
1524
import MyPlugin from 'my-plugin'
@@ -27,4 +36,24 @@ const freshWrapper = shallowMount(Foo)
2736
expect(freshWrapper.vm.foo).toBe(false)
2837
```
2938

39+
**使用[`errorHandler`](https://cn.vuejs.org/v2/api/index.html#errorHandler)选项:**
40+
41+
```js
42+
import { createLocalVue, shallowMount } from '@vue/test-utils'
43+
import Foo from './Foo.vue'
44+
45+
const errorHandler = (err, vm, info) => {
46+
expect(err).toBeInstanceOf(Error)
47+
}
48+
49+
const localVue = createLocalVue({
50+
errorHandler
51+
})
52+
53+
// Foo在生命周期挂钩中引发错误
54+
const wrapper = shallowMount(Foo, {
55+
localVue
56+
})
57+
```
58+
3059
- **延伸阅读:**[常用技巧](../guides/common-tips.md#applying-global-plugins-and-mixins)

‎flow/options.flow.js

Copy file name to clipboardExpand all lines: flow/options.flow.js
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ declare type NormalizedOptions = {
3636
shouldProxy?: boolean
3737
}
3838

39+
declare type VueConfig = {
40+
errorHandler?: Function
41+
}
42+
3943
declare type SlotValue = Component | string | Array<Component | string>
4044

4145
declare type SlotsObject = { [name: string]: SlotValue }

‎packages/server-test-utils/src/renderToString.js

Copy file name to clipboardExpand all lines: packages/server-test-utils/src/renderToString.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { throwError } from 'shared/util'
66
import { createRenderer } from 'vue-server-renderer'
77
import { mergeOptions } from 'shared/merge-options'
88
import config from './config'
9-
import testUtils from '@vue/test-utils'
9+
import _createLocalVue from 'shared/create-local-vue'
1010
import { validateOptions } from 'shared/validate-options'
1111

1212
Vue.config.productionTip = false
@@ -34,7 +34,7 @@ export default function renderToString(
3434
const vm = createInstance(
3535
component,
3636
mergedOptions,
37-
testUtils.createLocalVue(options.localVue)
37+
_createLocalVue(options.localVue)
3838
)
3939

4040
return renderer.renderToString(vm)

‎packages/shared/create-local-vue.js

Copy file name to clipboard
+67Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// @flow
2+
3+
import Vue from 'vue'
4+
import cloneDeep from 'lodash/cloneDeep'
5+
6+
/**
7+
* Used internally by vue-server-test-utils and test-utils to propagate/create vue instances.
8+
* This method is wrapped by createLocalVue in test-utils to provide a different public API signature
9+
* @param {Component} _Vue
10+
* @param {VueConfig} config
11+
* @returns {Component}
12+
*/
13+
function _createLocalVue(
14+
_Vue: Component = Vue,
15+
config: VueConfig = {}
16+
): Component {
17+
const instance = _Vue.extend()
18+
19+
// clone global APIs
20+
Object.keys(_Vue).forEach(key => {
21+
if (!instance.hasOwnProperty(key)) {
22+
const original = _Vue[key]
23+
// cloneDeep can fail when cloning Vue instances
24+
// cloneDeep checks that the instance has a Symbol
25+
// which errors in Vue < 2.17 (https://github.com/vuejs/vue/pull/7878)
26+
try {
27+
instance[key] =
28+
typeof original === 'object' ? cloneDeep(original) : original
29+
} catch (e) {
30+
instance[key] = original
31+
}
32+
}
33+
})
34+
35+
// config is not enumerable
36+
instance.config = cloneDeep(Vue.config)
37+
38+
// if a user defined errorHandler is defined by a localVue instance via createLocalVue, register it
39+
instance.config.errorHandler = config.errorHandler || Vue.config.errorHandler
40+
41+
// option merge strategies need to be exposed by reference
42+
// so that merge strats registered by plugins can work properly
43+
instance.config.optionMergeStrategies = Vue.config.optionMergeStrategies
44+
45+
// make sure all extends are based on this instance.
46+
// this is important so that global components registered by plugins,
47+
// e.g. router-link are created using the correct base constructor
48+
instance.options._base = instance
49+
50+
// compat for vue-router < 2.7.1 where it does not allow multiple installs
51+
if (instance._installedPlugins && instance._installedPlugins.length) {
52+
instance._installedPlugins.length = 0
53+
}
54+
const use = instance.use
55+
instance.use = (plugin, ...rest) => {
56+
if (plugin.installed === true) {
57+
plugin.installed = false
58+
}
59+
if (plugin.install && plugin.install.installed === true) {
60+
plugin.install.installed = false
61+
}
62+
use.call(instance, plugin, ...rest)
63+
}
64+
return instance
65+
}
66+
67+
export default _createLocalVue
+9-51Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,14 @@
11
// @flow
22

3-
import Vue from 'vue'
4-
import cloneDeep from 'lodash/cloneDeep'
5-
6-
function createLocalVue(_Vue: Component = Vue): Component {
7-
const instance = _Vue.extend()
8-
9-
// clone global APIs
10-
Object.keys(_Vue).forEach(key => {
11-
if (!instance.hasOwnProperty(key)) {
12-
const original = _Vue[key]
13-
// cloneDeep can fail when cloning Vue instances
14-
// cloneDeep checks that the instance has a Symbol
15-
// which errors in Vue < 2.17 (https://github.com/vuejs/vue/pull/7878)
16-
try {
17-
instance[key] =
18-
typeof original === 'object' ? cloneDeep(original) : original
19-
} catch (e) {
20-
instance[key] = original
21-
}
22-
}
23-
})
24-
25-
// config is not enumerable
26-
instance.config = cloneDeep(Vue.config)
27-
28-
instance.config.errorHandler = Vue.config.errorHandler
29-
30-
// option merge strategies need to be exposed by reference
31-
// so that merge strats registered by plugins can work properly
32-
instance.config.optionMergeStrategies = Vue.config.optionMergeStrategies
33-
34-
// make sure all extends are based on this instance.
35-
// this is important so that global components registered by plugins,
36-
// e.g. router-link are created using the correct base constructor
37-
instance.options._base = instance
38-
39-
// compat for vue-router < 2.7.1 where it does not allow multiple installs
40-
if (instance._installedPlugins && instance._installedPlugins.length) {
41-
instance._installedPlugins.length = 0
42-
}
43-
const use = instance.use
44-
instance.use = (plugin, ...rest) => {
45-
if (plugin.installed === true) {
46-
plugin.installed = false
47-
}
48-
if (plugin.install && plugin.install.installed === true) {
49-
plugin.install.installed = false
50-
}
51-
use.call(instance, plugin, ...rest)
52-
}
53-
return instance
3+
import _createLocalVue from 'shared/create-local-vue'
4+
5+
/**
6+
* Returns a local vue instance to add components, mixins and install plugins without polluting the global Vue class
7+
* @param {VueConfig} config
8+
* @returns {Component}
9+
*/
10+
function createLocalVue(config: VueConfig = {}): Component {
11+
return _createLocalVue(undefined, config)
5412
}
5513

5614
export default createLocalVue

‎packages/test-utils/src/error.js

Copy file name to clipboardExpand all lines: packages/test-utils/src/error.js
+21-2Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
import { warn } from 'shared/util'
2-
import { findAllInstances } from './find'
2+
import { findAllInstances, findAllParentInstances } from './find'
33

4-
function errorHandler(errorOrString, vm) {
4+
function errorHandler(errorOrString, vm, info) {
55
const error =
66
typeof errorOrString === 'object' ? errorOrString : new Error(errorOrString)
77

8+
// If a user defined errorHandler was register via createLocalVue
9+
// find and call the user defined errorHandler
10+
const instancedErrorHandlers = findAllParentInstances(vm)
11+
.filter(
12+
_vm =>
13+
_vm &&
14+
_vm.$options &&
15+
_vm.$options.localVue &&
16+
_vm.$options.localVue.config &&
17+
_vm.$options.localVue.config.errorHandler
18+
)
19+
.map(_vm => _vm.$options.localVue.config.errorHandler)
20+
821
if (vm) {
922
vm._error = error
1023
}
1124

25+
// should be one error handler, as only once can be registered with local vue
26+
// regardless, if more exist (for whatever reason), invoke the other user defined error handlers
27+
instancedErrorHandlers.forEach(instancedErrorHandler => {
28+
instancedErrorHandler(error, vm, info)
29+
})
30+
1231
throw error
1332
}
1433

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.