Mocha: this.timeout () falla cuando se utilizan las funciones de flecha de ES6

Creado en 21 dic. 2015  ·  59Comentarios  ·  Fuente: mochajs/mocha

Cuando se usa Node> = 4 con "usar la sintaxis estricta" y ES6 para las funciones de flecha, mocha falla:

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

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

El uso de la sintaxis de ES5 funciona:

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

Entonces, ¿qué tipo de truco feo hace moka con this ?

faq

Comentario más útil

Gracias.

¿Por qué tanta "magia" que, al final, produce problemas? ¿Por qué no esto ?:

var mocha = require('mocha');

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

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

Sin globales, sin magia problemática ... solo JavaScript.

Todos 59 comentarios

Vincula la función al contexto de prueba, lo que no se puede hacer cuando se utilizan funciones de flecha. De http://mochajs.org/

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

¡Lo siento por eso!

Gracias.

¿Por qué tanta "magia" que, al final, produce problemas? ¿Por qué no esto ?:

var mocha = require('mocha');

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

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

Sin globales, sin magia problemática ... solo JavaScript.

Lo que está proponiendo es un gran cambio radical y algo que se está discutiendo en https://github.com/mochajs/mocha/issues/1969#issuecomment-160925915 Una reescritura podría introducir ese tipo de semántica :)

Bueno saber. Gracias.

@ibc bueno, tendría que ser

var mocha = require('mocha');

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

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

pero, ¿son los dos argumentos de la suite diferentes del mismo tipo? probablemente no, entonces tienes diferentes nombres de variables para reflejar los diferentes tipos así

var mocha = require('mocha');

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

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

de todos modos, el operador de flecha no se puede utilizar en funciones que esperan contextos.

No me imagino romper la interfaz de usuario de BDD para el # 1969, de inmediato, de todos modos, aunque podría ser persuadido. Tenía la esperanza de que mantuviéramos la API existente e introdujéramos un paquete separado que contenga la interfaz de usuario de BDD. Mocha se enviará con una versión de la interfaz de usuario de BDD que usa la API existente, pero luego podemos lanzar una nueva versión del paquete de interfaz de usuario de BDD usando lambdas a partir de entonces; los usuarios pueden elegir si actualizar o no explícitamente a ese paquete.

Tal vez la sintaxis alternativa de ES6 para el contenedor describe o suite pueda resolver este problema:

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

Esto al menos permitiría la vinculación a nivel de suite.

¿Algún avance en esto? tengo esto

mocha = require('mocha');

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

suite.timeout(500);

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

Y obteniendo TypeError: no se puede leer la propiedad 'timeout' de undefined

@mroien esto no es un error de Mocha. la sintaxis de flecha no es un reemplazo 1: 1 de function . por favor lea sus limitaciones

¿Salió algo de esto? Me gusta la solución propuesta, aunque solo sea por mi amor por las funciones de flecha y la aversión a 'esto' cuando no es necesario

Dado que el tiempo de espera solo es relevante con done , ¿por qué no simplemente adjuntar la función de tiempo de espera a la función done?

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

@nomilous esto todavía no funciona. Tuve un problema similar. Lo que funciona para mi caso es llamar setTimeout dentro del bloque it . p.ej

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

@nomilous sincrónico o los casos que devuelven una promesa también pueden tener un tiempo de espera.

@ andela-engmkwalusimbi se supone que esto no funciona. Como escribió @boneskull :

@mroien esto no es un error de Mocha. la sintaxis de la flecha no es un reemplazo 1: 1 de la función. por favor lea sus limitaciones

Para todos los que todavía se preguntan sobre esto, asegúrese de comprender lo que implica una función de flecha, luego regrese aquí y siga leyendo (hay muchos recursos que pueden explicar esto mucho mejor que yo).

La única forma en que estas funciones de flecha funcionarían en este caso es si cambiamos la API bdd para pasar un objeto context a cada devolución de llamada de Runnable (ganchos, pruebas), en lugar de aprovechar this . No es una mala idea, pero es un terremoto de un cambio radical, por lo que nunca sucederá. En lugar de esto:

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

se vería así:

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

Eso rompería todas las pruebas asíncronas de Mocha existentes, independientemente de si fuera compatible con versiones anteriores de lo contrario:

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

Sin embargo, podríamos proporcionar una implementación alternativa bdd que haga esto, simplemente no sería la predeterminada.

Esa es la explicación más completa que tengo de "dónde está este problema". :sonrisa:

¿Quizás podría tenerse en cuenta para la próxima versión principal? No creo que sea un cambio lo suficientemente importante como para crear una implementación alternativa de bdd. Tener argumentos con nombre también podría ayudar con el desarrollo futuro y tal vez crear una forma simple de agregar algún tipo de middleware de prueba como este:

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

Sin embargo, podríamos proporcionar una implementación alternativa de bdd que haga esto, simplemente no sería la predeterminada.

@boneskull Una nueva interfaz bdd-es6 sería genial :)

