Mocha: this.timeout() échoue lors de l'utilisation des fonctions fléchées d'ES6

Créé le 21 déc. 2015  ·  59Commentaires  ·  Source: mochajs/mocha

Lors de l'utilisation de Node >= 4 avec "use strict" et la syntaxe ES6 pour les fonctions fléchées, mocha échoue :

describe('foo', () => {
  this.timeout(100);
});

# => TypeError: this.timeout is not a function

L'utilisation de la syntaxe ES5 fonctionne :

describe('foo', function() {
  this.timeout(100);
});

Alors, quel genre de truc laid fait du moka avec this ?

faq

Commentaire le plus utile

Merci.

Pourquoi tant de « magie » qui, à la fin, produisent des problèmes ? Pourquoi pas ça ? :

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Pas de global, pas de magie problématique... mais juste du JavaScript.

Tous les 59 commentaires

Il lie la fonction au contexte de test, ce qui ne peut pas être fait lors de l'utilisation de fonctions fléchées. De http://mochajs.org/

screen shot 2015-12-21 at 8 06 34 am

Désolé pour ça!

Merci.

Pourquoi tant de « magie » qui, à la fin, produisent des problèmes ? Pourquoi pas ça ? :

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Pas de global, pas de magie problématique... mais juste du JavaScript.

Ce que vous proposez est un changement majeur et quelque chose qui est discuté dans https://github.com/mochajs/mocha/issues/1969#issuecomment-160925915 Une réécriture pourrait introduire ces types de sémantique :)

Bon à savoir. Merci.

@ibc eh bien, il faudrait que ce soit

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (suite) => ... );  
});

mais les deux arguments de suite différents sont-ils du même type ? probablement pas, alors vous avez différents noms de variables pour refléter les différents types comme ainsi

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (test) => ... );  
});

de toute façon, l'opérateur flèche ne peut pas être utilisé dans les fonctions qui attendent des contextes.

Je n'envisage pas de casser l'interface utilisateur BDD pour #1969 - tout de suite, de toute façon - bien que je puisse être persuadé. J'espérais que nous conservions l'API existante et que nous introduisions un package séparé contenant l'interface utilisateur BDD. Mocha sera livré avec une version de l'interface utilisateur BDD qui utilise l'API existante, mais nous pourrons ensuite publier une nouvelle version du package BDD UI à l'aide de lambdas. Les utilisateurs peuvent choisir de mettre à niveau explicitement ou non ce package.

Peut-être que la syntaxe alternative ES6 pour describe ou suite wrapper pourrait résoudre ce problème :

describe({ feature: 'create stuff' , do () {
    it('abc', () => {
    }); 
}})

Cela permettrait au moins une liaison au niveau de la suite.

Une mise à jour pour ceci? J'ai ceci

mocha = require('mocha');

mocha.describe('test', (suite) => {

suite.timeout(500);

suite.it('test', (done)=>
          )
    }
)

Et obtenir TypeError: Impossible de lire la propriété 'timeout' de undefined

@mroien ce n'est pas un bug de Moka. la syntaxe de la flèche n'est pas un remplacement 1:1 pour function . s'il vous plaît lire sur ses limites

Est-ce que quelque chose en est sorti ? J'aime la solution proposée, ne serait-ce que pour mon amour des fonctions fléchées et mon aversion pour 'cela' quand ce n'est pas nécessaire

Étant donné que le délai d'expiration n'est pertinent qu'avec done , pourquoi ne pas simplement attacher la fonction de délai d'expiration à la fonction done.

it('makes sense', done => {
    done.timeout(100);
});

@nomilous cela ne fonctionne toujours pas. J'ai eu un problème similaire. Ce qui fonctionne pour mon cas, c'est d'appeler setTimeout à l'intérieur du bloc it . par exemple

it('description', done => {
     const func = () => {
          // assertions
     };
     setTimeout(func, 10000);
});

@nomilous synchrone ou les cas retournant une promesse peuvent également avoir un délai d'attente.

@andela-engmkwalusimbi, cela n'est pas censé fonctionner. Comme @boneskull l'a écrit :

@mroien ce n'est pas un bug de Moka. la syntaxe de la flèche n'est pas un remplacement 1:1 pour la fonction. s'il vous plaît lire sur ses limites

Pour tous ceux qui se posent encore des questions à ce sujet, assurez-vous de comprendre ce qu'implique une fonction de flèche, puis revenez ici et lisez la suite (il existe de nombreuses ressources qui peuvent expliquer cela bien mieux que moi).

La seule façon dont ces fonctions de flèche fonctionneraient dans ce cas est de modifier l'API bdd pour transmettre un objet context à chaque rappel de Runnable (hooks, tests), au lieu de tirer parti de this . Ce n'est pas une mauvaise idée, mais c'est un tremblement de terre d'un changement radical, donc cela n'arrivera jamais. Au lieu de cela:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

ça ressemblerait à ça :

it('should do something', (context, done) => {
  context.timeout(9000);
  done();
});

Cela casserait tous les tests Mocha asynchrone existants, qu'ils soient rétrocompatibles sinon :

