diff --git a/package.json b/package.json index 83f4979..9756a7b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,15 @@ "env": { "browser": true }, - "extends": "plugin:vue-libs/recommended" + "extends": "plugin:vue-libs/recommended", + "overrides": [ + { + "files": ["test/*"], + "env": { + "jest": true + } + } + ] }, "gitHooks": { "pre-commit": "lint-staged" diff --git a/src/index.js b/src/index.js index 4409bd7..f2dd776 100644 --- a/src/index.js +++ b/src/index.js @@ -136,10 +136,14 @@ export default function wrap (Vue, Component) { if (!wrapper._isMounted) { // initialize attributes const syncInitialAttributes = () => { - wrapper.props = getInitialProps(camelizedPropsList) - hyphenatedPropsList.forEach(key => { - syncAttribute(this, key) - }) + const initialProps = getInitialProps(camelizedPropsList, this) + const isUndefined = key => initialProps[camelize(key)] === undefined + wrapper.props = initialProps + hyphenatedPropsList + .filter(key => this.hasAttribute(key) || isUndefined(key)) + .forEach(key => { + syncAttribute(this, key) + }) } if (isInitialized) { diff --git a/src/utils.js b/src/utils.js index 0834f03..f2f2601 100644 --- a/src/utils.js +++ b/src/utils.js @@ -8,10 +8,10 @@ export const hyphenate = str => { return str.replace(hyphenateRE, '-$1').toLowerCase() } -export function getInitialProps (propsList) { +export function getInitialProps (propsList, el) { const res = {} propsList.forEach(key => { - res[key] = undefined + res[key] = el[key] }) return res } diff --git a/test/fixtures/mounting-manually.html b/test/fixtures/mounting-manually.html new file mode 100644 index 0000000..7ce426e --- /dev/null +++ b/test/fixtures/mounting-manually.html @@ -0,0 +1,23 @@ + + diff --git a/test/test.js b/test/test.js index 9423d7a..e098cb6 100644 --- a/test/test.js +++ b/test/test.js @@ -1,5 +1,7 @@ const launchPage = require('./setup') +/* global el, els, MyElement */ + test('properties', async () => { const { page } = await launchPage(`properties`) @@ -16,9 +18,9 @@ test('properties', async () => { el.foo = 234 el.someProp = 'lol' }) - const newFoo = await page.evaluate(() => el.vueComponent.foo) + const newFoo = await page.evaluate(() => el.vueComponent.foo) expect(newFoo).toBe(234) - const newBar = await page.evaluate(() => el.vueComponent.someProp) + const newBar = await page.evaluate(() => el.vueComponent.someProp) expect(newBar).toBe('lol') }) @@ -130,3 +132,26 @@ test('async', async () => { return document.querySelectorAll('my-element')[2].shadowRoot.textContent })).toMatch(`456 bar`) }) + +test('mounting manually', async () => { + const { page, logs } = await launchPage(`mounting-manually`) + + // mounting programmatically + await page.evaluate(() => { + window.el = new MyElement() + window.el.foo = 234 + window.el.setAttribute('some-prop', 'lol') + window.el.someProp = 'ignored as attribute takes precedence' + document.body.appendChild(window.el) + }) + + // props + const foo = await page.evaluate(() => el.vueComponent.foo) + expect(foo).toBe(234) + const bar = await page.evaluate(() => el.vueComponent.someProp) + expect(bar).toBe('lol') + + // lifecycle + expect(logs).toContain('mounted with foo: 234') + expect(logs).toContain('mounted with someProp: lol') +})