2016-06-03 18 views
1

Let'a eine einfache EmberJS Komponente annehmen:Mocking Komponente Funktion für die Zwecke der Komponentenintegrationstest in EmberJS

//my-app/components/my-component.js 
export default Ember.Component.extend({ 

    classNames: ['cursor-pointer'], 

    doSth(){ 
     // whatever, state of the component does not change 
    }, 

    clickListener: Ember.on('click', function(){ 
     this.doSth(); 
    }) 
}); 

Nun möchte Ich mag Integrationstests verwenden, um herauszufinden, ob Anklicken der Komponente erreicht (Delegierten finden) die doSth() Methode.

moduleForComponent('my-component', 'Integration | Component | stores parser previewer', { 
    integration: true 
}); 
test('should call doSth() on click', function (assert) { 

    /* Line 3 - the place I tried to set mocked doSth() up */  

    this.render(hbs`{{my-component}}`); 
    this.$('.cursor-pointer').click(); // triggers clickListener() correctly 
}); 

Das Problem ist, dass ich nicht Methode doSth() mit meiner mock ersetzen. So stoße ich nie auf assert.ok() Aussage.

habe ich versucht, folgende Aussagen auf die Linie 3 im Test einzufügen:

// idea 1 
this.set('doSth', function(){ 
    assert.ok(true); 
    }); 

// idea 2 
this.doSth = function(){ 
    assert.ok(true); 
}; 

Keine der 2 Ansätze (idea 1, Idee 2) gearbeitet. this.subject() ist ebenfalls nicht verfügbar, da es sich um einen Integrationstest und nicht um einen Komponententest handelt.

Update: Stellen doSth() sein, eine Funktion wie die openUrlInANewTab() unter dem entspricht nicht den Zustand der Komponente beeinflussen, noch die zugehörigen Controller noch Route des Staates. Beispiel:

//my-app/components/my-component.js 
... 
import openUrlInANewTab from 'my-app/utils/new-tab-opener'; 
... 
export default Ember.Component.extend({ 
    ... 
    doSth(url){ 
    openUrlInANewTab(url); 
    } 

während

// my-app/utils/new-tab-opener.js 
export default function openUrlInANewTab(){ 
     anchor = document.createElement("a"); 
     ... 
     anchor.click(); 
     ... 
} 
+0

würde etwas wie [dies] (https://github.com/elwayman02/ember-sinon-qunit) Hilfe? – MilkyWayJoe

+0

Im Abschnitt [Usage] (https://github.com/elwayman02/ember-sinon-qnit#usage) wird im Beispiel von const route = thissubject(); gefolgt von const stub = this.stub ausgegangen (route, 'transitionTo'); '. Da ich 'this_subject()' nicht verwenden darf, bleibt das Problem bestehen. Ich habe versucht, es direkt wie folgt zu verwenden: 'const stub = this.Stub (dies, 'DoSth') '; aber ich bekomme folgenden Fehler: 'Kann keine nicht existierende eigene Eigenschaft doSth' – Pavol

+0

stub wenn' component.doSth' etwas zum Controller oder zu Ihrer Route macht, können Sie testen, ob oder nicht * das Ding * passiert; Wenn Sie überprüfen möchten, ob der Klick die 'doSth'-Funktion erfolgreich ausführt, dann weiß ich nicht, ob dieser bestimmte Test in der Integration sein sollte – MilkyWayJoe

Antwort

3

Sie doSth bewegen kann custom-service Service, dass Sie Ihre my-component injizieren. Dann im Test können Sie dies leicht testen, indem Sie gefälschten Service injizieren.

Tests/Integration/components/my-Komponenten-test.js:

test('should call doSth() on click', function(assert) { 
    const customStub = Ember.Service.extend({ 
    doSth() { 
     // whatever, state of the component does not change 
     console.log('Stubbed doSth fired'); 
     assert.ok(true, 'Stubbed doSth fired'); 
    } 
    }); 
    this.register('service:custom-service', customStub); 
    this.inject.service('custom-service', { as: 'customService' }); 
    this.render(hbs`{{my-component}}`); 
    this.$('.cursor-pointer').click(); // triggers clickListener() correctly 
}); 

Komponenten/my-component.js:

import Ember from 'ember'; 

export default Ember.Component.extend({ 
    customService: Ember.inject.service('custom-service'), 
    classNames: ['cursor-pointer'], 

    clickListener: Ember.on('click', function(){ 
    this.get('customService').doSth(); 
    console.log('Click listener'); 
    }) 
}); 
+1

Ich wollte vermeiden, einen Dienst nur für diesen Zweck implementieren zu müssen, da die 'doSth()' -Funktion keinen Zustand beibehalten muss, da es eher eine Utility-Sache ist. Es scheint jedoch, dass dies in meinem Fall der richtige Weg ist, da die Logik unter mehreren Komponenten geteilt werden kann (obwohl sie keinen einzigen Zustand teilen). Darüber hinaus sollte 'doSth()' Logik vollständig unabhängig vom Kontext der Komponente sein und somit würde die von @altptugd vorgeschlagene Lösung das Design ein wenig durchbrechen. Ich habe meinen Beitrag aktualisiert, damit die Situation für alle klar ist, und ich akzeptiere Ihre Antwort, solange es keine perfekte Lösung gibt. – Pavol

1

Als Alternative zu dem, was Daniel vorgeschlagen hat, könnten Sie in Erwägung ziehen, eine Schließaktion zu verwenden, wenn Sie in Ihrer Komponente auf klicken. Was ich damit meine, ist, anstatt auf eine Ihrer Methoden zu delegieren (was Sie getan haben und nicht testen konnten) oder auf einen Service (was Daniel vorgeschlagen hat), einfach eine Aktion auszulösen, die an Ihre Komponente weitergegeben wird. Auf diese Weise haben Sie auch die Möglichkeit, in Ihrem Test zu verhöhnen. Darüber hinaus führt dieser Ansatz zu einer reaktiveren Komponente; da Sie das Verhalten Ihrer Komponente vom Eigentümer zur Laufzeit injizieren; Dadurch können Sie Ihre benutzerdefinierte Komponente problemlos in verschiedenen Kontexten (verschiedenen übergeordneten Komponenten/Vorlagen) wiederverwenden. Sehen Sie die twiddle für ein Beispiel, was ich meine.

+0

Ihre Antwort würde funktionieren, aber es würde das Konzept brechen, die Komponenten-Klick-Aktion isoliert zu halten (dies hängt stark von der Situation ab, der ich gegenüberstehe). Ich melde mich bereits in einem bestimmten Fall über den Elternteil der Eltern, und deshalb kenne und teste ich ein solches Muster, aber "doSth()" hat nichts mit dem Zustand oder Verhalten der Eltern zu tun. Ich wähle Ihre Antwort, weil es in einigen Fällen helfen könnte, ist es jetzt nicht die Lösung, mit der ich 100% zufrieden wäre. Vielen Dank! – Pavol

+0

@Pavol Wie Sie bereits erwähnt haben, ist 'doSth()' vollständig ein internes Verhalten, das Sie nicht dem übergeordneten Element aussetzen möchten. dann würde mein Vorschlag die Verkapselung Ihrer Komponente unterbrechen. Wie ich bereits sagte, war dies nur ein alternativer Vorschlag zu der obigen Antwort. Danke für die Frage und Ihre relevanten Kommentare. – alptugd