Aunque estoy enamorado de las funciones de flecha que son realmente útiles para, por ejemplo, funciones de matriz como .filter(i => i.val) , ¿cuál es el problema con el uso de funciones normales? Creo que es bastante útil tener una descripción global para no tener que exigirlos cada vez. Además, ¿desde cuándo es this mágico, solo porque no comprende las funciones (flecha)? Definitivamente no quiero proporcionar una variable cada vez que puedo devolver promesas, de lo contrario, habría cambiado a algo como ava hace mucho tiempo. Con respecto a la simplicidad de mocha, creo que no debería haber ningún gran cambio en las funciones normales / flechas descritas en el # 1969. Y por favor no me digas que las funciones de flecha son más rápidas de escribir ya que tu editor puede transformar un solo f en function () {\n\t\n} .

No estoy claro, ¿hay una solución para agotar el tiempo de espera de una llamada before() que usa funciones de flecha?

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

No tiene efecto. todavía tengo 4 segundos de tiempo de espera aquí. Esto es lo único lento en mi suite de pruebas. Puedo poner el tiempo de espera a 30 segundos en mocha.opts para resolver el problema, pero realmente no necesito que todas las pruebas agoten el tiempo de espera después de 30 segundos, solo una llamada a la API cuando 4 segundos está bien para el 99% de ellas.

Así es como lo resolví mientras tanto (tenga en cuenta que el primer describe() usa function lugar de la sintaxis de flecha gruesa:

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 Estás configurando el tiempo de espera después de que ocurra el tiempo de espera en await provider.getData() .
Intente usar esto en su lugar:

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

No estoy claro, ¿hay una solución para el tiempo de espera de una llamada before () que usa funciones de flecha?

Solo para ser claros en esto: actualmente no hay forma de llamar a timeout Mocha usando las funciones de flecha. Cualquier discusión de alternativas (aunque sea meritoria) es una discusión sobre posibles interfaces nuevas (o al menos modificadas).

Algo que tenía en mente durante un tiempo era poder hacer:

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

y

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

utilizando la misma interfaz predeterminada.

Al admitir ambos en la misma interfaz predeterminada, puede comenzar a usar las funciones de flecha en una base de código existente. Vale la pena señalar que la sintaxis (done) encuentra en muchos tutoriales en línea aún funcionaría, sin banderas ni nada.

Entonces, en esta implementación, obtiene como parámetro la función tradicional done , pero con las funciones de utilidad agregadas como propiedades de ese objeto de función done .

el uso de this.timeout() hace que el tiempo transcurrido desaparezca en el informe.

@dasilvacontin no

@dasilvacontin oh, lo recuerdo. porque tienes que llamarlo. es posible que no quieras.

Lo siento, ¿puedes dar más detalles sobre "tengo que llamarlo", @boneskull? ¿Estás hablando de los problemas en los que Mocha pensará que la prueba es asíncrona?

El 29 de enero de 2017, a las 05:54, Christopher Hiller [email protected] escribió:

@dasilvacontin oh, lo recuerdo. porque tienes que llamarlo. es posible que no quieras.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub o silencia el hilo.

Además, ¿cómo declara su intención de realizar una prueba asíncrona cuando usa 't'?

En la cinta, siempre debe llamar a 't.done' ('t.end' en su API), o establecer la cantidad esperada de afirmaciones ('t.plan').

¿Sería posible agregarle un tercer argumento () con opciones? Eso no rompería la API.

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

@boneskull

¿Qué pasa si en lugar de poner el contexto primero, fuera un segundo opcional?

En lugar de esto:

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

se vería así:

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();
});

Sin embargo, podríamos proporcionar una implementación alternativa de bdd que haga esto, simplemente no sería la predeterminada.

Esa es la explicación más completa que tengo de "dónde está este problema". 😄

o si el contexto tenía que ser algún parámetro definido

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

Pero también tomaría una interfaz no predeterminada :)

La desventaja de cualquier solución que requiera done es que debe usar done incluso si devolver una promesa sería más sencillo. Hablando por mí mismo, sé que prefiero escribir function y return que .then(()=>{done()}, done) !

@Flamenco Esa es una idea interesante, aunque podría preferir tener la función al final (sí, técnicamente es más "mágico" de esa manera pero, seamos sinceros, es bastante fácil verificar si el parámetro es una función y es lo suficientemente intuitivo de usar y no es como si Mocha estuviera siendo introducido en algún tipo de abstracción que tal "magia" pudiera romper); dicho objeto de opciones también podría usarse para proporcionar etiquetas y / o razones de prueba pendiente, las cuales son características solicitadas (encontrarlas en el cuadro de búsqueda de problemas de GitHub / lista de relaciones públicas se deja como un ejercicio para el lector) con las que I ' Admitiré simpatizar (incluso si es posible evitar su ausencia, hay ventajas en lo real sobre las soluciones).

@ScottFreeCode Definitivamente estoy de acuerdo con done Tampoco me gusta usarlo, solo estaba comentando sobre la necesidad de poner el contexto en primer lugar frente al último y usar el ejemplo mencionado anteriormente proporcionado por boneskull.

