From 98b8e6823c5ecbcc0ef850a1134e1df4ab537b78 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Mon, 14 Dec 2020 14:13:49 +0200 Subject: [PATCH] fix: prevent infinite loop with setProps with immediate watchers * prevent `setProps` from being called on non-top level wrappers * remove useless `silent` option from config --- docs/api/config.md | 17 +--- docs/api/wrapper/setProps.md | 4 +- docs/ja/api/config.md | 15 --- docs/ru/api/config.md | 15 --- docs/ru/api/wrapper/setProps.md | 4 +- docs/zh/api/config.md | 17 +--- flow/config.flow.js | 1 - packages/create-instance/create-instance.js | 18 +++- .../dist/vue-server-test-utils.js | 47 +++++---- packages/server-test-utils/types/index.d.ts | 1 - .../types/test/renderToString.ts | 1 - packages/test-utils/src/config.js | 1 - packages/test-utils/src/wrapper.js | 98 +++++++------------ packages/test-utils/types/index.d.ts | 3 +- packages/test-utils/types/test/mount.ts | 3 +- .../component-with-watch-immediate.vue | 24 +++++ test/specs/config.spec.js | 38 ------- test/specs/wrapper/props.spec.js | 4 +- test/specs/wrapper/setProps.spec.js | 34 ++++++- 19 files changed, 143 insertions(+), 202 deletions(-) create mode 100644 test/resources/components/component-with-watch-immediate.vue diff --git a/docs/api/config.md b/docs/api/config.md index a737b80c5..5a84aa259 100644 --- a/docs/api/config.md +++ b/docs/api/config.md @@ -47,7 +47,7 @@ config.deprecationWarningHandler = (method, message) => { - type: `{ [name: string]: Component | boolean | string }` - default: `{}` -The stub stored in `config.stubs` is used by default. +The stub stored in `config.stubs` is used by default. Stubs to use in components. These are overwritten by `stubs` passed in the mounting options. When passing `stubs` as an array in the mounting options, `config.stubs` are converted to an array, and will stub components with a basic component that returns `<${component name}-stub>`. @@ -112,18 +112,3 @@ config.provide['$logger'] = { } } ``` - -### `silent` - -- type: `Boolean` -- default: `true` - -It suppresses warnings triggered by Vue while mutating component's observables (e.g. props). When set to `false`, all warnings are visible in the console. This is a configurable way which relies on `Vue.config.silent`. - -Example: - -```js -import { config } from '@vue/test-utils' - -config.silent = false -``` diff --git a/docs/api/wrapper/setProps.md b/docs/api/wrapper/setProps.md index 9fc39cc7d..9a86ea0e1 100644 --- a/docs/api/wrapper/setProps.md +++ b/docs/api/wrapper/setProps.md @@ -8,7 +8,9 @@ Sets `Wrapper` `vm` props and forces update. -**Note the Wrapper must contain a Vue instance.** +::: warning +`setProps` could be called only for top-level component, mounted by `mount` or `shallowMount` +::: ```js import { mount } from '@vue/test-utils' diff --git a/docs/ja/api/config.md b/docs/ja/api/config.md index e37c8e1b0..2dcad4997 100644 --- a/docs/ja/api/config.md +++ b/docs/ja/api/config.md @@ -73,18 +73,3 @@ config.provide['$logger'] = { } } ``` - -### `silent` - -- 型: `Boolean` -- デフォルト: `true` - -Vue がコンポーネントの変更を感知するプロパティ(例えば props )が変更される時に出す警告を出力しません。`false` をセットするとすべての警告はコンソールに表示されません。この機能は `Vue.config.silent` を使って実現しています。 - -例: - -```js -import { config } from '@vue/test-utils' - -config.silent = false -``` diff --git a/docs/ru/api/config.md b/docs/ru/api/config.md index f66cb6420..5500bf75b 100644 --- a/docs/ru/api/config.md +++ b/docs/ru/api/config.md @@ -74,18 +74,3 @@ config.provide['$logger'] = { } } ``` - -### `silent` - -- Тип: `Boolean` -- По умолчанию: `true` - -Подавляет предупреждения, вызванные Vue во время изменения наблюдаемых компонентов (например, входных параметров). Если установлено значение `false`, все предупреждения показываются в консоли. Это настраиваемый способ, который основывается на `Vue.config.silent`. - -Пример: - -```js -import { config } from '@vue/test-utils' - -config.silent = false -``` diff --git a/docs/ru/api/wrapper/setProps.md b/docs/ru/api/wrapper/setProps.md index 9e4764161..6cb8e5cae 100644 --- a/docs/ru/api/wrapper/setProps.md +++ b/docs/ru/api/wrapper/setProps.md @@ -8,7 +8,9 @@ Устанавливает входные параметры `Wrapper` `vm` и выполняет принудительное обновление. -**Обратите внимание, что `Wrapper` должен содержать экземпляр Vue.** +::: warning Обратите внимание! +`setProps` может быть вызван только на `wrapper` верхнего уровня, который был создан с помощью `mount` или `shallowMount` +::: ```js import { mount } from '@vue/test-utils' diff --git a/docs/zh/api/config.md b/docs/zh/api/config.md index 71a17a334..1e2aa4756 100644 --- a/docs/zh/api/config.md +++ b/docs/zh/api/config.md @@ -24,7 +24,7 @@ config.showDeprecationWarnings = false - 类型:`{ [name: string]: Component | boolean | string }` - 默认值:`{}` -存储在 `config.stubs` 中的存根会被默认使用。 +存储在 `config.stubs` 中的存根会被默认使用。 用到的组件存根。它们会被传入挂载选项的 `stubs` 覆写。 当把 `stubs` 作为一个数组传入挂载选项时,`config.stubs` 会被转换为一个数组,然后用只返回一个 `<${component name}-stub>` 的基础组件进行存根。 @@ -89,18 +89,3 @@ config.provide['$logger'] = { } } ``` - -### `silent` - -- 类型:`Boolean` -- 默认值:`true` - -在组件的可观察内容 (如 props) 发生突变时,警告会被 Vue 阻止。当设置为 `false` 时,所有的警告都会出现在控制台中。这是一个 `Vue.config.silent` 的配置方式。 - -示例; - -```js -import { config } from '@vue/test-utils' - -config.silent = false -``` diff --git a/flow/config.flow.js b/flow/config.flow.js index a53bb381d..f23909d0c 100644 --- a/flow/config.flow.js +++ b/flow/config.flow.js @@ -3,6 +3,5 @@ declare type Config = { mocks?: Object, methods?: { [name: string]: Function }, provide?: Object, - silent?: boolean, showDeprecationWarnings?: boolean } diff --git a/packages/create-instance/create-instance.js b/packages/create-instance/create-instance.js index 336c5c197..948544cb1 100644 --- a/packages/create-instance/create-instance.js +++ b/packages/create-instance/create-instance.js @@ -11,7 +11,7 @@ import createScopedSlots from './create-scoped-slots' import { createStubsFromStubsObject } from './create-component-stubs' import { patchCreateElement } from './patch-create-element' -function createContext(options, scopedSlots) { +function createContext(options, scopedSlots, currentProps) { const on = { ...(options.context && options.context.on), ...options.listeners @@ -20,8 +20,8 @@ function createContext(options, scopedSlots) { attrs: { ...options.attrs, // pass as attrs so that inheritAttrs works correctly - // propsData should take precedence over attrs - ...options.propsData + // props should take precedence over attrs + ...currentProps }, ...(options.context || {}), on, @@ -110,16 +110,26 @@ export default function createInstance( parentComponentOptions.provide = function() { return { ...getValuesFromCallableOption.call(this, originalParentComponentProvide), + // $FlowIgnore ...getValuesFromCallableOption.call(this, options.provide) } } + const originalParentComponentData = parentComponentOptions.data + parentComponentOptions.data = function() { + return { + ...getValuesFromCallableOption.call(this, originalParentComponentData), + vueTestUtils_childProps: { ...options.propsData } + } + } + parentComponentOptions.$_doNotStubChildren = true + parentComponentOptions.$_isWrapperParent = true parentComponentOptions._isFunctionalContainer = componentOptions.functional parentComponentOptions.render = function(h) { return h( Constructor, - createContext(options, scopedSlots), + createContext(options, scopedSlots, this.vueTestUtils_childProps), createChildren(this, h, options) ) } diff --git a/packages/server-test-utils/dist/vue-server-test-utils.js b/packages/server-test-utils/dist/vue-server-test-utils.js index b3f56111f..e44841c21 100644 --- a/packages/server-test-utils/dist/vue-server-test-utils.js +++ b/packages/server-test-utils/dist/vue-server-test-utils.js @@ -13,7 +13,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau var Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue); var cheerio__default = /*#__PURE__*/_interopDefaultLegacy(cheerio); -// +// function createVNodes(vm, slotValue, name) { var el = vueTemplateCompiler.compileToFunctions( @@ -1698,7 +1698,7 @@ var CREATE_ELEMENT_ALIAS = semver.gt(Vue__default['default'].version, '2.1.5') ? '_c' : '_h'; -// +// function findDOMNodes( element, @@ -1716,7 +1716,7 @@ function findDOMNodes( return nodes.concat([].slice.call(element.querySelectorAll(selector))) } -// +// function isDomSelector(selector) { if (typeof selector !== 'string') { @@ -1956,7 +1956,7 @@ function matches(node, selector) { return vmMatchesName(componentInstance, nameSelector) } -// +// function findAllInstances(rootVm) { var instances = [rootVm]; @@ -2094,7 +2094,7 @@ function normalizeProvide(provide) { return provide } -// +// function getOption(option, config) { if (option === false) { @@ -2149,7 +2149,6 @@ var config = { mocks: {}, methods: {}, provide: {}, - silent: true, showDeprecationWarnings: typeof process.env.SHOW_DEPRECATIONS !== 'undefined' ? process.env.SHOW_DEPRECATIONS @@ -7541,7 +7540,7 @@ function ocd(str, options) { .replace(/>(\s*)(?=