web-dev-qa-db-fra.com

Ignorer conditionnellement les tests individuels avec Karma / Jasmine

J'ai des tests qui échouent dans PhantomJS mais pas dans d'autres navigateurs.

J'aimerais que ces tests soient ignorés lorsqu'ils sont exécutés avec PhantomJS dans ma tâche de surveillance (afin que les nouvelles fenêtres de navigateur ne prennent pas le focus et que la performance soit un peu plus rapide), mais dans ma tâche de test standard et mon pipeline CI, je veux tous les tests à exécuter dans Chrome, Firefox, etc ...

J'ai envisagé une convention de dénomination de fichier comme foo.spec.dont-use-phantom.js et en excluant ceux de ma configuration Karma, mais cela signifie que je devrai séparer les tests individuels qui échouent dans leurs propres fichiers, les séparer de leurs blocs logiques describe et avoir plus de fichiers avec des noms étranges les conventions seraient généralement nulles.

En bref:

Existe-t-il un moyen d'étendre Jasmine et/ou Karma et en quelque sorte d'annoter les tests individuels pour qu'ils ne fonctionnent qu'avec certaines configurations?

21
Zach Lysobey

Je peux partager mon expérience avec cela.

Dans notre environnement, nous avons plusieurs tests exécutés avec différents navigateurs et différentes technologies. Afin d'exécuter toujours les mêmes suites sur toutes les plateformes et tous les navigateurs, nous avons un fichier d'aide chargé dans karma (helper.js) avec certaines fonctions de détection de fonctionnalités chargées globalement.

C'est à dire.

function isFullScreenSupported(){
  // run some feature detection code here
}

Vous pouvez également utiliser Modernizr pour cela.

Dans nos tests, nous enveloppons les choses dans if/else blocs comme celui-ci:

it('should work with fullscreen', function(){
  if(isFullScreenSupported()){
    // run the test
  }
  // don't do anything otherwise
});

ou pour un test asynchrone

it('should work with fullscreen', function(done){
  if(isFullScreenSupported()){
    // run the test
    ...
    done();
  } else {
    done();
  }
});

Bien qu'il soit un peu verbeux, il vous fera gagner du temps pour le type de scénario auquel vous êtes confronté.

Dans certains cas, vous pouvez utiliser le reniflage d'agent utilisateur pour détecter un type ou une version de navigateur particulier - je sais que c'est une mauvaise pratique mais parfois il n'y a en fait aucun autre moyen.

7
MarcoL

Jasmine prend en charge une fonction pending().

Si vous appelez pending() n'importe où dans le corps de la spécification, quelles que soient les attentes, la spécification sera marquée comme en attente.

Vous pouvez appeler pending() directement dans test, ou dans une autre fonction appelée depuis test.

function skipIfCondition() {
  pending();
}

function someSkipCheck() {
  return true;
}

describe("test", function() {
  it("call pending directly by condition", function() {
    if (someSkipCheck()) {
      pending();
    }

    expect(1).toBe(2);
  });

  it("call conditionally skip function", function() {
    skipIfCondition();

    expect(1).toBe(3);
  });

  it("is executed", function() {
    expect(1).toBe(1);
  });

});

exemple de travail ici: http://plnkr.co/edit/JZtAKALK9wi5PdIkbw8r?p=preview

Je pense que c'est la solution la plus pure. Dans les résultats des tests, vous pouvez voir le nombre de tests terminés et ignorés.

27
milanlempera

La solution la plus simple que je vois est de remplacer les fonctions globales describe et it pour leur faire accepter le troisième argument facultatif, qui doit être un booléen ou une fonction renvoyant un booléen - pour dire si ou la suite/spécification non actuelle doit être exécutée. Lors de la substitution, nous devons vérifier si ce troisième argument facultatif se résout en true, et si c'est le cas, alors nous appelons xdescribe/xit (ou ddescribe/iit selon la version de Jasmine), qui sont les méthodes de Jasmine pour ignorer la suite/spécification, au lieu de l'original describe/it. Ce bloc doit être exécuté avant les tests, mais après que Jasmine soit inclus dans la page. Dans Karma, il suffit de déplacer ce code dans un fichier et de l'inclure avant les fichiers de test dans karma.conf.js. Voici le code:

(function (global) {

  // save references to original methods
  var _super = {
    describe: global.describe,
    it: global.it
  };

  // override, take third optional "disable"
  global.describe = function (name, fn, disable) {
    var disabled = disable;
    if (typeof disable === 'function') {
      disabled = disable();
    }

    // if should be disabled - call "xdescribe" (or "ddescribe")
    if (disable) {
      return global.xdescribe.apply(this, arguments);
    }

    // otherwise call original "describe"
    return _super.describe.apply(this, arguments);
  };

  // override, take third optional "disable"
  global.it = function (name, fn, disable) {
    var disabled = disable;
    if (typeof disable === 'function') {
      disabled = disable();
    }

    // if should be disabled - call "xit" (or "iit")
    if (disable) {
      return global.xit.apply(this, arguments);
    }

    // otherwise call original "it"
    return _super.it.apply(this, arguments);
  };

}(window));

Et exemple d'utilisation:

describe('foo', function () {

  it('should foo 1 ', function () {
    expect(true).toBe(true);
  });

  it('should foo 2', function () {
    expect(true).toBe(true);
  }); 

}, true); // disable suite

describe('bar', function () {

  it('should bar 1 ', function () {
    expect(true).toBe(true);
  });

  it('should bar 2', function () {
    expect(true).toBe(true);
  }, function () {
    return true; // disable spec
  });

}); 

Voir un exemple de travail ici

Je suis également tombé sur ce problème où l'idée était d'ajouter une méthode de chaîne .when() pour describe et it, ce qui fera l'affaire à peu près le même que j'ai décrit ci-dessus. Cela peut sembler plus agréable mais est un peu plus difficile à mettre en œuvre.

describe('foo', function () {

  it('bar', function () {
    // ...
  }).when(anything);      

}).when(something);

Si vous êtes vraiment intéressé par cette seconde approche, je serai heureux de jouer avec elle un peu plus et d'essayer d'implémenter la chaîne .when().

Mise à jour:

Jasmine utilise le troisième argument comme option de délai d'attente ( voir la documentation ), donc mon exemple de code remplace cette fonctionnalité, ce qui n'est pas correct. J'aime @milanlempera et @MarcoCI répond mieux, le mien semble un peu hacky et pas intuitif. J'essaierai de toute façon de mettre à jour ma solution bientôt pour ne pas casser la compatibilité avec les fonctionnalités par défaut de Jasmine.

10
Michael Radionov

Essaye ça. J'utilise cette solution dans mes projets.

it('should do something', function () {
    if (!/PhantomJS/.test(window.navigator.userAgent)) {
        expect(true).to.be.true;
    }
});

Cela n'exécutera pas ce test particulier dans PhantomJS, mais l'exécutera dans d'autres navigateurs.

1
Marcin Rapacz