Me encantaría la opción de pasar en el contexto o establecer algún interruptor en mocha para la ejecución de es6.

Mientras tanto, solo estoy terminando esas pocas descripciones de prueba que requieren diferencias de tiempo de espera en una llamada de función () de aspecto derpy.

Encontré una solución para el caso de uso en el que se devuelve una promesa a mocha desde una función de flecha que necesita un tiempo de espera personalizado, que quiero compartir en caso de que otros lo encuentren útil.

Al agregar la siguiente función when definida a continuación en una declaración de prueba como esta: it('does something', when(() => someFunctionReturningAPromise, customTimeout)) el tiempo de espera de mocha se puede configurar sin renunciar a las funciones de flecha.

De manera similar, y debido a que estamos trabajando solo con promesas, podemos volver a tomar el primer parámetro para una prueba y pasar en el contexto en lugar de la devolución de llamada realizada: 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)
  }

Algunos casos de prueba para ilustrar:

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 sí, o simplemente escribe function () {} ... ¿Wtf?

Ok luca, mal bocado. :-)

La diferencia con una función de flecha es que la devolución se puede omitir. En un
configuración de tipo es6, esto ya puede ser un patrón común para la promesa 'entonces'
cadenas.

Con un bloque de funciones, como sugiere, y hasta donde yo sé, el retorno de
la promesa debe ser explícita. Mínimamente para una función de prueba basada en promesas
{...} es incorrecto, una prueba siempre debe devolver su promesa, por lo que el mínimo
La trivialización válida es en realidad: función {retorno ...}. De lo contrario, el
La prueba devuelve indefinido a moca y no a la promesa enviada ... y la
El autor de la prueba lo pasa mal.

Si la mayor parte del código en una base de código ya es funciones de flecha de la promesa.
y / o un estilo de programación funcional, agregar función de retorno puede parecer
inconsistente. El formulario de "cuándo" sugerido está disponible en su lugar para aquellos que
prefieren flechas y un estilo más funcional que la función tradicional
estilos de devolución de llamada o función. Es más conciso y encaja con el
describir el contexto dsl todos estamos de acuerdo en que nos gusta escribir pruebas en
cuenta la promesa de abstracción de programación asíncrona que javascript maneja para
bien. También es más corto que function + return, incluso sin nuestro amigo curly:
cuando (() => ...).

Tal vez ese no sea el estilo preferido de este proyecto, lo entiendo, y
No lo propongo como un cambio en el proyecto. Tal vez sea incluso
reprobable como su wtf implica. Esta bien. Mocha tiene que trabajar con
js compatible con pre-fp. La compatibilidad con versiones anteriores es una preocupación de primera clase. Ese
también tiene sentido.

Este es un hilo largo y estancado, y esta es una salida. Una agradable
Lo que pasa con JavaScript es que no tiene que haber una forma o un estilo para
terminar las cosas. No tenemos que estar de acuerdo en el estilo en absoluto. Funcionalmente
hablando, mi publicación anterior le da a la gente una forma de usar flechas y promesas
de forma coherente y con la prueba dsl, sin ceder el acceso al moka
contexto, de una manera limpia y funcional de programación amigable que no había
sido sugerido previamente.

Gracias.

Si la mayor parte del código en una base de código ya es ... estilo de programación funcional ...

... luego usar this.mutatingMethod(currentConfiguration) para configurar comportamientos, especialmente de una función (o más bien una subrutina) que ya se está ejecutando, es mucho más inconsistente que tener que escribir return (que es solo sintaxis) , y la apariencia inconsistente estaría haciendo esa realidad más obvia en lugar de introducir la inconsistencia.

(No me malinterpretes, estoy bastante contento con el aumento de la popularidad de las ideas de programación funcional en JS; pero la sintaxis de function / return vs => es no es realmente esencial para la programación funcional, solo es una cuestión de lo que parece más limpio en ese paradigma, mientras que otros conceptos como pureza y declarativo frente a imperativo son realmente esenciales. Sería bueno tener un corredor de pruebas que fuera, en cambio, más funcional en su comportamiento / semántica , en cuyo punto cambiar a funciones de flecha probablemente sería trivial ...)

Estoy de acuerdo con usted en que this.timeout es mutacional y rompe con el paradigma de programación funcional. Por supuesto que es totalmente inconsistente. En la actualidad, ¿hay alguna otra forma de declarar un tiempo de espera personalizado por prueba que este tiempo de espera?

En la implementación actual de mocha, parece necesario escapar de nuevo al paradigma imperativo / mutacional, o renunciar a la configuración por tiempos de espera de prueba. Uno o el otro.

En la abstracción when , un tiempo de espera es el segundo parámetro de cuándo, lo que permite que un estilo funcional permanezca en el nivel de la prueba. Oculta este inevitable escape del modo FP a la programación imperativa, pero lo hace en un solo lugar. Además, le da a las funciones de flecha acceso al contexto de mocha, que de otra manera no sería posible sin romper la convención de parámetros de la función de prueba. Por lo tanto, potencialmente resuelve algunos problemas para algunos de los usuarios de este proyecto (a juzgar por el historial de este problema) en el ínterin hasta que alguien explore su idea de corredor de pruebas.

