From 4f4f65a11b5b5aa7723d67f50ad2ce6236b32154 Mon Sep 17 00:00:00 2001 From: Declan de Wet Date: Wed, 2 Nov 2016 10:25:43 +0200 Subject: [PATCH] switch to beforemount hook & improve test timing logic --- README.md | 2 +- package.json | 1 + src/index.js | 4 ++-- src/updateClientMetaInfo.js | 7 ++++++- test/basic.spec.js | 38 ++++++++++++++++++++----------------- yarn.lock | 2 +- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0731fcd..306b164 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ In any of your components, define a `metaInfo` property: # Performance -On the client, `vue-meta` batches DOM updates using [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). It needs to do this because it registers a Vue mixin that subscribes to the [`mounted`](https://vuejs.org/api/#mounted) lifecycle hook on all components in order to be notified that renders have occurred and data is ready. If `vue-meta` did not batch updates, the DOM meta info would be re-calculated and re-updated for every component on the page in quick-succession. +On the client, `vue-meta` batches DOM updates using [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). It needs to do this because it registers a Vue mixin that subscribes to the [`beforeMount`](https://vuejs.org/api/#beforeMount) lifecycle hook on all components in order to be notified that renders have occurred and data is ready. If `vue-meta` did not batch updates, the DOM meta info would be re-calculated and re-updated for every component on the page in quick-succession. Thanks to batch updating, the update will only occurr once - even if the correct meta info has already been compiled by the server. If you don't want this behaviour, see below. diff --git a/package.json b/package.json index e21363f..cd2ba29 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "cross-env": "^3.1.3", "css-loader": "^0.25.0", "doctoc": "^1.2.0", + "es6-promise": "^4.0.5", "express": "^4.14.0", "express-urlrewrite": "^1.2.0", "file-loader": "^0.9.0", diff --git a/src/index.js b/src/index.js index 4c7837c..fea3bd2 100644 --- a/src/index.js +++ b/src/index.js @@ -20,7 +20,7 @@ export default function VueMeta (Vue) { // watch for client side component updates Vue.mixin({ - mounted () { + beforeMount () { // batch potential DOM updates to prevent extraneous re-rendering window.cancelAnimationFrame(requestId) @@ -28,7 +28,7 @@ export default function VueMeta (Vue) { requestId = null // update the meta info - updateClientMetaInfo(getMetaInfo(this.$root)) + updateClientMetaInfo(getMetaInfo(this.$root), this.$root) }) } }) diff --git a/src/updateClientMetaInfo.js b/src/updateClientMetaInfo.js index 3c51384..3c23e44 100644 --- a/src/updateClientMetaInfo.js +++ b/src/updateClientMetaInfo.js @@ -11,7 +11,7 @@ if (typeof window !== 'undefined' && window !== null) { * * @param {Object} newInfo - the meta info to update to */ -export default function updateClientMetaInfo (newInfo) { +export default function updateClientMetaInfo (newInfo, $root) { // if this is not a server render, then update if (htmlTag.getAttribute(SERVER_RENDERED_ATTRIBUTE) === null) { if (newInfo.title) { @@ -24,4 +24,9 @@ export default function updateClientMetaInfo (newInfo) { } else { htmlTag.removeAttribute(SERVER_RENDERED_ATTRIBUTE) } + + // HACK: since we're performing DOM side effects, we can't rely on + // Vue.nextTick in our tests. This event helps keep the test suite + // free of setTimeout clutter + $root.$emit('vue-meta-update') } diff --git a/test/basic.spec.js b/test/basic.spec.js index 982acbb..d0d8fd2 100644 --- a/test/basic.spec.js +++ b/test/basic.spec.js @@ -1,25 +1,29 @@ import Vue from 'vue' import Meta from 'vue-meta' +import { Promise } from 'es6-promise' + Vue.use(Meta) -before(() => { - new Vue({ - template: ` -
-
- `, - metaInfo: { - title: 'Foo' - } - }).$mount() -}) - describe('basic', () => { - it('sets the document title', (done) => { - setTimeout(() => { - expect(document.title).to.equal('Foo') - done() - }, 100) + const container = document.createElement('div') + let vm + + function setMetaInfo (metaInfo) { + return new Promise((resolve) => { + vm = new Vue({ el: container, metaInfo }) + vm.$on('vue-meta-update', resolve) + }) + } + + afterEach(() => vm.$destroy()) + + it('sets a title', () => setMetaInfo({ title: 'Foo' }) + .then(() => expect(document.title).to.equal('Foo'))) + + it('sets a title with a template', () => setMetaInfo({ + title: 'Foo', + titleTemplate: '%s Bar' }) + .then(() => expect(document.title).to.equal('Foo Bar'))) }) diff --git a/yarn.lock b/yarn.lock index 0543cde..4df29c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1764,7 +1764,7 @@ es6-map@^0.1.3: es6-symbol "~3.1.0" event-emitter "~0.3.4" -es6-promise@~4.0.3: +es6-promise, es6-promise@~4.0.3: version "4.0.5" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42"