2017-10-19 3 views
1

Projekt: https://github.com/marioedgar/webpack-unit-testVue.js Unit-Test - Mock-Service mit asynchronen Daten

Ich habe eine Vue.js app ich mit dem vue CLI erzeugt. Ich habe nur die Hello World-Komponente bearbeiten leicht einige Asynchron Daten von meinem Test-Service zu holen, können Sie das hier sehen:

<template> 
 
    <h1>{{ message }}</h1> 
 
</template> 
 

 
<script> 
 
    import service from './test.service' 
 
    export default { 
 
    name: 'HelloWorld', 
 
    created() { 
 
     service.getMessage().then(message => { 
 
     this.message = message 
 
     }) 
 
    }, 
 
    data() { 
 
     return { 
 
     message: 'A' 
 
     } 
 
    } 
 
    } 
 
</script> 
 
<style scoped> 
 
</style>

Der Test Service wohnt im gleichen Verzeichnis und ist sehr einfach :

class Service { 
 
    getMessage() { 
 
    return new Promise((resolve, reject) => { 
 
     console.log('hello from test service') 
 
     resolve('B') 
 
    }) 
 
    } 
 
} 
 

 
const service = new Service() 
 
export default service

zu m Also, um ock diesen Dienst, im die webpack vue-Lader mit dem Schein-Service zu injizieren, wie hier in der offiziellen Dokumentation beschrieben:

https://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html

So, hier ist mein Test, der fast identisch mit dem Beispiel ist:

import Vue from 'vue' 
 
const HelloInjector = require('!!vue-loader?inject!../../../src/components/HelloWorld') 
 

 
const Hello = HelloInjector({ 
 
    // mock it 
 
    './test.service': { 
 
    getMessage() { 
 
     return new Promise((resolve, reject) => { 
 
     resolve('C') 
 
     }) 
 
    } 
 
    } 
 
}) 
 

 
describe('HelloWorld.vue',() => { 
 
    it('should render',() => { 
 
    const vm = new Vue({ 
 
     template: '<div><test></test></div>', 
 
     components: { 
 
     'test': Hello 
 
     } 
 
    }).$mount() 
 
    expect(vm.$el.querySelector('h1').textContent).to.equal('C') 
 
    }) 
 
})

Es gibt zwei Probleme i bin vor:

  1. Der Test schlägt fehl, weil die Assertion ausgeführt wird, bevor das verspottete Versprechen aufgelöst wird. Aus meiner Sicht ist dies so, weil der Vue-Lebenszyklus nicht vollständig beendet ist, wenn ich meine Assertion ausführe. Der gemeinsame Rüttler für den nächsten Zyklus zu warten, wäre meine Behauptung um die nächste Zecke Funktion wie folgt Wrapp:

it('should render', (done) => { 
 
    const vm = new Vue({ 
 
     template: '<div><test></test></div>', 
 
     components: { 
 
     'test': Hello 
 
     } 
 
    }).$mount() 
 
    Vue.nextTick(() => { 
 
     expect(vm.$el.querySelector('h1').textContent).to.equal('C') 
 
     done() 
 
    }) 
 
    })

Dies funktioniert jedoch nicht, wenn ich Nest 3 nextTicks das scheint mir extrem hacky zu sein. Gibt es etwas, was ich vermisse, damit das funktioniert? Dieses Beispiel scheint sehr einfach, aber ich kann diesen Test ohne viele nextTicks

  1. Ich erhalte einen seltsamen Fehler, Unterbrechungen passiert nicht bekommen ... diese Warnung erscheint wahrscheinlich 50% der Zeit und ist nicht Consistant an alle.

[vue Warnen] ausgefallene Komponente montieren: Vorlage oder Funktion rendern ist nicht definiert

Auch dies geschieht nur manchmal. Ich kann denselben genauen Komponententest ohne irgendwelche Änderungen ausführen und es zeigt mir diese Nachricht in 50% der Zeit.

+0

ist der Link zu meinem öffentlichen Repo: https://github.com/marioedgar/webpack-unit-test –

Antwort

1

Ich konnte wirklich nicht herausfinden, warum manchmal die Komponente nicht mounten konnte. Ich bin mir nicht einmal sicher, ob es mit dem Injektor zu tun hat, aber in jedem Fall habe ich den Test konsistent gehalten, indem ich ihn nicht benutzt habe. einen anderen Ansatz versuchen.

Die Komponente könnte besser testbar sein, wenn der Dienst über die props anstatt direkt verwendet wird.

<template> 
    <div> 
    <h1>{{ message }}</h1> 
</div> 
</template> 

<script> 
    import service from './test.service' 

    export default { 
    name: 'HelloWorld', 
    created() { 
     this.service.getMessage().then(message => { 
     this.message = message 
     }) 
    }, 
    data() { 
     return { 
     message: 'A' 
     } 
    }, 
    props: { 
     service: { 
     default: service 
     } 
    } 
    } 
</script> 
<style scoped> 
</style> 

Dies macht den Injektor nicht notwendig, da der nachgeahmten Dienst kann stattdessen auf das propsData im Konstruktor Komponente übergeben werden. Hier

import Vue from 'vue' 

import Async from '@/components/Async' 

const service = { 
    getMessage() { 
    return new Promise((resolve, reject) => { 
     resolve('C') 
    }) 
    } 
} 

describe('Async.vue',() => { 
    let vm 
    before(() => { 
    const Constructor = Vue.extend(Async) 
    vm = new Constructor({ 
     propsData: { 
     service: service 
     } 
    }).$mount() 
    }) 
    it('should render', function() { 
    // Wrapping the tick inside a promise, bypassing PhantomJS's lack of support 
    return (new Promise(resolve => Vue.nextTick(() => resolve()))).then(() => { 
     expect(vm.$el.querySelector('h1').textContent).to.equal('C') 
    }) 
    }) 
}) 
+0

Ich mag das besser als den Injektor, dies ist eines der Probleme nicht beheben Ich war konfrontiert. Es ist bedauerlich, dass die zusätzlichen Ticks notwendig sind. Ich frage mich, ob das in einem before() tun kann, um all diesen zusätzlichen Code in jedem Test zu vermeiden. Das oder ich kann eine einfache asynchrone Hilfsfunktion hinzufügen. –

+0

Sie haben Recht. Wenn Sie Mochas "vorher" -Tests verwenden, geben Sie nur ein, bis die Komponente vollständig geladen ist. Es ist also nur ein Häkchen erforderlich. Ich habe den Code geändert, um dies zu berücksichtigen. –