Además, por favor, tampoco me malinterpretes. No creo que la programación funcional nunca o deba reemplazar completamente la programación imperativa / mutacional derivada de la máquina de turing. Por ejemplo, en casi todos los casos, en un tiempo de ejecución de JS, el código, funcional o no, es interpretado en última instancia por un programa escrito en ese estilo imperativo más tradicional (probablemente c ++, pero no necesariamente), que se ejecuta en un sistema operativo también escrito en torno a mutaciones e ideas imperativas (probablemente C). La memoria es un recurso fijo, las estructuras de datos inmutables son una mentira que nos dice el tiempo de ejecución. Ese modelo fundamentalmente imperativo es el predeterminado en informática y está aquí para quedarse. Pero eso no significa que la programación funcional no pueda coexistir encima. Y si es así, es inevitable que el código FP tenga que bajar al modelo subyacente de vez en cuando. No creo que eso deba significar que levantemos las manos y digamos que es todo sintaxis, y usemos function / return.

En realidad, podemos hacer programación funcional en C dada una cierta tolerancia al detalle, al igual que es cierto que se puede hacer programación funcional con función / retorno en lugar de funciones =>. No olvide devolver su promesa. FP en C requiere una pequeña cantidad de escritura, que después de todo, es solo una mera sintaxis ... / s

Al final del día, las funciones de flecha nos acercan cada vez más a una forma viable y práctica de trabajar en el modelo de cálculo lambda, en un lenguaje popular. Eliminar esos caracteres adicionales hace una pequeña pero importante diferencia. Todavía existen muchas limitaciones prácticas, pero muchas de ellas se pueden resolver, el tema en cuestión es una de ellas.

De todos modos. Usaré mi función de ayuda sugerida, y otros también pueden usarla ahora. Espero su solución de prueba, pero mientras tanto, no sé si será particularmente productivo seguir tratando de convencernos unos a otros de nuestras propias opiniones sobre qué sintaxis es importante o no, como si hubiera es una forma. Me gustan las flechas y a ti te gustan las funciones. No he visto un argumento convincente que cambie mi punto de vista. Estoy abierto a uno, pero es mejor que esté más pensado que reflexiones como: "solo usa la función, wtf" o "todavía puedes hacer fp con una _sintaxis_ más detallada".

Resuelva el problema de otra manera, y nadie necesitará usar when . Dijo Nuff. :-)

No creo que eso deba significar que levantemos las manos y digamos que es todo sintaxis, y usemos function / return.

Me gustan las flechas y a ti te gustan las funciones.

... es mejor que esté más pensado que reflexiones como: ... "todavía puedes hacer fp con una sintaxis más detallada".

Sin embargo, eso es casi lo contrario de lo que dije: iba por el hecho de que las funciones de flecha que todavía usan this no serían FP en primer lugar, serían OO con funciones de flecha ( la inversa de FP con funciones JS tradicionales). En otras palabras, lejos de ser solo una sintaxis diferente, el problema real es que hay una incompatibilidad de paradigma más profunda que solo la incompatibilidad de sintaxis (como Mocha está diseñado actualmente de todos modos).

Estoy bastante seguro de que es posible construir una interfaz alternativa sobre Mocha para reemplazar this completo con parámetros. Solo quiero dejar en claro que si desea pasar a FP en las pruebas de escritura, tendrá que hacer más que simplemente encontrar una manera de pasar las funciones de this Mocha a las flechas. Sin embargo, estoy muy a favor de enfrentar ese tipo de desafío. ; ^)

(También hay varios otros comportamientos de Mocha que son con estado, globales o, peor aún, ambos, pero no tengo tiempo en este momento para encontrar una forma breve de enumerarlos. Si alguna vez has visto Sin embargo, los problemas relacionados con la ejecución de Mocha más de una vez, ese es un ejemplo de ellos).

En la actualidad, ¿hay alguna otra forma de declarar un tiempo de espera personalizado por prueba que este tiempo de espera?

Desafortunadamente, estoy bastante seguro de que no lo hay; en la parte superior de mi cabeza la sugerencia de aceptar un parámetro adicional a it que sería un mapa de valor clave (como un objeto JS) de los ajustes de configuración suena como una solución futura decente en Mocha, si alguien quiere intente implementarlo.

En la actualidad, ¿hay alguna otra forma de declarar un tiempo de espera personalizado por prueba que este tiempo de espera?

Desafortunadamente, estoy bastante seguro de que no lo hay;

Gracias por confirmar este detalle. Esto solidifica el punto que estaba haciendo.

En la parte superior de mi cabeza, la sugerencia de aceptar un parámetro adicional que sería un mapa de clave-valor (como un objeto JS) de los ajustes de configuración suena como una solución futura decente en Mocha, si alguien quiere intentar implementarlo.

+1 para una solución más general.

