2015-10-26 15 views
6

Ich teste meine Winkelapplikation mit Winkelmesser. Sobald der Benutzer in meiner App angemeldet ist, habe ich ein $ -Zeitlimit gesetzt, um einen Job in einer Stunde zu erledigen (wenn der Benutzer also zum Beispiel 13:00 Uhr angemeldet war, wird $ Timeout um 14:00 Uhr ausgeführt). Ich erhalte diese Fehler:

"Timed out waiting for Protractor to synchronize with the page after 20 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md. The following tasks were pending: - $timeout: function onTimeoutDone(){....." 

ich diese Timeouts Seite gelesen habe: https://github.com/angular/protractor/blob/master/docs/timeouts.md so verstehe ich Protractor wartet, bis die Seite vollständig geladen ist, was bedeutet, dass er für den $ Timeout warten ... abzuschließen

Wie kann ich den Progractor NICHT auf diesen $ Timeout warten lassen? Ich will nicht verwenden:

browser.ignoreSynchronization = true; 

Denn dann wird meine Tests aus anderen Gründen nicht (andere Winkelkomponenten muss noch die Zeit zum Laden ...)

+1

Haben Sie versucht, dieses Zeitlimit über Ihren Test sofort nach dem Einstellen zu löschen? – MBielski

Antwort

3

Die Lösung wird aktiv spülen Timeouts (as @MBielski mentioned it in comments), aber die ursprüngliche Flush-Methode selbst ist nur in Anuglar-Mocks verfügbar. Um Winkel-Mocks direkt zu verwenden, müssen Sie es auf der Seite als <script>-Tag einfügen und außerdem müssen Sie mit allen Überschreibungen umgehen, die es erzeugt, es erzeugt eine Menge Nebenwirkungen. Ich war in der Lage, Flush neu zu erstellen, ohne winkelige Mocks zu verwenden, indem ich die erzeugten Timeouts abhöre und sie dann bei Bedarf zurücksetzte.

Zum Beispiel, wenn Sie ein Timeout in Ihren Angular App:

$timeout(function() { 
    alert('Hello World'); 
}, 10000); // say hello in 10 sec 

Der Test wird wie folgt aussehen:

it('should reset timeouts', function() { 

    browser.addMockModule('e2eFlushTimeouts', function() { 

     angular 
     .module('e2eFlushTimeouts', []) 
     .run(function ($browser) { 

      // store all created timeouts 
      var timeouts = []; 

      // listen to all timeouts created by overriding 
      // a method responsible for that 
      var originalDefer = $browser.defer; 

      $browser.defer = function (fn, delay) { 
       // originally it returns timeout id 
       var timeoutId = originalDefer.apply($browser, arguments); 
       // store it to be able to remove it later 
       timeouts.push({ id: timeoutId, delay: delay }); 
       // preserve original behavior 
       return timeoutId; 
      }; 

      // compatibility with original method 
      $browser.defer.cancel = originalDefer.cancel; 

      // create a global method to flush timeouts greater than @delay 
      // call it using browser.executeScript() 
      window.e2eFlushTimeouts = function (delay) { 
       timeouts.forEach(function (timeout) { 
        if (timeout.delay >= delay) { 
         $browser.defer.cancel(timeout.id); 
        } 
       }); 
      }; 

     }); 

    }); 


    browser.get('example.com'); 

    // do test stuff 

    browser.executeScript(function() { 
     // flush everything that has a delay more that 6 sec 
     window.e2eFlushTimeouts(6000); 
    }); 

    expect(something).toBe(true); 
}); 

Es ist irgendwie experimentell, ich bin nicht sicher, ob es für funktioniert dein Fall. Dieser Code kann auch vereinfacht werden, indem browser.addMockModule in ein separates node.js-Modul verschoben wird. Außerdem kann es Probleme geben, wenn Sie kurze Timeouts (wie 100ms) entfernen möchten, es kann laufende Angular-Prozesse abbrechen, daher wird der Test abgebrochen.

+0

nette Lösung. Wenn ich jedoch richtig verstehe, löscht diese Lösung alle Timeouts, so dass ich keine Assertion testen kann, während das Timeout läuft. – BiAiB

+0

@BiAiB, Timeouts werden nur abgebrochen, wenn Sie den 'browser.executeScript (...)' Teil aufrufen. Ich glaube, Sie können erst Assertions erstellen und dann die Timeouts bei Bedarf beenden. Vielleicht ist es auch möglich, 'browser.executeScript (...)' in 'afterEach' zu platzieren. –

0

Die Lösung ist, Interzeptoren zu verwenden und ändern Sie die HTTP-Anfrage, die Zeitüberschreitung und benutzerdefinierte Timeout auf einige Millisekunden (Ihr Wunsch) zu dieser HTTP-Anfrage, so dass nach einer langen Laufzeit http-Anfrage geschlossen wird (wegen neuer Timeout) und dann können Sie die sofortige Reaktion testen.

Dies funktioniert gut und vielversprechend.

Verwandte Themen