it('should do something', function (context, done) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

Cependant, nous pourrions fournir une implémentation alternative de bdd qui fait cela - ce ne serait tout simplement pas la valeur par défaut.

C'est à peu près l'explication la plus complète que j'ai de "où en est ce problème". :le sourire:

Peut-être pourrait-il être pris en considération pour la prochaine version majeure ? Je ne pense pas que ce soit un changement assez important pour créer une implémentation alternative de bdd. Le fait d'avoir des arguments nommés peut également aider au développement futur et peut-être créer un moyen simple d'ajouter une sorte de middleware de test comme ceci :

it('should do something', function ({ context, done }) { ...

Cependant, nous pourrions fournir une implémentation alternative de bdd qui fait cela - ce ne serait tout simplement pas la valeur par défaut.

@boneskull Une nouvelle interface bdd-es6 serait géniale :)

Bien que je sois amoureux des fonctions fléchées qui sont vraiment utiles pour, par exemple, les fonctions de tableau comme .filter(i => i.val) , quel est le problème avec l'utilisation de fonctions normales ? Je pense qu'il est assez utile de les décrire globalement pour ne pas avoir à les exiger à chaque fois. Aussi depuis quand this magique, uniquement parce que vous ne comprenez pas les fonctions (flèches) ? Je ne veux certainement pas fournir une variable à chaque fois que je peux retourner des promesses, sinon je serais passé à quelque chose comme ava il y a longtemps. En ce qui concerne la simplicité de moka, je pense qu'il ne devrait pas y avoir de grand changement sur les fonctions normales/flèches décrites dans #1969. Et s'il vous plaît, ne me dites pas que les fonctions fléchées sont plus rapides à saisir puisque votre éditeur peut transformer un seul f en function () {\n\t\n} .

Je ne suis pas clair, existe-t-il une solution pour expirer un appel before() qui utilise des fonctions fléchées ?

    before( async function () {
      data = await provider.getData();
      console.log(data);
      this.timeout(30*1000);
    });

N'a aucun effet. obtenant toujours un temps mort de 4 secondes ici. C'est la seule chose lente dans ma suite de tests. Je peux mettre le délai d'attente à 30s dans mocha.opts pour résoudre le problème, mais je n'ai pas vraiment besoin que tous les tests expirent après 30s, juste le seul appel d'API lorsque 4s convient à 99% d'entre eux.

Voici comment je l'ai résolu entre-temps (notez que le premier describe() utilise function au lieu de la syntaxe de la grosse flèche :

describe('Search API', function () {
    this.timeout(30*1000);

    context('search', () => {
        let data;

        before( async () => {
          data = await provider.getSearch();
        });

        it('returns results', () => {
          expect(data).to.exist;
          expect(data.results).to.be.instanceOf(Array);
          expect(data.results.length).to.be.above(0);
        });
    })
});

@chovy Vous définissez le délai d'attente après que le délai d'attente se soit produit dans await provider.getData() .
Essayez d'utiliser ceci à la place :

before(async function () {
  this.timeout(30*1000); // set timeout first, then run the function
  data = await provider.getData();
  console.log(data);
});

Je ne suis pas clair, existe-t-il une solution pour expirer un appel before() qui utilise des fonctions fléchées?

Juste pour être clair à ce sujet : il n'y a actuellement aucun moyen d'appeler le timeout Mocha en utilisant les fonctions fléchées. Toute discussion d'alternatives (aussi méritoires soit-elles) est une discussion sur d'éventuelles nouvelles interfaces (ou au moins modifiées).

Quelque chose que j'avais en tête depuis un moment était de pouvoir faire:

it('...', (done) => {
  ...
  done()
})

et

it('...', (t) => {
  t.timeout(500)
  t.tag('integration', 'api')
  ...
  t.done()
})

en utilisant la même interface par défaut.

La prise en charge des deux dans la même interface par défaut vous permet de commencer à utiliser les fonctions de flèche dans une base de code existante. Il convient de souligner que la syntaxe (done) trouvée dans de nombreux tutoriels en ligne fonctionnerait toujours, sans drapeaux ou quoi que ce soit.

Ainsi, dans cette implémentation, vous obtenez en paramètre la fonction done traditionnelle, mais avec les fonctions utilitaires ajoutées en tant que propriétés de cet objet fonction done .

l'utilisation de this.timeout() fait disparaître le temps écoulé dans le rapport.

@dasilvacontin aucune idée de pourquoi nous n'y avons pas pensé plus tôt. c'est une excellente idée.

@dasilvacontin oh, je me souviens. parce qu'il faut l'appeler. vous ne voudrez peut-être pas.

Désolé, pouvez-vous préciser "je dois l'appeler", @boneskull ? Parlez-vous des problèmes où Mocha pensera que le test est asynchrone ?

Le 29 janvier 2017, à 05h54, Christopher Hiller [email protected] a écrit :

@dasilvacontin oh, je me souviens. parce qu'il faut l'appeler. vous ne voudrez peut-être pas.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou coupez le fil de discussion.

De plus, comment déclarez-vous votre intention de faire un test asynchrone lorsque vous utilisez « t » ?

Dans la bande, vous devez toujours appeler 't.done' ('t.end' dans leur API) ou définir le nombre attendu d'assertions ('t.plan').

Serait-il possible d'ajouter un troisième argument à it() avec des options ? Cela ne briserait pas l'API.

it ('accepts lambda', (done)=>{ doWork();  done(); }, {timeout:60000});

@boneskull

Et si au lieu de mettre le contexte en premier, c'était un second facultatif ?

Au lieu de cela:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

ça ressemblerait à ça :

it('should do something', (done, context) => {
  context.timeout(9000);
  done();
});
it('should do something', function (done, context) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

Cependant, nous pourrions fournir une implémentation alternative de bdd qui fait cela - ce ne serait tout simplement pas la valeur par défaut.

C'est à peu près l'explication la plus complète que j'ai de "où en est ce problème". ??

ou si le contexte devait être un paramètre défini

it('should do something', function (done, override) {
  // context is unused, but 'done' is now the second parameter
  override.timeout(9000);
  done();
});

Mais je prendrais aussi une interface autre que celle par défaut :)

L'inconvénient de toute solution qui nécessite done est que vous devez utiliser done même si retourner une promesse serait plus simple. Pour ma part, je sais que je préfère taper function et return que .then(()=>{done()}, done) !

@Flamenco C'est une idée intéressante, même si je préférerais peut-être que la fonction dure (oui, c'est techniquement plus "magique" comme ça mais,

@ScottFreeCode Je suis tout à fait d'accord à propos de done Je n'aime pas l'utiliser non plus, je commentais simplement la nécessité de mettre le contexte en premier par rapport au dernier et en utilisant l'exemple susmentionné fourni par boneskull.

J'aimerais juste avoir la possibilité de transmettre le contexte ou de définir un commutateur sur moka pour l'exécution es6.

Pendant ce temps, je résume simplement ces quelques descriptions de tests qui nécessitent des différences de délai d'expiration dans un appel de fonction () d'apparence derpy.

J'ai trouvé une solution de contournement pour le cas d'utilisation où une promesse est renvoyée à moka à partir d'une fonction de flèche qui nécessite un délai d'attente personnalisé, que je souhaite partager au cas où d'autres le trouveraient utile.

En ajoutant la fonction when suivante définie ci-dessous dans une déclaration de test comme ceci : it('does something', when(() => someFunctionReturningAPromise, customTimeout)) le délai d'attente moka peut être défini sans abandonner les fonctions fléchées.

De même, et parce que nous ne travaillons qu'avec des promesses, nous pouvons reprendre le premier paramètre à un test et passer dans le contexte au lieu du rappel effectué : it('can access the mocha test context', when(testContext => someFunctionThatNeedsContext(testContext))

const when = (lambda, timeout) =>
  function() { // return a plain function for mocha to bind this to
    this.timeout(timeout || this.timeout() || 1000)
    return lambda(this)
  }

Quelques cas de test pour illustrer :

const delay = timeout =>
  new Promise((resolve, reject) => setTimeout(resolve, timeout))

const deject = timeout => // similar to above, but a delayed reject
  new Promise((resolve, reject) => setTimeout(reject, timeout))

describe('mocha testing', () => {
  context('with only arrow functions', () => {
    context('tests that do not time out', () => {
      it('passes fast', when(() => delay(10), 100))
      it('does not usually time out', when(() => delay(2000), 2010))
    })
    context('tests that will time out', () => { // these should fail if the 'when' function works properly
      it('times out fast', when(() => delay(1000), 10)) // will fail in 10ms
      it('times out', when(() => delay(1000), 1000)) // will fail in about 1000ms
    })
    context('tests that will reject', () => { // this shows the when function works as expected when a test rejects
      it('fails fast', when(() => deject(10), 100))
    })
  })
})

@astitt-ripple ouais, ou vous écrivez simplement function () {} ... Wtf?

Ok Lucas, je mords mal. :-)

La différence avec une fonction flèche, c'est que le retour peut être ignoré. Dans un
configuration de type es6, cela peut déjà être un modèle commun pour la promesse "alors"
Chaînes.

Avec un bloc fonction, comme vous le suggérez, et à ma connaissance, le retour pour
la promesse doit être explicite. Au minimum pour une fonction de test basée sur une promesse
{... } est faux, un test doit toujours retourner sa promesse, donc le minimum
la banalisation valide est en fait : function { return ... }. Sinon le
le test renvoie undefined à moka et non à la promesse expédiée... et le
l'auteur du test passe un mauvais moment.

Si la plupart du code dans une base de code est déjà des fonctions fléchées de promise.then
et/ou un style de programmation fonctionnel, l'ajout d'un retour de fonction peut sembler
inconsistant. Le formulaire « quand » suggéré est disponible à la place pour ceux qui
préférez les flèches et un style plus fonctionnel que la fonction traditionnelle
styles de rappel ou de retour de fonction. C'est plus concis, et s'accorde avec le
décrire le contexte il dsl nous sommes tous d'accord nous aimons écrire des tests, en tenant compte
compte la promesse d'abstraction de programmation async que javascript gère donc
bien. Aussi c'est plus court que fonction+retour, même sans notre pote bouclé :
quand(() => ...).

Ce n'est peut-être pas le style préféré de ce projet, je le comprends, et
Je ne le propose pas comme un changement au projet. C'est peut-être même
répréhensible comme l'implique votre wtf. C'est très bien. Moka doit travailler avec
pre-fp friendly js. La rétrocompatibilité est une préoccupation de première classe. Cette
a aussi du sens.

C'est un fil long et sans issue, et c'est une issue. Une belle
la chose à propos de javascript, c'est qu'il n'y a pas forcément un moyen ou un style pour
faire avancer les choses. Nous n'avons pas du tout besoin d'être d'accord sur le style. Fonctionnellement
parlant, mon post précédent donne aux gens un moyen d'utiliser des flèches et des promesses
systématiquement et avec le test dsl, sans renoncer à l'accès au moka
contexte, d'une manière conviviale de programmation propre et fonctionnelle qui n'avait pas
été suggérée précédemment.

Merci.

Si la plupart du code dans une base de code est déjà... un style de programmation fonctionnel...

...puis utiliser this.mutatingMethod(currentConfiguration) pour définir des comportements, en particulier d'une fonction (ou plutôt d'un sous-programme) qui est déjà en cours d'exécution, est bien plus incohérent que d'avoir à écrire return (qui n'est que de la syntaxe) , et une apparence incohérente rendrait cette réalité plus évidente plutôt que d'introduire réellement l'incohérence.

(Ne vous méprenez pas, je suis assez satisfait de la popularité croissante des idées de programmation fonctionnelle en JS ; mais la syntaxe de function / return vs => est pas réellement essentiel à la programmation fonctionnelle, juste une question de ce qui semble plus propre dans ce paradigme, alors que d'autres concepts comme la pureté et le déclaratif par rapport à l'impératif sont en fait essentiels. son comportement / sémantique , auquel cas le passage aux fonctions flèches serait probablement trivial...)

Je suis d'accord avec vous que this.timeout est mutationnel et rompt avec le paradigme de la programmation fonctionnelle. Bien sûr, c'est totalement incohérent. À l'heure actuelle, existe-t-il un autre moyen de déclarer un délai d'expiration personnalisé par test que this.timeout ?

Dans l'implémentation actuelle de moka, il semble nécessaire de revenir au paradigme impératif/mutationnel, ou d'abandonner le paramétrage par timeouts de test. Un ou l'autre.

Dans l'abstraction when ci-dessus, un délai d'attente est le deuxième paramètre de quand, permettant à un style fonctionnel de rester au niveau du test. Il cache cette inévitable évasion du mode FP vers la programmation impérative, mais le fait en un seul endroit. En outre, il donne aux fonctions fléchées l'accès au contexte moka, ce qui n'est pas possible autrement sans rompre la convention des paramètres de la fonction de test. Cela résout donc potentiellement quelques problèmes pour certains des utilisateurs de ce projet (à en juger par l'historique de ce problème) dans l'intervalle jusqu'à ce que quelqu'un explore votre idée de testeur.

Aussi s'il vous plaît ne vous méprenez pas non plus. Je ne pense pas que la programmation fonctionnelle remplacera jamais ou ne devrait jamais complètement remplacer la programmation impérative/mutationnelle dérivée de la machine de Turing. Par exemple, dans presque tous les cas, dans un environnement d'exécution JS, le code, fonctionnel ou non, est finalement interprété par un programme écrit dans ce style impératif plus traditionnel (probablement c++, mais pas nécessairement), fonctionnant sur un système d'exploitation également écrit autour de la mutation et les idées impératives (probablement C). La mémoire est une ressource fixe, les structures de données immuables sont un mensonge que nous dit le runtime. Ce modèle fondamentalement impératif est le modèle informatique par défaut et est là pour rester. Mais cela ne signifie pas que la programmation fonctionnelle ne peut pas coexister dessus. Et si c'est le cas, il est inévitable que le code FP doive tomber de temps en temps dans le modèle sous-jacent. Je ne pense pas que cela devrait signifier que nous levons les mains et disons toute sa syntaxe, et utilisons simplement la fonction/le retour.

En fait on peut faire de la programmation fonctionnelle en C avec une certaine tolérance au détail, tout comme il est vrai qu'on peut faire de la programmation fonctionnelle avec fonction/retour au lieu de => fonctions. N'oubliez pas de retourner votre promesse. FP en C prend un peu plus de frappe, ce qui, après tout, n'est qu'une simple syntaxe.../s

En fin de compte, les fonctions fléchées nous rapprochent progressivement d'une manière réalisable et pratique de travailler dans le modèle de calcul lambda, dans un langage populaire. La suppression de ces caractères supplémentaires fait une différence petite mais importante. Il existe encore de nombreuses limitations pratiques, mais beaucoup d'entre elles peuvent être résolues, le sujet traité en fait partie.

De toute façon. J'utiliserai ma fonction d'assistance suggérée, et d'autres sont libres de l'utiliser aussi maintenant. J'attends avec impatience votre solution de testeur, mais en attendant, je ne sais pas si ça va être particulièrement productif de continuer à essayer de se convaincre les uns les autres de nos propres opinions sur la syntaxe qui est importante ou pas, comme s'il y avait est à sens unique. J'aime les flèches et vous aimez les fonctions. Je n'ai pas vu d'argument convaincant qui change mon point de vue. Je suis ouvert à un, mais il vaut mieux que ce soit plus réfléchi que des réflexes comme: "just use function, wtf" ou "vous pouvez toujours faire fp avec une _syntaxe_ plus verbeuse".

Résolvez le problème d'une autre manière, et personne n'aura besoin d'utiliser when . dit Nuff. :-)

Je ne pense pas que cela devrait signifier que nous levons les mains et disons toute sa syntaxe, et utilisons simplement la fonction/le retour.

J'aime les flèches et vous aimez les fonctions.

...il vaut mieux que ce soit plus réfléchi que des réflexes comme : ... "vous pouvez toujours faire des fps avec une syntaxe plus verbeuse".

C'est à peu près le contraire de ce que j'ai dit, cependant - j'espérais que les fonctions fléchées qui utilisent toujours this ne seraient pas FP en premier lieu, elles seraient OO avec des fonctions fléchées ( l'inverse de FP avec les fonctions JS traditionnelles). En d'autres termes, loin qu'il s'agisse simplement d'une syntaxe différente, le vrai problème est qu'il existe une incompatibilité de paradigme plus profonde que la simple incompatibilité de syntaxe (comme Mocha est actuellement conçu de toute façon).

Je suis à peu près sûr qu'il est possible de créer une interface alternative au-dessus de Mocha pour remplacer complètement this par des paramètres. Je veux juste préciser que si vous voulez passer à FP en écrivant des tests, vous devrez faire plus que simplement trouver un moyen de passer les this de Mocha aux fonctions de flèche. Je suis tout à fait pour relever ce genre de défi, cependant. ;^)

(Il existe également plusieurs autres comportements de Mocha qui sont avec état, globaux ou - pire - les deux, mais je n'ai pas le temps pour le moment de proposer une brève façon de les énumérer. Si vous avez déjà vu les problèmes liés à l'exécution de Mocha plus d'une fois, c'en est un exemple.)

À l'heure actuelle, existe-t-il un autre moyen de déclarer un délai d'expiration personnalisé par test que this.timeout ?

Malheureusement, je suis assez sûr qu'il n'y en a pas; du haut de ma tête, la suggestion d'accepter un paramètre supplémentaire à it qui serait une carte clé-valeur (en tant qu'objet JS) des paramètres de configuration ressemble à une future solution décente dans Mocha, si quelqu'un veut essayez de le mettre en œuvre.