Sin embargo, por lo que puedo decir, parece factible pasar un solo parámetro todavía. Combine this con la devolución done llamada this convierta en una función). Luego, haga que mocha ejecute cada prueba envuelta con una promesa (bueno, dos en realidad, una para manejar el tiempo de espera y otra para ejecutar la prueba), independientemente del recuento de parámetros (desviación de cómo funciona hoy). A continuación, podría comprobar si el resultado de la función era una promesa o no. Si no es así, llame a done después de que la función síncrona regrese para finalizar la prueba. Si el resultado de la función es una promesa, espere a que se resuelva (o rechace). Si se agota el tiempo de espera, detenga la prueba (igual que antes). En el caso de que una prueba consiga llamar a done y también devolver una promesa. Cualquiera de los dos se llama antes de la resolución, en cuyo caso mocha debe esperar la promesa y luego fallar la prueba por tener una secuencia de finalización ambigua. O se llama hecho en algún momento después de la resolución, en cuyo caso, de alguna manera, la prueba debe fallar retroactivamente, o el problema se indica de alguna otra manera razonable. Lo siento, son muchos trazos generales, pero esa es la comprensión de mi forastero de lo que está tratando de hacer el moca y las peculiaridades con las que se encuentra. ¿Qué otras consideraciones podrían evitar que esto sea una solución viable?

si desea pasar a FP en las pruebas de escritura, tendrá que hacer más que simplemente encontrar una manera de pasar esto de Mocha a las funciones de flecha

acordado. hay un cambio definitivo al pasar a un modelo computacional diferente y, además, javascript es un ecosistema complejo con mucho que considerar. En mi caso de uso específico, sin embargo, establecer el tiempo de espera de vez en cuando (por ejemplo, para ser más preciso en función de algunos cálculos en lugar de un valor predeterminado fijo), es el único problema tangible que he encontrado al escribir pruebas de FP con Mocha (hasta ahora por lo menos). Lo cual es genial. : +1:

Dicho esto, me gustaría saber qué más ve como obstáculos inminentes que tienen que ver específicamente con Mocha (a diferencia de lo que las pruebas de escritura en FP podrían significar en general).

Eso es casi lo contrario de lo que dije, aunque

Lamento haberme interpretado mal o haberme interpretado mal. En gran parte de lo que escribí, tampoco estoy seguro de haberlo transmitido según lo previsto, según las respuestas. Lo cual es una lástima, ya que creo que si nos ponemos manos a la obra, probablemente llegaríamos a un acuerdo bastante estrecho sobre cómo debería verse FP en la teoría. Sin embargo, aquí parece que no estamos de acuerdo en cuanto a cómo se vería una reducción viable a _practice_ en las versiones actualmente disponibles de Mocha en la actualidad, al menos para algunos usuarios / casos de uso. Por lo tanto, no estoy muy seguro de cuál es exactamente el problema principal con la función complementaria propuesta que propuse, de su lado.

(Citado y respondido en orden, pero podría decirse que lo más importante es más tarde que antes).


Sin embargo, por lo que puedo decir, parece factible pasar un solo parámetro todavía. Combine esto con la devolución de llamada realizada (para que esto se convierta en una función). Entonces ... ¿Qué otras consideraciones podrían impedir que esto sea una solución viable?

Si rompemos la compatibilidad con versiones anteriores, hay diseños más simples a los que podríamos cambiar.

Si mantenemos la compatibilidad con versiones anteriores, ambas pruebas deben aprobarse y no agotarse el tiempo de espera:

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

Puede intentar crear un código de ejemplo para demostrar lo contrario (aunque sugeriría centrarse en la sugerencia al final de este comentario), pero estoy bastante seguro de que ningún diseño podrá hacer eso y también haga que esta prueba pase y no se agote el tiempo:

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
})

Pero también, observe la mutación allí. Más sobre esto a continuación.


En mi caso de uso específico, sin embargo, establecer el tiempo de espera de vez en cuando (por ejemplo, para ser más preciso en función de algunos cálculos en lugar de un valor predeterminado fijo), es el único problema tangible que he encontrado al escribir pruebas de FP con Mocha (hasta ahora por lo menos). Lo cual es genial.

: +1:!


Dicho esto, me gustaría saber qué más ve como obstáculos inminentes que tienen que ver específicamente con Mocha (a diferencia de lo que las pruebas de escritura en FP podrían significar en general).

Creo que es posible que no haya estado comunicando este enfoque con bastante precisión, así que déjame ver si puedo resumirlo un poco más. (También lo siento si algo de esto ha resultado ser antagónico; ciertamente no se pretende que lo sea, aunque admitiré que intento cambiar la mentalidad aquí). "orientación a objetos" (y hay varios problemas o problemas potenciales que Mocha tiene que creo que se reducen a su estado mutable), pero eso generalmente no afecta su código de prueba si todo lo que está haciendo es escribir pruebas y dejar que Mocha las ejecute . Se pueden hacer cosas extrañas con la configuración mutante imperativo 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)
})

... pero no tienes que hacerlo. Al igual que con tantos elementos de programación funcionalmente en lenguajes no funcionales: simplemente no abuse de las cosas imperativas.

