diff --git a/npm/vue2/README.md b/npm/vue2/README.md index 8b07e1a1c22a..4df3754f4d58 100644 --- a/npm/vue2/README.md +++ b/npm/vue2/README.md @@ -57,10 +57,31 @@ You can pass extensions (global components, mixins, modules to use) when mounting Vue component. Use `{ extensions: { ... }}` object inside the `options`. -- `components` - object of 'id' and components to register globally, see [Components](cypress/component/basic/components) example -- `use` (alias `plugins`) - list of plugins, see [Plugins](cypress/component/basic/plugins) -- `mixin` (alias `mixins`) - list of global mixins, see [Mixins](cypress/component/basic/mixins) example -- `filters` - hash of global filters, see [Filters](cypress/component/basic/filters) example +- `components` - object of 'id' and components to register globally. See docs [here](https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration). +- `use` (alias `plugins`) - list of plugins. See docs [here](https://v2.vuejs.org/v2/guide/plugins.html#Using-a-Plugin). +- `mixin` (alias `mixins`) - list of global mixins. See docs [here](https://v2.vuejs.org/v2/guide/mixins.html#Global-Mixin). +- `filters` - hash of global filters. See docs [here](https://v2.vuejs.org/v2/guide/filters.html). +- `directives` - global directives, see `directives` docs [here](https://v2.vuejs.org/v2/guide/custom-directive.html#ad) and [here](https://vuejs.org/guide/reusability/custom-directives.html). + +```js +import Todo from './Todo.vue' +import MyMixin1 from '../mixins/MyMixin1' +import MyMixin2 from '../mixins/MyMixin2' +import MyPlugin from '../plugins/MyPlugin' +import MyGlobalComponent1 from '../global/MyGlobalComponent1.vue' +import MyGlobalComponent2 from '../global/MyGlobalComponent2.vue' +import MyDirective from '../directives/MyDirective' + +mount(Todo, { + extensions: { + mixins: [MyMixin1, MyMixin2], + plugins: [MyPlugin], + // or use: [MyPlugin] + components: { MyGlobalComponent1, MyGlobalComponent2 }, + directives: { MyDirective }, + } +}) +``` ## Compatibility diff --git a/npm/vue2/src/index.ts b/npm/vue2/src/index.ts index 86d94af09d2b..29645d63f7d4 100644 --- a/npm/vue2/src/index.ts +++ b/npm/vue2/src/index.ts @@ -69,6 +69,17 @@ const installMixins = (Vue, options) => { } } +const registerGlobalDirectives = (Vue, options) => { + const directives = + Cypress._.get(options, 'extensions.directives') + + if (Cypress._.isPlainObject(directives)) { + Object.keys(directives).forEach((name) => { + Vue.directive(name, directives[name]) + }) + } +} + const hasStore = ({ store }: { store: any }) => Boolean(store && store._vm) const forEachValue = (obj: Record, fn: (value: T, key: string) => void) => { @@ -127,6 +138,10 @@ type VueFilters = { [key: string]: (value: string) => string } +type VueDirectives = { + [key: string]: Function | Object +} + type VueMixin = unknown type VueMixins = VueMixin | VueMixin[] @@ -211,6 +226,27 @@ interface MountOptionsExtensions { * @memberof MountOptionsExtensions */ plugins?: VuePlugins + + /** + * Optional Vue directives to install while mounting the component + * + * @memberof MountOptionsExtensions + * @see https://github.com/cypress-io/cypress/tree/develop/npm/vue#examples + * @example + * const directives = { + * custom: { + * name: 'custom', + * bind (el, binding) { + * el.dataset['custom'] = binding.value + * }, + * unbind (el) { + * el.removeAttribute('data-custom') + * }, + * }, + * } + * mount(Hello, { extensions: { directives }}) + */ + directives?: VueDirectives } /** @@ -400,6 +436,7 @@ export const mount = ( installFilters(localVue, options) installMixins(localVue, options) installPlugins(localVue, options, props) + registerGlobalDirectives(localVue, options) registerGlobalComponents(localVue, options) props.attachTo = componentNode diff --git a/system-tests/projects/vueclivue2-configured/README.md b/system-tests/projects/vueclivue2-configured/README.md index bc0d1a3428ae..ddf2b517ed9b 100644 --- a/system-tests/projects/vueclivue2-configured/README.md +++ b/system-tests/projects/vueclivue2-configured/README.md @@ -1,4 +1,4 @@ -# vueclivue2-unconfigured +# vueclivue2-configured ## Project setup ``` diff --git a/system-tests/projects/vueclivue2-configured/src/components/GlobalComponentWithCustomDirective.vue b/system-tests/projects/vueclivue2-configured/src/components/GlobalComponentWithCustomDirective.vue new file mode 100644 index 000000000000..96252239e99f --- /dev/null +++ b/system-tests/projects/vueclivue2-configured/src/components/GlobalComponentWithCustomDirective.vue @@ -0,0 +1,9 @@ + + + diff --git a/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.cy.js b/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.cy.js index 6226c3920657..ac2616bfe97f 100644 --- a/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.cy.js +++ b/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.cy.js @@ -1,5 +1,7 @@ import { mount } from 'cypress/vue2' import HelloWorld from './HelloWorld.vue' +import GlobalComponentWithCustomDirective from './GlobalComponentWithCustomDirective.vue' +import custom from '../directive' describe('', () => { it('contains the default slot in its h1', () => { @@ -13,4 +15,30 @@ describe('', () => { cy.contains('h1', slotContent) }) + + it('Vue2 custom directive should work ', () => { + mount(GlobalComponentWithCustomDirective, { + extensions: { + directives: { custom }, + }, + }) + + cy.get('.child').should('have.attr', 'data-custom', 'test') + }) + + it('Vue2 custom directive should work in nested component', () => { + const slotContent = 'Welcome to testing in Vue CLI' + + mount(HelloWorld, { + propsData: { + msg: slotContent, + }, + extensions: { + components: { GlobalComponentWithCustomDirective }, + directives: { custom }, + }, + }) + + cy.get('.child').should('have.attr', 'data-custom', 'test') + }) }) diff --git a/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.vue b/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.vue index f8e7e8a5e9f5..8002b0ce7ded 100644 --- a/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.vue +++ b/system-tests/projects/vueclivue2-configured/src/components/HelloWorld.vue @@ -25,6 +25,7 @@
  • vue-loader
  • awesome-vue
  • + diff --git a/system-tests/projects/vueclivue2-configured/src/directive.js b/system-tests/projects/vueclivue2-configured/src/directive.js new file mode 100644 index 000000000000..fdb22b0d0962 --- /dev/null +++ b/system-tests/projects/vueclivue2-configured/src/directive.js @@ -0,0 +1,9 @@ +export default { + name: 'custom', + bind (el, binding) { + el.dataset['custom'] = binding.value + }, + unbind (el) { + el.removeAttribute('data-custom') + }, +} diff --git a/system-tests/projects/vueclivue2-configured/src/main.js b/system-tests/projects/vueclivue2-configured/src/main.js index 418f3996d1f6..535c6cdce3aa 100644 --- a/system-tests/projects/vueclivue2-configured/src/main.js +++ b/system-tests/projects/vueclivue2-configured/src/main.js @@ -1,8 +1,14 @@ import Vue from 'vue' import App from './App.vue' +import GlobalComponentWithCustomDirective from './components/GlobalComponentWithCustomDirective.vue' +import custom from './directive' Vue.config.productionTip = false +Vue.component('GlobalComponentWithCustomDirective', GlobalComponentWithCustomDirective) +Vue.directive('custom', custom) new Vue({ - render: function (h) { return h(App) }, + render (h) { + return h(App) + }, }).$mount('#app') diff --git a/tooling/v8-snapshot/cache/dev-linux/snapshot-meta.cache.json b/tooling/v8-snapshot/cache/dev-linux/snapshot-meta.cache.json index e2485724317e..e63cdfc7816f 100644 --- a/tooling/v8-snapshot/cache/dev-linux/snapshot-meta.cache.json +++ b/tooling/v8-snapshot/cache/dev-linux/snapshot-meta.cache.json @@ -47,6 +47,7 @@ "./packages/network/node_modules/minimatch/minimatch.js", "./packages/server/lib/modes/record.js", "./packages/server/lib/modes/run.ts", + "./packages/server/lib/open_project.ts", "./packages/server/node_modules/@benmalka/foxdriver/node_modules/graceful-fs/polyfills.js", "./packages/server/node_modules/glob/node_modules/minimatch/minimatch.js", "./packages/server/node_modules/graceful-fs/polyfills.js", @@ -3526,5 +3527,5 @@ "./tooling/v8-snapshot/cache/dev-linux/snapshot-entry.js" ], "deferredHashFile": "yarn.lock", - "deferredHash": "95205f49259fe2d246d45ef15d1499f6e3d1d235d6db892124bbd5423f1ba872" + "deferredHash": "b23274a95457555a9102f7f660744b1a8f08324bfcfa01be64771c12fcb3ae35" } \ No newline at end of file