À l'heure actuelle, existe-t-il un autre moyen de déclarer un délai d'expiration personnalisé par test que this.timeout ?

Malheureusement, je suis assez sûr qu'il n'y en a pas;

Merci d'avoir confirmé ce détail. Cela renforce le point que je faisais.

du haut de ma tête, la suggestion d'accepter un paramètre supplémentaire qui serait une carte clé-valeur (en tant qu'objet JS) des paramètres de configuration semble être une future solution décente dans Mocha, si quelqu'un veut essayer de l'implémenter.

+1 pour une solution plus générale.

D'après ce que je peux dire, il semble possible de passer encore un seul paramètre. Combinez this avec le rappel done (ainsi this devient une fonction). Ensuite, demandez à mocha d'exécuter chaque test enveloppé d'une promesse (enfin, deux en fait, une pour gérer le délai d'attente et une pour exécuter réellement le test), quel que soit le nombre de paramètres (départ de la façon dont cela fonctionne aujourd'hui). Il pouvait alors vérifier que le résultat de la fonction était une promesse ou non. Sinon, appelez done après le retour de la fonction synchrone pour finaliser le test. Si le résultat de la fonction est plutôt une promesse, attendez qu'elle soit résolue (ou rejetée). Si le délai d'attente se produit, arrêtez le test (comme précédemment). Dans le cas où un test parvient à appeler done et à retourner également une promesse. L'un ou l'autre fait est appelé avant la résolution, auquel cas mocha doit attendre la promesse, puis échouer au test pour avoir une séquence d'achèvement ambiguë. Ou done est appelé quelque temps après la résolution, auquel cas le test doit échouer rétroactivement - ou le problème signalé d'une autre manière raisonnable. Désolé, c'est beaucoup de grands traits, mais c'est la compréhension de mon étranger de ce que le moka essaie de faire et des bizarreries qu'il rencontre. Quelles autres considérations pourraient empêcher que cela soit une solution viable ?

si vous voulez aller FP en écrivant des tests, vous devrez faire plus que simplement trouver un moyen de passer les fonctions de flèche de Mocha

D'accord. il y a un changement certain en passant à un modèle de calcul différent, et en plus javascript est un écosystème complexe avec beaucoup de choses à considérer. Dans mon cas d'utilisation spécifique, cependant, définir le délai d'attente de temps en temps (par exemple, pour être plus précis en fonction de certains calculs au lieu d'une valeur par défaut fixe), est le seul problème tangible que j'ai rencontré lors de l'écriture de tests FP avec Mocha (jusqu'à présent au moins). Qui est genial. :+1:

Cela dit, j'aimerais savoir ce que vous voyez d'autre comme obstacles imminents qui ont spécifiquement à voir avec Mocha (par opposition à ce que l'écriture de tests en PF pourrait signifier en général).

C'est à peu près le contraire de ce que j'ai dit, cependant

Je suis désolé si j'ai mal interprété ou mal compris. Pour une grande partie de ce que j'ai écrit, je ne suis pas sûr non plus d'avoir bien compris, d'après les réponses. Ce qui est malheureux, car je pense que si nous nous y mettions, nous arriverions probablement à un accord assez proche sur ce à quoi FP _devrait_ ressembler en _théorie_. Ici, il semble cependant que nous ne soyons pas d'accord sur ce à quoi pourrait ressembler une réduction réalisable à _practice_ dans les versions actuellement disponibles de Mocha aujourd'hui, au moins pour certains utilisateurs/cas d'utilisation. Je ne sais donc pas exactement quel est le problème majeur avec la fonction complémentaire que j'ai proposée, de votre côté.

(Cité et réponse dans l'ordre, mais sans doute le plus important est plus tard que plus tôt.)


D'après ce que je peux dire, il semble possible de passer encore un seul paramètre. Combinez cela avec le rappel terminé (cela devient donc une fonction). Alors... Quelles autres considérations pourraient empêcher que cela soit une solution viable ?

Si nous cassons la rétrocompatibilité, il existe des conceptions bien plus simples vers lesquelles nous pourrions passer.

Si nous maintenons la rétrocompatibilité, ces deux tests doivent réussir et ne pas expirer :

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneWithSomeOtherName => {
  setTimeout(() => {
    // call functions and assert whatever
    doneWithSomeOtherName()
  }, 100)
})

Vous pouvez essayer de trouver un exemple de code pour prouver le contraire (bien que je suggère de vous concentrer plutôt sur la suggestion à la fin de ce commentaire), mais je suis à peu près sûr qu'aucun design ne pourra le faire et faites également passer ce test et ne dépassez pas le délai :

it("looks just like an asynchronous test with a different name for `done`, but never tells Mocha it's done", context => {
  context.configureByMutation("some value")
  // call functions and assert whatever
})

Mais aussi, remarquez la mutation là-bas. Plus à ce sujet ci-dessous.


Dans mon cas d'utilisation spécifique, cependant, définir le délai d'attente de temps en temps (par exemple, pour être plus précis en fonction de certains calculs au lieu d'une valeur par défaut fixe), est le seul problème tangible que j'ai rencontré lors de l'écriture de tests FP avec Mocha (jusqu'à présent au moins). Qui est genial.

:+1:!


Cela dit, j'aimerais savoir ce que vous voyez d'autre comme obstacles imminents qui ont spécifiquement à voir avec Mocha (par opposition à ce que l'écriture de tests en PF pourrait signifier en général).

Je pense que je n'ai peut-être pas communiqué cela de manière assez ciblée ... edly, alors laissez-moi voir si je peux le résumer un peu plus loin. (Désolé également si tout cela s'est révélé antagoniste ; ce n'est certainement pas censé l'être, même si j'admets que j'ai essayé de changer les mentalités ici.) "orientation objet" (et il y a plusieurs problèmes ou problèmes potentiels que Mocha a qui, je pense, se résument à son état mutable), mais cela n'affecte généralement pas votre code de test si tout ce que vous faites est d'écrire des tests et de laisser Mocha les exécuter . Vous pouvez faire des choses étranges avec la configuration de mutation impérative de Mocha :

it("imperatively sets the timeout multiple times", function(done) {
  this.timeout(5000)
  var context = this
  setTimeout(function() {
    context.timeout(1000)
    setTimeout(done, 500)
  }, 4000)
})

... mais vous n'êtes pas obligé. Comme pour tant d'éléments de programmation fonctionnelle dans des langages non fonctionnels : n'abusez pas de l'impératif.

(Il y a aussi un argument à faire valoir que les exceptions sont impures, mais je ne suis pas encore convaincu que ce soit vrai des exceptions qui sont levées en fonction de l'entrée - ce qui pourrait simplement être considéré comme une autre forme de sortie. Ainsi, certains diraient que l'utilisation d'assertions ce lancer n'est pas fonctionnel, mais je ne vais pas m'y attaquer à ce stade.)

(Partie importante ici :) Ce à quoi j'essaie d'en venir, c'est que nous envisageons potentiellement soit d'ajouter des complications à une base de code déjà complexe, soit d'apporter une modification rétrocompatible. Nous avons besoin d'une justification pour l'une ou l'autre de ces choses. Si la justification est "rendre les tests plus fonctionnels", c'est bien (dans mon livre en tout cas). Une conception qui rend les tests plus fonctionnels peut valoir la peine (en fonction de l'ampleur du problème). Mais si par "rendre les tests plus fonctionnels" vous voulez dire "faire en sorte que les fonctions flèches mutent les choses", c'est-à-dire "rendre les fonctions flèches moins fonctionnelles", cela affaiblit beaucoup le cas (si ce n'est pas simplement contradictoire). Plus complètement: (! Aussi propre que les fonctions de flèche font regard) Je ne pense pas que les tests faisant un aspect plus fonctionnel tout en conservant le bit de mutation en cause, si petite que peu était de commencer, est presque aussi la justification d'une convaincante que fait se débarrasser de ce morceau de mutation serait - du moins s'il s'agit de rendre les tests plus fonctionnels.

Je n'aurais probablement même pas dû aller si loin sur cette tangente cependant; voir ci-dessous concernant les solutions. ??


Je ne sais donc pas exactement quel est le problème majeur avec la fonction complémentaire que j'ai proposée, de votre côté.

(Partie également importante ici :) Eh bien, j'aime le peu où il prend le timeout comme paramètre au lieu d'un appel de méthode, en fait ! Si vous pouvez trouver un moyen de généraliser cela au reste des méthodes de configuration de Mocha (il y en a beaucoup - et certains s'appliquent aux tests synchrones si je me souviens bien, c'est pourquoi nous ne pouvons pas simplement ajouter les mêmes méthodes que properties sur done et laisser les gens écrire des tests asynchrones qui peuvent appeler la configuration via done , mais je m'égare), alors je voudrais vraiment y jeter un œil. À tout le moins, nous pouvons vouloir en faire une recommandation, et nous pourrions même être en mesure d'adopter l'implémentation dans it lorsqu'un troisième paramètre est passé (ou quelque chose comme ça, peut-être it.configured ou it(...).configured(...) si nous ne voulons pas plus de manigances sur le nombre de paramètres...) -- ce qui, je pense, serait une solution rétrocompatible qui s'attaque à la mutation/impératif sous-jacent et prend en charge la fonction de flèche "le bon manière" (ce que je dis est tel de toute façon): parce que cela correspond au nouveau comportement. Je suppose que ce que j'aurais dû dire, plutôt que d'aller après this dans la solution de contournement, c'est : développons la partie paramètre !

Je jure que j'ai lu quelque part que vous pourriez faire quelque chose comme ça :

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

qui ne modifie pas le contrat de paramètre à la fonction fournie. Maintenant, je ne trouve aucune référence à une telle chose, alors peut-être que je viens de l'imaginer.

@thom-nic ça marche ! je suppose que cela a du sens puisque toutes les fonctions de moka renvoient son contexte

return this;

Cela fonctionne avec moi lors du remplacement du formulaire de fonction de flèche par la fonction normale

fonction() { ..... }

Salut les gens. Je m'excuse d'être devenu sombre après avoir déclenché la discussion en août, j'ai été assez occupé et en fait j'ai pour la plupart terminé / quitté ce travail.

J'apprécie la réponse détaillée sur les différents cas d'utilisation et à quel point il est difficile de les concilier. C'était la présentation la plus concise des différentes configurations que moka doit prendre en charge que j'ai lu. Alors merci pour votre temps sur celui-là.

Avec le recul, il est clair que j'ai dû trop insister sur l'accès au contexte moka ( this ), alors que cet aspect était vraiment plus une réflexion pratique après coup. Je ne savais pas à quel point cela détournerait facilement l'attention de ce que j'essayais de faire : qui était de m'amuser en ajoutant une extension temporelle ( when ) au dsl de test pour rationaliser ajustements de délai d'attente (en plus d'éliminer une erreur courante pour un style particulier de tests, que j'expliquerai ci-dessous). Renvoyer this était juste une autre chose amusante que j'ai pensé à ajouter, l'idée principale (d'où le nom when ) était de gérer les cas qui nécessitaient des délais d'attente différents de la normale.

Évidemment, si je voulais accéder au contexte lié, je pourrais simplement utiliser directement function comme beaucoup l'ont suggéré, plutôt que de le sortir avec un wrapper. Ce n'est pas le problème. 😄 Je ne comprends pas à quel point cela peut sembler étrange à première vue. J'espère que cela complétera peut-être le tableau si je montre comment j'ai mis en place certains des tests qui m'ont conduit dans cette voie pour commencer. Pour être clair, je n'essaie pas de vendre un style en particulier ici, utilisez ce qui fonctionne pour vous. C'est ce qui a fonctionné pour moi.

D'accord
Tout d'abord, commencez par supposer que nous testons une configuration qui fait fondamentalement une chose, mais le fera pour un large éventail d'entrées, et nous devons donc tester cette chose dans un tas de scénarios pour nous assurer que les sorties sont correctes . Cependant, étant donné que le code d'application concerné « fait une chose », la procédure de test sous-jacente est à peu près toujours la même. Je ne veux pas non plus dupliquer/muter le corps de test inutilement, car cela ralentit la rapidité avec laquelle je peux ajouter plus de cas de test pour de nouvelles entrées et finalement la maintenance deviendrait déraisonnable.

Au lieu de cela, nous écrivons une fonction suffisamment générale pour démarrer le code de l'application avec toutes les entrées potentiellement prises en charge, effectuer l'action de test, puis affirmer les résultats ... Ajoutez que dans mon cas, je travaillais avec l'abstraction Promise (pour des raisons qui je vais laisser de côté), donc cette fonction de procédure de test généralisée doit naturellement renvoyer cette chaîne promise.then. Du pain et du beurre es6 genre de trucs, jusqu'ici tout va bien.

Vient maintenant les scénarios de test, puisque nous avons tout emballé dans notre fonction de procédure de test, les cas de test définissent efficacement les entrées et invoquent la fonction.

Alors peut-être que j'écris un tas de tests comme celui-ci, et tout semble fonctionner :

it('does something', function() {
  testProcedureFunction('something','1')
})

Si vous suivez de près, vous aurez probablement déjà remarqué que cet exemple a un bogue. Il manque son return , et puisque testProcedureFunction est construit sur des promesses (jeu de mots voulu), il passera toujours, peu importe si les assertions à la fin réussissent ou échouent. Il s'agit d'un bogue, et il peut parfois être extrêmement subtil à traquer. Pour illustrer, selon la façon dont nous avons écrit testProcedureFunction et la façon dont l'application est écrite, disons qu'il y a du code synchrone au début, et qui explose au lieu des assertions de fin de test, le cas de test peut même échouer -- nous menant penser que tout va bien.

Le test devrait bien sûr vraiment ressembler à ceci avec un retour :

it('does something', function() {
  return testProcedureFunction('something','1')
})

Maintenant, je sais que ce test va être une ligne dans la plupart des cas. En fait, chaque cas sera une ligne, sauf lorsque les entrées sont telles qu'un délai d'attente plus important est requis. Maintenant, parmi les différences entre les fonctions js classiques et les flèches, il y a un aspect particulier des fonctions fléchées qui est utile ici : une fonction flèche à une seule instruction a un retour implicite lorsque les accolades sont omises. Si au lieu d'écrire un function {...} , un test utilise le => ... , alors je peux facilement analyser ces cas pour la flèche et l'absence d'accolades, et en déduire rapidement qu'ils ne peuvent pas avoir ce return manquant

Ainsi:

it('does something', () => testProcedureFunction('something','1'))

Et si l'un de ces cas prenait plus de temps que les autres ! On peut bien sûr régler le timeout comme ceci :

it('does something slow', function() {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

Ou peut-être que quelqu'un fera une erreur et le fera d'abord (ce qui ne fonctionne pas bien sûr):

it('does something slow', () => {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

Mais maintenant, nous sommes de retour là où nous avons commencé, la base de code a un modèle prêt à être répété, qui est susceptible au bogue de retour manquant (soit par le futur moi, soit par la prochaine personne à ajouter une fonctionnalité - le fait est que c'est un simple erreur à faire, elle peut passer inaperçue et elle peut être difficile à retrouver). La fonction when résout ce problème et nous permet d'utiliser à nouveau les flèches de manière cohérente :

it('does something slow', when(() => testProcedureFunction('somethingSlow','2'), 10000))

(remarque, je n'ai pas réussi à faire fonctionner la suggestion de chaînage .timeout(5000) points
(note2, notez que l'utilisation de when n'utilise pas l'astuce de levage de paramètres this -- c'était vraiment juste une réflexion après coup).

Peut-être qu'il existe des linters qui peuvent signaler les bogues manquants des retours sur promesse (ou probablement de manière plus réaliste, en appliquant une instruction return avec un rhs pour chaque fonction). Cependant, ce n'était pas une option à l'époque, et je pense que la syntaxe de la flèche est plus courte et je la trouve (subjectivement/personnellement) plus facile à lire et à utiliser, ce qui m'a fait pencher la balance de function .

Alors voilà.

Je ne sais pas si j'aurai le temps de répondre à nouveau de sitôt, alors j'espère que c'était au moins informatif et clair, et peut-être même qu'il mettra une partie de la controverse entourant l'ensemble de l'"accès au contexte moka à partir des flèches" à lit.

Enfin, puisque j'ai trouvé la fonction vs => déroutante pendant longtemps, je laisserai tomber ce lien au cas où ce ne serait pas clair pour quiconque lisant avec désinvolture pourquoi les flèches ne peuvent pas accéder à this . C'était l'explication la plus claire des fonctions par rapport aux flèches que j'ai trouvée, et c'est ce qui m'a finalement aidé à comprendre suffisamment bien les différences pour les utiliser en toute confiance.

https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/

@thom-nic Cela fonctionne sur it , mais pas sur describe .

describe('my test suite', () => {

  it('test case 1', () => {
    // ...
  }).timeout('10s');  // Works on `it`. This test case doesn't timeout

  it('test case 2', () => {
    // ...
  });  // This test case timeouts.

}).timeout('10s');  // Doesn't work on `describe`. Tests are already created when runs to here.

@thom-nic , vous pouvez utiliser la forme de fonction normale

describe('my test suite', function() {
this.timeout(n);

...
}

Quiconque se plaint de cela ne comprend pas les fonctions des flèches.

Les fonctions fléchées ne sont PAS une nouvelle chose sophistiquée que ES6 est censée remplacer le classique function () {} . Le seul but des fonctions fléchées est qu'il hérite de this de son parent, où le function () classique a son propre this .

Oui, même en utilisant la syntaxe ES6 complète, vous devriez toujours utiliser function () si vous souhaitez utiliser this dans le bon contexte de votre fonction. Vous devriez utiliser à la fois function () et () => dans votre application ES6 en fonction de ce que vous essayez de faire.

this.timeout() ne fonctionne pas avec it('....', () => { ... }) car le rappel hérite de this de la fonction parent describe() , dans laquelle this.timeout() ne fonctionne pas faire sens à ce niveau.

Les fonctions lambda ne vous permettent-elles pas également d'envoyer automatiquement un seul argument à la fonction sans le déclarer dans l'appel ?

(param)=>uneFonction
...puis(uneFonction)

function(){} peut être lié à 'ceci' mais ()=> est 'verrouillé'

Les fonctions fléchées devraient remplacer la fonction traditionnelle lorsque le récepteur attend un « ceci » prédéterminé dans le même contexte qu'à partir duquel il est appelé (et bénéficier également de taper moins de code).

J'irais jusqu'à dire de ne jamais utiliser function() à moins que vous ne vouliez que 'ceci' soit autre chose que ce qu'est 'ceci' lorsque vous l'invoquez.

@Flamenco...

Les fonctions lambda ne vous permettent-elles pas également d'envoyer automatiquement un seul argument à la fonction sans le déclarer dans l'appel ?

Je ne suis pas sûr de comprendre _exactement_ comment vous exprimez cela.
En ce qui concerne "l'envoi d'arguments à la fonction", les grosses flèches fonctionnent comme les fonctions normales à une seule exception près : si vous avez exactement 1 argument, vous pouvez supprimer la parenthèse.

() => console.log("hi"); //zero arguments requires empty parenthesis
a => console.log(a); //you can optionally leave the parenthesis off for 1 argument
(a,b) => console.log(`${a} ${b}`); //2..n arguments requires parenthesis

Ce à quoi vous voulez en venir, c'est que les grosses flèches vous permettent de _retourner_ une valeur en omettant les accolades et le mot-clé return tant que votre fonction est une expression unique.
Alors si vous aviez...

setTimeout(function(a,b) { doSomething(); return calculateSomething(a,b); }, 5000);

... et vous vouliez convertir cela en une grosse fonction de flèche, vous ne seriez pas en mesure de secouer les accolades et le mot-clé return car le corps de la fonction a plusieurs instructions. Tu ferais comme ça...

setTimeout((a,b) => { doSomething(); return calculateSomething(a,b); }, 5000);

Si plutôt vous commenciez par...

setTimeout(function(a,b) { return calculateSomething(a,b); }, 5000);

... alors vous avez affaire à une fonction si simple qu'elle ne renvoie qu'une seule expression et que vous pouvez utiliser ...

setTimeout((a,b) => calculateSomething(a,b), 5000);

C'est devenu beaucoup plus facile à lire!
J'ai écrit un peu plus à ce sujet sur codefoster.com/levelup-arrays .

Il existe de nombreux styles de codage différents en JavaScript - de la POO à la FP, de la sécurité de type stricte au mixin/duck-typing. De plus, il existe des modèles avancés dans chacun de ces styles (c.-à-d. injection de dépendance dans le camp OOP, curry/monad dans le camp FP).

Si votre style de codage est plus proche de FP où this n'est pas utilisé et les fonctions fléchées sont utilisées pour réduire le passe-partout, devoir préserver this est une surcharge supplémentaire pour tout test avancé (par exemple, test paramétré, création DSL).

Tout développeur expérimenté peut simplement pré-encapsuler le framework de test en fonction de son style de codage, mais cela signifie que le framework est moins "prêt à l'emploi". Cela se traduit par un travail supplémentaire pour la mise à niveau, l'adoption de plugins et l'intégration de nouveaux ingénieurs.

J'aime l'idée d'une interface alternative bdd qui n'utilise pas this et passe à la place ce qui serait normalement l'objet de contexte en tant que paramètre à describe , it et crochets.

Mais ce n'est pas si simple à mettre en œuvre, IIRC. Ce serait cool de voir une tentative cependant.

Je sais que cela entre dans le domaine des effets secondaires graves, mais ne pourriez-vous pas traiter le paramètre de fait ou de contexte quelque chose comme ça?

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneOrContext => {
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
  }, 100)
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs immediately using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  // As well as changing config, also flags to Mocha that this test is treating the
  // parameter as a context object and is therefore not async.
  // Call functions and assert whatever
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs asynchronously using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  doneOrContext.setAsync(); // Flags to Mocha that even though the parameter has been used as
  // a context object, the test is in fact asynchronous.
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
    // or doneOrContext.done()
  }, 100)
})

j'ai utilisé le script ci-dessous mais j'ai eu la même erreur de dépassement de délai d'attente.

Mon script :

describe("getBillingDetail", fonction asynchrone (){
this.timeout(55000);
it.only("vérifier un nom de travail valide",fonction async (fait){
this.timeout(55000);
var result = wait url.getBillingDetail('12254785565647858');
console.log(résultat);
assert.equal(result,true);
});
});

Erreur : dépassement du délai d'expiration de 55 000 ms. Pour les tests et hooks asynchrones, assurez-vous que "done()" est appelé ; si vous retournez une promesse, assurez-vous qu'elle se résout.

Ne pas transmettre un rappel terminé à une fonction asynchrone

J'ai créé un prototype de solution rétrocompatible. Pour l'instant, c'est un module séparé, mais les fonctionnalités pourraient facilement être fusionnées dans mocha proprement dit.

https://github.com/papercuptech/mocha-lambda

manière rapide

require('mocha-lambda')
// now a global '_tst' can be used where 'this' was before

describe('suite', () => {
  beforeEach(() => {
    _tst.answer = 42
  })

  it('provides "this" as "_tst"', function() {
    assert(this === _tst)
  })

  it('works', () => {
    assert(_tst.answer === 42)
    _tst.skip()
  })
})

pour un nommage explicite (et fonctionne avec TypeScript)

// if you were previously explicitly importing api (describe, it, etc.) from 'mocha',
// you will have to change to importing from 'mocha-lambda', until (or if) this
// gets merged into mocha proper
import ctx, {describe as d, it as i} from 'mocha-lambda'

d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using ctx()', () => {
    ctx().skip()
  })
})

import {Context} from 'mocha'
// ctx() can also rename global
ctx('t')
declare var t: Context
d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using renamed global', () => {
    t.skip()
  })
})

@papercuptech Le lien est 404 introuvable.

Woops… était un dépôt privé. maintenant publique

Peut aussi npm i moka-lambda

@aleung @linesh-simplicity, ceci est remplacé par #3485

Merci.

Pourquoi tant de « magie » qui, à la fin, produisent des problèmes ? Pourquoi pas ça ? :

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Pas de global, pas de magie problématique... mais juste du JavaScript.

voir @thom-nic répondre, nettoyer et faire le tour

Je jure que j'ai lu quelque part que vous pourriez faire quelque chose comme ça :

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

qui ne modifie pas le contrat de paramètre à la fonction fournie. Maintenant, je ne trouve aucune référence à une telle chose, alors peut-être que je viens de l'imaginer.

La solution @thom-nic a fonctionné pour moi, merci!

Cette page vous a été utile?
0 / 5 - 0 notes