(También se puede argumentar que las excepciones son impuras, pero aún no estoy convencido de que eso sea cierto para las excepciones que se lanzan en función de la entrada , lo que podría considerarse otra forma de salida. Por lo tanto, algunos dirían que el uso de aserciones ese lanzamiento no es funcional, pero no voy a abordar eso en este momento).

(Parte importante aquí :) A lo que estoy tratando de llegar es a que estamos considerando la posibilidad de agregar una complicación a una base de código ya compleja o hacer un cambio incompatible con versiones anteriores. Necesitamos una justificación para cualquiera de esas cosas. Si la justificación es "hacer que las pruebas sean más funcionales", eso es bueno (en mi libro de todos modos). Un diseño que hace que las pruebas sean más funcionales puede valer la pena (dependiendo de la cantidad de problemas). Pero si por "hacer que las pruebas sean más funcionales" te refieres a "hacer que las funciones de flecha muten cosas", es decir, "hacer que las funciones de flecha sean menos funcionales", eso debilita mucho el caso (si no es solo autocontradictorio). Más completamente: no creo que hacer que las pruebas parezcan más funcionales (¡tan limpias como se ven las funciones de flecha!) Mientras se retiene la mutación involucrada, por pequeña que sea para empezar, sea una justificación casi tan convincente como en realidad. deshacerse de esa pequeña mutación sería, al menos si el objetivo es hacer que las pruebas sean más funcionales.

Probablemente ni siquiera debería haberme alejado tanto en esta tangente; consulte a continuación las soluciones. 😸


Por lo tanto, no estoy muy seguro de cuál es exactamente el problema principal con la función complementaria propuesta que propuse, de su lado.

(También es una parte importante aquí :) Bueno, me gusta la parte en la que toma timeout como parámetro en lugar de una llamada al método, ¡en realidad! Si puede encontrar una manera de generalizar eso al resto de los métodos de configuración de Mocha (hay muchos de ellos, y algunos se aplican a las pruebas síncronas si no recuerdo mal, por lo tanto, no podemos simplemente agregar los mismos métodos que properties en done y dejar que la gente escriba pruebas asincrónicas que pueden llamar a la configuración a través de done , pero estoy divagando), entonces definitivamente querría echarle un vistazo. Como mínimo, es posible que queramos hacer una recomendación, e incluso podríamos adoptar la implementación en it cuando se pase un tercer parámetro (o algo así, tal vez it.configured o it(...).configured(...) si no queremos más travesuras de número de parámetros ...), que creo que sería una solución compatible con versiones anteriores que aborda la mutación subyacente / materia imperativa y obtiene el apoyo de la función de flecha "a la derecha way "(lo que estoy argumentando es así de todos modos): porque encaja con el nuevo comportamiento. Supongo que lo que debería haber dicho, en lugar de ir tras this en la solución alternativa, es: ¡expandamos la parte del parámetro!

Juro que leí en algún lugar que podrías hacer algo como esto:

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

que no altera el contrato del parámetro a la función proporcionada. Ahora no puedo encontrar ninguna referencia a algo así, así que tal vez simplemente lo imaginé.

@ thom-nic ¡esto funciona! supongo que tiene sentido ya que todas las funciones de mocha devuelven su contexto

return this;

Funciona conmigo al reemplazar el formulario de función de flecha con la función normal

función () {.....}

Hola amigos. Pido disculpas por haberme oscurecido después de iniciar la discusión en agosto, he estado bastante ocupado y, de hecho, he completado / dejado ese trabajo en su mayoría.

Agradezco la respuesta detallada sobre los diferentes casos de uso y lo difícil que es combinarlos. Esa fue la demostración más concisa de las diferentes configuraciones que mocha tiene para admitir que he leído. Así que gracias por tu tiempo en eso.

Mirando hacia atrás, está claro que debo haber enfatizado demasiado el acceso al contexto moca ( this ), cuando ese aspecto era realmente un pensamiento posterior más conveniente. No me di cuenta de la facilidad con la que desviaría la atención de lo que en realidad estaba tratando de hacer: divertirme agregando una extensión temporal ( when ) al dsl de prueba para simplificar una sola vez ajustes de tiempo de espera (además de eliminar un error común para un estilo particular de pruebas, que explicaré a continuación). Devolver this fue solo otra cosa divertida que pensé en agregar, la idea principal (de ahí el nombre when ) era manejar casos que necesitaban tiempos de espera diferentes a los normales.

Obviamente, si quisiera acceder al contexto enlazado, simplemente podría usar function directamente como muchos han sugerido, en lugar de sacarlo con una envoltura. Ese no es el problema. 😄 No se me escapa cómo eso puede parecer extraño a primera vista. Espero que tal vez redondee la imagen si muestro cómo estaba configurando algunas de las pruebas que me llevaron por este camino para empezar. Para ser claro, no estoy tratando de vender ningún estilo en particular aquí, use lo que funcione para usted. Esto es lo que funcionó para mí.

OK
En primer lugar, comience con la suposición de que estamos probando una configuración que básicamente hace una cosa, pero lo hará para una amplia gama de entradas, por lo que debemos probar esto en un montón de escenarios para asegurarnos de que las salidas sean correctas. . Sin embargo, dado que el código de aplicación relevante "hace una cosa", el procedimiento de prueba subyacente es prácticamente siempre el mismo. Tampoco quiero duplicar / mutar el cuerpo de prueba innecesariamente, ya que eso ralentiza la rapidez con la que puedo agregar más casos de prueba para nuevas entradas y, finalmente, el mantenimiento se volvería irrazonable.

Entonces, en su lugar, escribimos una función que sea lo suficientemente general como para iniciar el código de la aplicación con cualquier entrada potencialmente compatible, realizar la acción de prueba y luego afirmar los resultados ... Agregue que en mi caso estaba trabajando con la abstracción Promise (por razones que lo dejaré fuera), por lo que esta función de procedimiento de prueba generalizada naturalmente tiene que devolver esa promesa. Pan y mantequilla es una clase de cosas, hasta ahora todo bien.

Ahora vienen los escenarios de prueba, ya que empaquetamos todo en nuestra función de procedimiento de prueba, los casos de prueba definen efectivamente las entradas e invocan la función.

Entonces, tal vez escribo un montón de pruebas como esta, y todo _ parece_ estar funcionando:

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

Si está siguiendo de cerca, probablemente ya se habrá dado cuenta de que este ejemplo tiene un error. Le falta su return , y dado que testProcedureFunction se basa en promesas (juego de palabras), siempre va a pasar sin importar si las afirmaciones al final pasan o fallan. Se trata de un error y, a veces, puede ser extremadamente sutil rastrearlo. Para ilustrar, dependiendo de cómo escribimos testProcedureFunction y cómo se escribe la aplicación, digamos que hay un código síncrono al principio, y eso explota en lugar de las afirmaciones de fin de prueba, el caso de prueba incluso podría fallar, lo que nos lleva pensar que todo está bien.

La prueba, por supuesto, debería verse así con un retorno:

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

Ahora sé que esta prueba será una línea en la mayoría de los casos. En realidad, cada caso será una línea, excepto cuando las entradas sean tales que se requiera un tiempo de espera mayor. Ahora, entre las diferencias entre las funciones js clásicas y las flechas, hay un aspecto particular de las funciones de flecha que es útil aquí: una función de flecha de declaración única tiene un retorno implícito cuando se omiten las llaves. Si en lugar de escribir un function {...} , una prueba usa el => ... , entonces puedo escanear fácilmente esos casos en busca de la flecha y la falta de llaves, e inferir rápidamente que no pueden tener este return faltante

Al igual que:

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

Ahora, ¿qué pasa si uno de estos casos tarda más que los demás? Por supuesto, podemos establecer el tiempo de espera de esta manera:

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

O tal vez alguien cometa un error y haga esto primero (lo que no funciona, por supuesto):

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

Pero ahora estamos de vuelta donde comenzamos, la base de código tiene un patrón listo para repetirse, que es susceptible al error de retorno faltante (ya sea por mi futuro o por la siguiente persona que agregue una función; el punto es que es fácil cometer un error, puede pasar desapercibido y puede ser difícil de localizar). La función when resuelve esto y nos permite usar flechas de manera consistente nuevamente:

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

(nota, no pude conseguir que funcionara la sugerencia de encadenamiento de puntos .timeout(5000) anterior, puede haber sido debido a la versión de mocha que necesitaba usar, ya no recuerdo, le daré un ¡tratar!)
(nota 2, observe que el uso de when no utiliza el truco de elevación de parámetros this ; en realidad, fue solo una idea posterior).

Tal vez haya linters que puedan marcar errores de devoluciones por promesa faltantes (o probablemente de manera más realista, imponiendo una declaración de devolución con un rhs para cada función). Sin embargo, esa no era una opción en ese momento, además creo que la sintaxis de la flecha es más corta y la encuentro (subjetivamente / personalmente) más fácil de leer y trabajar, lo que me alejó de function .

Así que ahí lo tienes.

No sé si tendré tiempo para responder de nuevo pronto, así que espero que sea al menos informativo y claro, y tal vez incluso ponga algo de la controversia en torno a todo el tema del "acceso al contexto moca desde las flechas" a cama.

Por último, dado que encontré function vs => confuso durante mucho tiempo, dejaré este enlace en caso de que no esté claro para cualquiera que lea casualmente por qué las flechas no pueden acceder a this . Fue la explicación más clara de funciones frente a flechas que encontré, y fue lo que finalmente me ayudó a comprender las diferencias lo suficientemente bien como para usarlas con total confianza.

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

@ thom-nic Funciona en it , pero no en 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, puede usar la forma de función normal

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

...
}

Cualquiera que se queje de esto no comprende las funciones de las flechas.

Las funciones de flecha NO son una nueva cosa elegante de ES6 que se supone que reemplaza al clásico function () {} . El único propósito de las funciones de flecha es que hereda this de su padre, donde el clásico function () tiene su propio this .

Sí, incluso cuando use la sintaxis completa de ES6, aún debería usar function () si desea usar this en el contexto correcto de su función. Debería utilizar tanto function () como () => en su aplicación ES6 dependiendo de lo que esté intentando hacer.

this.timeout() no funciona con it('....', () => { ... }) porque la devolución de llamada hereda this de la función principal describe() , en la que this.timeout() no tiene sentido en ese nivel.

¿Las funciones lambda también le permiten enviar automáticamente un solo argumento a la función sin declararlo en la llamada?

(param) => aFunción
... entonces (una función)

function () {} se puede vincular a 'this' pero () => está 'bloqueado'

Las funciones de flecha deben reemplazar la función tradicional cuando el receptor espera un 'esto' predeterminado en el mismo contexto desde el que se llama, (y también beneficiarse de escribir menos código).

Me atrevería a decir que nunca uses function () a menos que quieras que 'this' sea algo distinto de lo que es 'this' cuando lo invoques.

@Flamenco...

¿Las funciones lambda también le permiten enviar automáticamente un solo argumento a la función sin declararlo en la llamada?

No estoy seguro de entender _exactamente_ cómo lo estás diciendo.
En cuanto a "enviar argumentos a la función", las flechas gruesas funcionan igual que las funciones normales con una única excepción: si tiene exactamente 1 argumento, puede dejar los paréntesis.

() => 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

A lo que puede haber llegado es a que las flechas gruesas le permiten _devolver_ un valor omitiendo las llaves y la palabra clave return siempre que su función sea una sola expresión.
Entonces, si tuvieras ...

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

... y quería convertir eso en una función de flecha gruesa, no podría quitar las llaves y la palabra clave return porque el cuerpo de la función tiene varias declaraciones. Lo harías así ...

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

Si más bien empezaste con ...

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

... entonces estás tratando con una función tan simple que solo devuelve una sola expresión y podrías usar ...

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

¡Eso se volvió mucho más fácil de leer!
Escribí un poco más sobre esto en codefoster.com/levelup-arrays .

Hay muchos estilos de codificación diferentes en JavaScript, desde OOP hasta FP, desde estricta seguridad de tipos hasta mixin / duck-typing. Además, existen patrones avanzados en cada uno de esos estilos (es decir, inyección de dependencia en el campamento OOP, curry / mónada en el campamento FP).

Si su estilo de codificación está más cerca de FP donde this no se usa y las funciones de flecha se usan para reducir el texto estándar, tener que preservar this es una sobrecarga adicional para cualquier prueba avanzada (por ejemplo, pruebas parametrizadas, creación DSL).

Cualquier desarrollador experimentado puede empaquetar previamente el marco de prueba para que se adapte a su estilo de codificación, pero eso significa que el marco está menos "listo para usar". Eso se traduce en trabajo adicional para actualizar, adoptar complementos e incorporar nuevos ingenieros.

Me gusta la idea de una interfaz alternativa bdd que no usa this y en su lugar pasa lo que normalmente sería el objeto de contexto como parámetro a describe , it y ganchos.

Pero no es tan sencillo de implementar, IIRC. Sin embargo, sería genial ver un intento.

Sé que esto está llegando a la tierra de los efectos secundarios graves, pero ¿no podrías lidiar con el parámetro hecho o contexto de algo como esto?

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)
})

Usé el siguiente script pero obtuve el mismo error de exceder el tiempo de espera.

Myscript:

describe ("getBillingDetail", función asíncrona () {
this.timeout (55000);
it.only ("comprobar el nombre de trabajo válido dado", función asíncrona (hecho) {
this.timeout (55000);
var result = await url.getBillingDetail ('12254785565647858');
console.log (resultado);
asert.equal (resultado, verdadero);
});
});

Error: se excedió el tiempo de espera de 55000 ms. Para pruebas asíncronas y ganchos, asegúrese de que se llame a "done ()"; si devuelve una Promesa, asegúrese de que se resuelva.

No pase una devolución de llamada realizada a una función asincrónica

He creado un prototipo de solución que es compatible con versiones anteriores. Por ahora es un módulo separado, pero la funcionalidad podría fusionarse fácilmente en mocha propiamente dicha.

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

manera rápida

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()
  })
})

para nombres explícitos (y funciona con 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 El enlace es 404 no encontrado.

Woops ... era un repositorio privado. ahora público

También puedo npm i mocha-lambda

@aleung @ linesh-simplicity, esto es reemplazado por # 3485

Gracias.

¿Por qué tanta "magia" que, al final, produce problemas? ¿Por qué no esto ?:

var mocha = require('mocha');

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

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

Sin globales, sin magia problemática ... solo JavaScript.

ver la respuesta de @ thom-nic, limpiar y hacer el truco

Juro que leí en algún lugar que podrías hacer algo como esto:

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

que no altera el contrato del parámetro a la función proporcionada. Ahora no puedo encontrar ninguna referencia a algo así, así que tal vez simplemente lo imaginé.

La solución @ thom-nic funcionó para mí, ¡gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones