Mocha: Error: el método de resolución está sobreespecificado.

Creado en 2 ago. 2016  ·  84Comentarios  ·  Fuente: mochajs/mocha

Esta:

before(done => {
    return Promise
        .all([])
        .then(() => Model.insert(...)) // Bookshelf model returning a Bluebird Promise
        .then(() => done())
        .catch(done)
})

resultará en un error Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.

Los doctores dicen:

En Mocha v3.0.0 y más reciente, devolver una Promise y llamar a done () dará como resultado una excepción, ya que esto generalmente es un error:

La llamada del modelo se está resolviendo con un Promise.<Object> de la entrada recién insertada, sin embargo, si omito .then(() => done()) , los tiempos de espera de la prueba.

confirmed-bug

Comentario más útil

async funciones (babel) con done también se rompen.

Todos 84 comentarios

async funciones (babel) con done también se rompen.

Como indica el error, no se supone que debe proporcionar una función con una aridad de> 0 (lo que significa que está aceptando una devolución done llamada

La forma más fácil de solucionarlo sería omitir el return , pero como estás usando promesas, sugiero deshacerte de la devolución done llamada

before(() => Promise.all([]).then(() => Model.insert(...)));

Aquí hay un ejemplo de async (esencialmente una promesa) y done que se rompe:

it('fires change event when calling blah.doSomethingThatFiresChange', async function (done) {
  const blah = await getBlah()
  blah.on('change', () => done())
  blah.doSomethingThatFiresChange()
})

@elado Ese es un caso de uso interesante, aunque desde el punto de vista de mocha es la misma situación: una función que toma una devolución done llamada

it('fires change event when calling blah.doSomethingThatFiresChange', async function () {
  const blah = await getBlah()
  return new Promise(resolve => {
    blah.on('change', resolve)
    blah.doSomethingThatFiresChange()
  })
})

... pero supongo que a lo que te refieres es que en este ejemplo, sería mejor si mocha esperara a que se resuelva la promesa y se llame a la devolución de llamada.

Desafortunadamente, esa combinación en particular suele ser un error en la prueba, por lo que este mensaje de error se agregó en primer lugar.

... si omito .then (() => done ()) entonces los tiempos de espera de la prueba

En cualquier caso, esto parece un error.

@ScottFreeCode Hmm, sí, parece ser porque el error "sobreespecificado" se emite en la función proporcionada como devolución done llamada https://github.com/mochajs/mocha/blob/4944e31ff60105815f4b314996a9861e73f6bfd2/lib/ runnable.js # L357 -L373

... pero, por supuesto, podemos determinar que tenemos que fallar con ese error tan pronto como la función haya regresado.

@ScottFreeCode ¿Cuál es la solución aquí?

¿Voy a suponer que es "esperar a que la promesa se resuelva o rechazar, luego rechazar con el error 'sobreespecificado'"?

Si vamos a considerar done más la promesa en la misma prueba como un error, no veo ninguna razón para no detectar el error tan pronto como una función de prueba que tomó done devuelva un promesa, como sugirió @papandreou . No tiene mucho sentido para mí tratar de averiguar qué otros puntos deberían desencadenar el error a menos que pretendamos permitir promesas y done juntos en algunos casos.

@ScottFreeCode Estoy de acuerdo. Entonces es

  1. Detectar problema; instancia el Error pero no llame a done() con él
  2. Espere hasta el cumplimiento de la promesa
  3. Rechazar con Error

Pregunta adicional: ¿Qué hacer con el resultado del cumplimiento de la Promesa?

Ah, creo que lo entiendo, incluso cuando detectamos el error, debemos dejar que la prueba se ejecute para que no siga ejecutando su código durante la siguiente prueba y, tal vez, para que también podamos informar el resultado de la prueba.

¿Podría una prueba también terminar llamando a done sin resolver o rechazar la promesa? Si es así, ese es otro caso final que tendremos que manejar.

Mi inclinación, re. qué hacer con el resultado de la prueba, es que si se agota el tiempo de espera (sin que se haya llamado a done o se haya resuelto / rechazado la promesa), deberíamos informar el uso de done con la promesa (porque la confusión sobre la combinación podría ser la razón por la que nunca llegó a ninguno de los dos y se agotó el tiempo), pero si logra terminar por cualquiera de los medios, entonces presumiblemente el resultado es válido (o al menos de alguna manera significativo) y deberíamos informar tanto el uso posiblemente erróneo de done y la promesa juntos como el resultado de la prueba con la esperanza de que sea al menos algo útil.

Eso es lo mejor que se me ocurre en este momento, de todos modos, pero podría tener más información si puedo encontrar el tiempo para profundizar en este problema.

Bueno, podemos hacer esto en fases. La primera sería asegurarse de que si se devuelve una Promesa y se devuelve una llamada done , Mocha se romperá de manera amistosa.

Es _concebible_ que uno pueda hacer algo como esto (con Bluebird):

// to make this work, you need to omit `return`
it('should do something async for sure', function(done) {
  return somethingAsync()
    .then(makeAssertion)
    .asCallback(done);
});

Pero eso es algo que usted _ podría_ hacer; Todavía tengo que determinar un caso de uso para esto.

Creo que me he confundido. No estoy seguro de que haya un error aquí.

Este es más un problema de tipo "IU deficiente"

Agotar el tiempo de espera para que se llame a done a pesar de que una promesa devuelta se resuelve / rechaza es definitivamente un error, independientemente de si queremos no permitir que tales pruebas usen done y promesas juntas en la primera sitio. Esto debería usar el resultado de la promesa y / o el error porque la promesa y done se utilizaron en la misma prueba, pero no solo el tiempo de espera porque uno de los dos nunca se completó cuando el otro lo hizo (lo que es lo que hace actualmente):

it("should not time out", function(done) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve.bind(42), 50)
  })
})

1) no debe agotarse el tiempo:
Error: se superó el tiempo de espera de 2000 ms. Asegúrese de que se llame a la devolución de llamada done () en esta prueba.

En cualquier caso, miraré las relaciones públicas ...

Las partes interesadas deben ver el número 2413.

@briansipple

Recibo el mismo error al usar varios ganchos asíncronos beforeEach en la versión 3:

  beforeEach((cb) => connection.db.collection('users').remove({}, cb));
  beforeEach((cb) => connection.db.collection('accounts').remove({}, cb));
  beforeEach((cb) => connection.db.collection('accounts').insertOne(account1, cb));

¿No es posible seguir usando enlaces asíncronos de esa manera?

Descubrí mi problema: mis métodos dentro de cada gancho devuelven una promise (no sabía eso porque no estaba usando promesas en esos casos) y obviamente también estoy pasando la función cb .

No creo que sea una buena idea. Si uno solicita una devolución de llamada, creo que ha dejado claras sus intenciones. El error aquí es solo una molestia. Elimínelo.

Esto no es realmente una cuestión de intención. De la descripción de # 1320:

Cuando se especifica una función de devolución de llamada y un objeto Promise
devuelto, la condición de resolución del Runnable es ambigua.

No es ambiguo, se solicitó la devolución de llamada. ¿Cómo es eso de ambiguo?

Estoy de acuerdo con que @RobertWHurst no hay ambigüedad aquí.

Además de eso, creo que este tema podría ser algo "basado en opiniones" y los desarrolladores tendrán diferentes puntos de vista. Considero que es muy extremista hacer un cambio radical y obligar a la gente a usarlo de esa manera.

No obligamos a nadie a hacer nada. Lanzamos un importante, que por definición tendrá cambios importantes. No rompimos semver.

No creo que se refiera a que rompiste Semver, creo que se refiere a que rompiste a Mocha. Este cambio no facilita las cosas a los desarrolladores, está forzando una opinión.

beforeEach((cb) => connection.db.collection('users').remove({}, cb));
            ^^

^^ Eso no es ambiguo. Está bastante claro lo que espera el autor. El autor ha hecho todo lo posible para solicitar una devolución de llamada.

En realidad, la razón por la que obtiene una excepción aquí es por evitar al máximo hacer cumplir la opinión. Mocha no tiene una opinión sobre si la promesa devuelta o la devolución de llamada son autorizadas. No puede tener ambos al mismo tiempo ya que eso conduce a resultados ambiguos. Los resultados ambiguos en un marco de prueba deben considerarse un error. De ahí el mensaje de error para ayudarlo a ser consciente de esto y hacer la elección y el cambio que coincida con su opinión.

Podría ser beneficioso reducir la cantidad de drama. "Rompiste Mocha" no ayuda a nadie. Un aumento de la versión principal de semver se define explícitamente como cambios importantes que pueden requerir que ajuste su código. Puede permanecer en 2.x para que tenga tiempo de realizar los cambios necesarios para corregir sus pruebas. Esta es una evolución, no una ruptura

@Munter Todavía no sé cómo solicitar una devolución de llamada es ambiguo. Si solicita una devolución de llamada, se espera que la use. De lo contrario, es un error de programación. Esta es una acción explícita del autor de la prueba.

Si sientes drama, me refiero a ninguno. "Rompiste Mocha" no pretende ser hiperbólico. Creo que esto va en contra del diseño del módulo y rompe el contrato de API original.

Como meintonizado antes de babel async / await no funciona bien con new mocha @ 3. Ejemplo:

it('should fill userName and password', async function (done) {
    const userNameField = global.driver.wait(until.elementLocated({css: '#username'}));
    userNameField.sendKeys('admin');

    const passNameField = global.driver.findElement({css: '#password'});
    passNameField.sendKeys('*******');

    const userNameVal = await userNameField.getAttribute('value');
    const passwordVal = await passNameField.getAttribute('value');

    try {
      assert.equal(userNameVal, 'admin');
      assert.equal(passwordVal, 'changeme');
    } catch (error) {
      done(error);
      return;
    }

    done();
  });

Este código funciona bien con mocha @ 2 pero no con mocha @ 3 porque en await devuelve promesa

Creo que este PR es relevante aquí => https://github.com/mochajs/mocha/pull/2413
Más complejidad para lidiar con los casos extremos de este error.

@artyomtrityak Ese es un gran ejemplo de dónde done es innecesario.

Los detractores han dicho su parte. Sin embargo, los mantenedores de Mocha no están de acuerdo con el argumento (s) para revertir este cambio. Eran Hammer dijo (parafraseado): "Como mantenedor, una de las cosas más difíciles que puede hacer es decepcionar a aquellos que quieren llevar el trabajo en su dirección".

Soy bienvenido a soluciones alternativas: más documentación (por ejemplo, más ejemplos de este error y cómo solucionarlo), mejores mensajes de error, pero no estoy interesado en el drama, la mala educación o las quejas. Contribuir con cualquiera de estas soluciones a Mocha ayudaría a convertir lo negativo en positivo.

Si no le gusta este cambio y simplemente no puede ser constructivo al respecto, es OSS: puede bifurcar el proyecto y revertir los cambios allí.

@boneskull se transforma en funciones asíncronas que devuelven promesas, no necesito terminar mi caso de prueba cuando la promesa se cumplirá, pero necesito hacer algunas verificaciones personalizadas en torno a los resultados. Como dije, este código funciona perfectamente bien con mocha @ 2 pero con mocha @ 3 no. Entonces mi equipo (~ 20ppl) no puede pasar al último moka debido a esto.

Actualmente mocha 2.x ofrece mucha flexibilidad, ¿hay alguna razón técnica para este cambio?

@artyomtrityak Ese es un gran ejemplo de dónde no es necesario hacerlo.

¿Puede dar un ejemplo de cómo debería verse esto con la sintaxis de babel async/await y sin return new Promise ?

@artyomtrityak ¿Qué tal aceptar plenamente las promesas? Entonces puede acortar su prueba a:

it('should fill userName and password', async function () {
    const userNameField = global.driver.wait(until.elementLocated({css: '#username'}));
    userNameField.sendKeys('admin');

    const passNameField = global.driver.findElement({css: '#password'});
    passNameField.sendKeys('*******');

    const userNameVal = await userNameField.getAttribute('value');
    const passwordVal = await passNameField.getAttribute('value');

    assert.equal(userNameVal, 'admin');
    assert.equal(passwordVal, 'changeme');
  });

Si se siente atacado personalmente, entonces creo que debe reconsiderar qué tan involucrado emocionalmente está en esta conversación. Ninguno de los comentarios ha sido personal. Estoy seguro de que están muy bien, especialmente si se tiene en cuenta que ha donado su tiempo para ayudar a mantener este proyecto, que es muy apreciado y muy encomiable.

La mayoría de ustedes (los mantenedores activos actualmente) comenzaron a trabajar en Mocha a mediados de 2014. Mocha ya estaba establecido cuando ustedes empezaron a contribuir. Es solo mi opinión, pero no creo que sea el único que piense que uno no debería hacer cambios importantes en una biblioteca establecida a menos que esté justificado. Aunque puedo imaginar la justificación original de este cambio, no se sostiene bien cuando uno señala lo siguiente. Solicitar una devolución de llamada comunica una intención clara. Las promesas no son tan claras porque no se solicitan, se devuelven, lo que puede suceder de forma indirecta y accidental (devueltas de una biblioteca de terceros, por ejemplo). Debido a estas diferencias, las dos formas de ceder no son iguales y, por lo tanto, tratar de utilizar ambas no es realmente ambiguo. Las devoluciones de llamada deben escribirse en los argumentos de prueba. No puede hacer eso con promesas, por lo que al solicitar una devolución de llamada, ha comunicado sus intenciones explícitamente. Su comunidad planteó estas inquietudes y, en lugar de reconocer el paso en falso, ustedes están redoblando. Parece que incluso está considerando forzar las pruebas a ser asíncronas para garantizar que este error actúe de manera consistente. Ver => https://github.com/mochajs/mocha/pull/2413. Parece un gran cambio para un mensaje de error que protege contra un error poco probable.

Ustedes han hecho un gran trabajo manteniendo esta biblioteca desde la partida de @tj , ¿podrían pensar un poco más en este cambio? Mi preocupación es que esto podría comprometer la biblioteca.

Totalmente de acuerdo con @RobertWHurst.

Solicitar done debe anular el comportamiento de la promesa devuelta. No es probable que solicite done cuando no es necesario, y los escenarios de eventos emitidos en una función async son un ejemplo perfecto.

De mi comentario anterior:

it('fires change event when calling blah.doSomethingThatFiresChange', async function (done) {
  const blah = await getBlah()
  blah.on('change', () => done())
  blah.doSomethingThatFiresChange()
})

A medida que más personas pasen a ES6 / 7 + async / await , esto se convertirá en un problema común al usar Mocha.

Reconsidere este cambio.

@RobertWHurst Usted argumenta que definir una devolución done llamada return no es una intención explícita? Ambos están definidos en su código por usted. ¿Cómo podemos decidir que una parte de su código es intencional y otra no? Si imagina un mundo antes de () => foo cualquier declaración de devolución siempre habría sido explícita. La única razón por la que están todos en armas ahora es porque ha comenzado a usar declaraciones de retorno implícitas, por lo que solo puedo pensar que son razones estéticas.

Dado que gran parte del uso de Mocha es por principiantes que generalmente copian / pegan ejemplos, que muy probablemente contienen una devolución done llamada

El comportamiento actual es mucho más claro sobre lo que está mal que solo un tiempo de espera inesperado

@Munter Con las async en la imagen, creo que la promesa devuelta obtiene una puntuación más baja en la escala de explícita porque se crea y devuelve automáticamente, ya sea que use o no await :

it('should work with a async function that could have been sync', async function () {
  assert.ok(true);
});

it('should work with a legitimately async function', async function () {
  assert.equal(await getBlah(), 'blah');
});

it('should work with a fully spelled-out Promise-based test', function () {
  return getBlah().then(function (blah) {
    assert.equal(blah, 'blah');
  });
});

Y luego está el controvertido:

it('should foo', async function (done) {
  assert.equal('foo', 'foo');
  done();
});

También es fácil para ese pequeñito async colarse por accidente, por lo que deberíamos pensar en (al menos) el primer ejemplo como un nuevo tipo de trampa , como señala

Después de una pequeña conversación aquí => https://github.com/mochajs/mocha/pull/1320, tuve una idea para una solución alternativa al problema. Agregué un PR para su placer de revisar aquí => https://github.com/mochajs/mocha/pull/2454

: cervezas:

Usted argumenta que definir una devolución de llamada realizada es una intención explícita. ¿Una declaración de devolución no es una intención explícita?

@Munter No olvide que las expresiones de función de flecha coffeescript y es6 devuelven _ implícitamente_, por lo que puede hacer algo como

it 'should foo', (done) -> request('/foo').end (err, res, body) -> done()

y piensa que estás a salvo. Pero este problema significa que tienes que transformar esa bonita frase en algo como

it 'should foo', (done) ->
  request('/foo').end (err, res, body) -> done()
  return

Este es exactamente nuestro problema con nuestro código base general en cada uno y mecano . Considera esto:

it 'should foo', (done) ->
  obj =
    run: ->
      done()
      @
    then: -> "what the hell, i'm not a promise"
  obj.run()

Esto no es completamente específico de coffeescript, pero devolver valores implícitos lo hace peor. Mocha debería detectar instancias de promesa válidas. Además, tal vez una opción podría desactivar esta función.

Oigan todos,
Me encontré con este problema con el siguiente código;

describe('Page', ->
  describe('/GET home', ->
    it('it SHOULD return the homepage', (done) ->
      chai.request(app).get('/').end((err, res) ->
        res.should.have.status(200)
        res.text.should.be.a('string')
        done()
      )
    )
  )
)

Resolví esto respetando la cadena de promesa y omitiendo la devolución done() llamada

describe('Page', ->
  describe('/GET home', ->
    it('it SHOULD return the homepage', ->
      chai.request(app).get('/').then((res) ->
        res.should.have.status(200)
        res.text.should.be.a('string')
      )
    )
  )
)

Espero que esto ayude a otros, que se encuentran con un error similar: sonrisa:

PD : corazón: Mocha por cierto: +1:

EDITAR Eliminar catch() según el comentario de @Munter .

@karlbateman Gracias. Sin embargo, no necesitas ese último .catch . Mocha considera que una promesa rechazada es un error

@Munter ya veo, gracias: smiley:

Al pensarlo un poco más, realmente me gusta el comportamiento de esperar tanto la promesa como la devolución de llamada. ¿Se logró algún progreso en su implementación?

@ light24bulbs ¡ Gracias por los comentarios! No, afaik nadie empezó a trabajar en eso ya que es solo una idea que lancé allí para ver las reacciones. Ahora estaba comprobando si había habido comentarios adicionales sobre la idea, algún caso en el que no funciona, etc.

¿Hay alguna solución para esto al usar babel?

¿Hay alguna solución para esto al usar babel?

Envuelvo dos veces:

it("should work", done => {
  (async () => {
    await something;
    done();
  })();
});

@SaschaNaz gracias, esto funciona en v3.2.0 :)

6 meses después, este problema sigue frenando todas las pruebas js modernas ...
vergüenza

@benfavre Gracias por las palabras de aliento que definitivamente motivarán a los voluntarios a asumir la responsabilidad de implementar cualquier solución que no haya especificado en su tiempo libre en lugar de jugar con sus hijos.

@Munter No se preocupe, me alegro de haber podido ayudar a identificar un problema específico que enfrenté como nuevo usuario de mochajs.
@SaschaNaz sugirió que la solución de envolver dos veces no ayudó.

=> El uso exclusivo de promesas funcionó como debería.

La próxima vez supongo que debería hacer "+1" como un morrón para no ser insultado gratis.
No había nada insultante en mi mensaje, además, mi afirmación sigue siendo cierta.

La mayoría de las personas simplemente elegirán otro marco ... a partir de ahora, simplemente está roto con async / await, sin indicaciones claras en ninguna parte del sitio principal y sin un mensaje de error claro en el cli.

Feliz año nuevo y diviértete jugando con los niños.

Frío...

Las discusiones evolucionaron hasta "prestar atención" tanto a la devolución done llamada Promise : https://github.com/mochajs/mocha/issues/2509

Clausura. ver # 2509

En caso de que algún cuerpo todavía esté luchando ...

¿Hay alguna solución para esto al usar babel?

Ahora, con el controlador integrado para la promesa como se menciona en # 2509, no tenemos que usar el wrapping twice hack esta manera:

it("should work", done => {
  (async () => {
    await something;
    done();
  })();
});

En lugar de eso, simplemente podemos ir con esto:

it("should work", async () => {
  await something;
});

Consulte esta publicación para obtener más detalles.

@ lo-tp
1.) ¿este código funciona cuando se compila con babel?

it("should work", async () => {
  await something;
});

@SerkanSipahi

  • Sí, para usar la sintaxis async/await ahora, necesitamos la ayuda de babel.

No estoy seguro de si me falta algo ... pero resolví este problema al no usar ninguna declaración de devolución con mis Promesas y solo confiando en done ().

Aquí hay un ejemplo que me funciona

  describe('STRIPE CHARGES: Get Charges', () => {
    it('should list customer charges', async () => {
      const charges = await Stripe.getChargesList(customerObj);
      charges.data[0].should.have.property('id');
      charges.data[0].amount.should.have.property('id');
    });
  });

He estado usando mocha 4 con chai.assert.

Al principio traté de usar la devolución de llamada done () así.

it('should throw an error', async function(done) {
  try {
    result = await something('value that causes something() to throw an Error');
    done('failed');
  } catch (e) {
    done();
  }
});

Falló con el

Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both."

Ese error es lo que me llevó aquí, a esta página. Después de recorrer este hilo bastante largo (y admito que no entendí completamente todas las disputas), ¿debo entender que no debería usar done () en absoluto con llamadas asincrónicas porque están basadas en Promised?

Si es así, ¿cómo hago la siguiente prueba cuando la llamada para esperar algo () arroja un error y esto es lo que esperaría que sucediera?

it('should throw an error', async function() {
  try {
    result = await something('value that causes something() to throw an Error');
  } catch (e) {
    // how to indicate that this should happen, if I can't call done() to tell mocha?
  }
});

¿Podría alguien ayudarme a entender este caso específico, por favor? ¿Debería usar la biblioteca de aserciones o hay algo adicional que deba poner en el código anterior?

Muchas gracias.

La solución de bajo nivel y propensa a errores:

it('should throw an error', async function() {
  try {
    result = await something('value that causes something() to throw an Error');
    throw new Error('Promise unexpectedly fulfilled');
  } catch (e) {
    // Optionally assert something about e...
  }
});

Usaría una biblioteca de afirmaciones cualquier día de la semana:

const expect = require('unexpected');
it('should throw an error', async function () {
    await expect(something(), 'to be rejected with', 'the error message');
});

O chai + chai-como-prometido:

const chai = require('chai');
chai.use(require('chai-as-promised'));
const expect = chai.expect;

it('should throw an error', async function () {
    await expect(something()).to.be.rejectedWith('argh');
});

Hola chicos, este funciona bien con asyncawait (solo omita 'done ()')

describe('New order from landing', function() {
    describe('check new client function', function () {
        it("must check db and return that random client is new", async function () {
            var result = await handler.checkClient(reqNewClient.body)
                expect(result).to.have.property('newclient').equal(true)
            })
    })
})

resultado:

Nuevo orden desde el aterrizaje
comprobar la función del nuevo cliente
√ debe verificar db y devolver que el cliente aleatorio es nuevo
1 pase (9 ms)

@kolykhalov Gracias Funcionó para mí

En mi caso, envolví el bloque asíncrono en un intento / captura

it('It should activate a user.', async() => {
        return new Promise((resolve, reject) => {
            try {
                // Get the last activation token from the DB
                let sql = 'select * from activation_tokens order by created_at desc limit 1';
                let res = await DB.query(sql);
                let {token} = res[0];

                server
                    .post('/auth/activate')
                    .send({token})
                    .set('Content-Type', 'application/x-www-form-urlencoded')
                    .expect('Content-Type', /json/)
                    .expect(200)
                    .end((err, res) => {
                        res.body.data.should.contain.keys('message');
                        res.body.data.message.should.equal("Activated");
                        resolve();
                    });
            } catch (e) {
                console.error(e);
            }
        });
    });

Actualizado para evitar vulnerabilidades. Ahora tengo que reescribir 99 pruebas. FML

Entonces, para dejar en claro cuál es el problema, ya que algunos dicen que no debería necesitar usar done y async , aquí hay un ejemplo en el que le gustaría usar ambos.

it('should error on fn', async function(done) {
  try {
    await fn();
  } catch (e) {
    // assert some things here
    done()
  }
});

No usar done permitirá que la prueba pase si no se arroja ningún error. Algunos han sugerido usar cosas como expect(await fn).to.throw('blah') , pero a veces es necesario verificar más propiedades de las que caben en una sola línea.

Recibí este error pero accidentalmente estaba devolviendo una promesa (supertest)

it('Should do something', (done) => {
       return supertest(server)
           .get(`/api/endpoint`)
           .set('somekey', 'somevalue')
           .expect(200)
           .then(() => { done(); })
           .catch(done);
});

Eliminar la cláusula de 'devolución' resolvió el problema

Para cualquiera que se haya vuelto loco por esto ...

Esto funciona:

it("should work", async () => {
  await something;
});

Esto no lo hace:

it("should work", async (done) => {
  await something;
});

Debe eliminar done como parámetro.

@tamoyal , sí, como publicó Elado el 3 de agosto de 2016.

El uso de async / await devuelve un Promise implícito. El uso de la devolución done llamada
Asíncrono basado en aquí . Mocha admite ambos ... pero no al mismo tiempo.
Esto está documentado y ha sido un comportamiento estándar desde el lanzamiento de Mocha-3.0.

Recibí este error pero accidentalmente estaba devolviendo una promesa (supertest)

it('should do something', (done) => {
       return supertest(server)
           .get(`/api/endpoint`)
           .set('somekey', 'somevalue')
           .expect(200)
           .then(() => { done(); })
           .catch(done);
});

Eliminar la cláusula de 'devolución' resolvió el problema

@victorsferreira , parece que esta debería haber sido la solución ...

it('should do something', () => {
  return supertest(server)
    .get(`/api/endpoint`)
    .set('somekey', 'somevalue')
    .expect(200);
});

@tamoyal Sí, eso fue lo que me hizo tropezar. Es muy poco intuitivo tener una biblioteca de terceros que busque en los parámetros de una función que creo y use eso para tomar una decisión sin decirme que lo hizo.

@mienaikoe , este escenario exacto está explícitamente documentado , ya sabes ...

@plroebuck dos cosas:

1) Existe una diferencia entre documentar algo y ser una de las pocas bibliotecas en npm que hace introspección sobre los parámetros de una función. Podría documentar que realizo una verificación de antecedentes de todos mis amigos cuando los conozco por primera vez, pero sigue siendo extraño y la gente todavía se quejaría de ello a menos que yo tuviera un motivo y les dijera explícitamente el motivo.

2) Hay una falla en la documentación:

En Mocha v3.0.0 y posteriores, devolviendo una Promesa y llamando a done () ...

No se trata de llamar a done, se trata de _especificar done como parámetro_ si lo usa o no.

@mienaikoe

  1. Mocha verifica el segundo parámetro de it para ver si la función existe y (si es así) su aridad para determinar si el usuario agregó una devolución de llamada. Esto apenas se califica como introspección y se usa comúnmente en JavaScript.
  2. Envíe PR para corregir la documentación si cree que es demasiado vaga.

¡Eliminar hecho como parámetro funcionó para mí!

ANTES DE:

image

¡Después del trabajo!)

image

@QauseenMZ , no ve ninguna diferencia entre su código "antes" y "después".

Tampoco estás devolviendo tu promesa. ¿No debería ser más parecido a lo siguiente?

  it('should receive successful RPC response', async () => {
    return await getResponse(unitData)
      .then((res) => {
        expect(res).to.have.status(200);
      });
  });

PD. El orden de su argumento de devolución de llamada de nodo está dañado ... error _ siempre_ va primero.

@plroebuck ¡ Gracias por mencionar! Acabo de editar eso.

No estoy manejando la promesa porque la función getResponse está devolviendo una devolución de llamada. Fue la única forma en que lo hice funcionar. La función getResponse es la siguiente:

image

Aquí el error es el segundo parámetro solo porque la función getResponse de devolución de llamada está regresando. Por favor déjeme saber lo que piensa al respecto. ¡Gracias!

Algunas partes parecen un poco ilógicas. Solo para mayor claridad, ¿qué paquete request estás usando?
¿Por qué necesitarías devolver el objeto options (lo que llamaste unitData )?

  • ¿De dónde viene obj ?
  • ¿Por qué tendrías un res.body.error con un res.statusCode === 200 ?

PD. Simplemente pegue el código en sí en lugar de imágenes del código ...

Para cualquiera que se haya vuelto loco por esto ...

Esto funciona:

it("should work", async () => {
  await something;
});

Esto no lo hace:

it("should work", async (done) => {
  await something;
});

Debe eliminar done como parámetro.

@tamoyal Me salvaste la vida <3

Esto se rompe y da como resultado el mismo error:

it('Location Querying Works', async () => {
    await WeatherComponent.pullLocationData();
    Vue.nextTick(()=>{
      expect(WeatherComponent.$el.textContent).contain("Spain")
    })
  })

Para darle una solución rápida a este problema, envuelva toda la prueba en una promesa y use resolve como lo haría done .

Gire esto:

it.only("Works with the database", async (done) => {
    let browser = await puppeteer.launch();
    let query = db.collection('lists').where('ownerId', '==', 'UJIXXwynaCj8oeuWfYa8');
    let ct = 0;
    query.onSnapshot(async querySnapshot => {
        if (ct === 0) {
            await addAPurpose(browser, session, sessionSig); // A function with a bunch of Puppeteer code.
            ct++
        } else {
            expect(querySnapshot.size).to.equal(1);
            expect(querySnapshot.docs[0].get().title).to.equal("Understand Mocha");
            done();
        }
        console.log(`Received query snapshot of size ${querySnapshot.size}`);
    }, err => {
        console.log(`Encountered error: ${err}`);
    });
});

dentro de esto:

it.only("Works with the database", async () => {
    const onSnap = new Promise(async (res, rej) => {
        let browser = await puppeteer.launch();
        let query = db.collection('lists').where('ownerId', '==', 'UJIo1gGMueoubgfWfYa8');
        let ct = 0;
        let unsubscribe = query.onSnapshot(async querySnapshot => {
            if (ct === 0) {
                await addAPurpose(browser, session, sessionSig);
                ct++
            } else {
                expect(querySnapshot.size).to.equal(1);
                expect(querySnapshot.docs[0].data().title).to.equal("Evolution");
                // done(); 
                unsubscribe();
                res();
            }
            console.log(`Received query snapshot of size ${querySnapshot.size}`);
        }, err => {
            console.log(`Encountered error: ${err}`);
            rej()
        });
    });
    return onSnap;
});

Y funciona como quieres.

La necesidad de eliminar done me sorprendió, porque la prueba se ejecutó hasta que se llamó a done. Para que sea más obvio que done no debe usarse con async, las funciones async deben fallar _inmediatamente_ si se pasa done. Mocha debe comenzar la prueba de la siguiente manera:

  1. Ver si la función es asíncrona y
  2. Detectando el argumento done .

Si ambos están presentes, debería lanzar en lugar de dejar que mis pruebas se ejecuten hasta que se llame a done y luego me llame azul. Luego, el error debería sugerir que envuelva su código en otra promesa y use resolve como lo haría done .

Sé que puedes usar function.prototype.name === "AsyncFunction" . Entonces es

if (function.prototype.name === "AsyncFunction && arg1.name === "done") {
  throw new Error("Can't use done with an async function")
}

para implementar esto.

Estaba casi SOL en esto. Necesito ejecutar código asincrónico Y se espera que el código no termine de ejecutarse (nunca), así que TENGO que usar hecho. El hack-a-round molesto fue envolver mi código de prueba asíncrono en una función asíncrona que se invoca automáticamente, pero dejar la función it como una función de sincronización.

Solución:

it("It shouldn't be like this", function (done) {
    ( async function(){
        var life = require('InfiniteLife');
        var asyncRes = await life.someCoolstuff();
        assert(asyncRes);
        setTimeout( function(){
            done();
        },letsCallItQuitsNow);
    })();
});

Un ejemplo de funciones asíncronas con ruptura terminada.

it('If the credentials exists in the system it should return the token generated against it.', async (done) => {
        let aObj = await admin.createAdmin();
        chai.request(server)
        .post("/authenticate")
        .set("Content-Type", "application/x-www-form-urlencoded")
        .send({username: aObj.login,password:aObj.password})
        .end((err, res) => {
            res.should.have.status(200);
            res.body.should.be.a("string");
            done();
        });
    });

Caso de éxito

it('If the credentials exists in the system it should return the token generated against it.', async () => {
        let adminObj = await admin.createAdmin();
        chai.request(server)
        .post("/auth/login")
        .set("Content-Type", "application/x-www-form-urlencoded")
        .send({username: adminObj.login,password:adminObj.password})
        .end((err, res) => {
            res.should.have.status(200);
            res.body.should.be.a("string");
            // done();
        });
    });

@ Haisum92

No necesita done ni async en su prueba. Chai http devuelve una promesa. Las pruebas de Mocha funcionan con código asíncrono si devuelve una promesa.

it('If the credentials exists in the system it should return the token generated against it.', () => {
  let adminObj = await admin.createAdmin();
  return chai.request(server)
    .post("/auth/login")
    .set("Content-Type", "application/x-www-form-urlencoded")
    .send({username: adminObj.login,password:adminObj.password})
    .end((err, res) => {
      res.should.have.status(200);
      res.body.should.be.a("string");
    });
});

@NateZimmer

Su solución publicada es para agotar el tiempo de la prueba si toma demasiado tiempo. Mocha ya tiene esta funcionalidad incorporada.

it("It should be liek this", async function () {
  this.timeout(letsCallItQuitsNow);

  var life = require('InfiniteLife');
  var asyncRes = await life.someCoolstuff();
  assert(asyncRes);
});

Su ejemplo tampoco parece fallar en la prueba si se excede el tiempo de espera, así que tenga cuidado con la corrección de la misma.

`Usando express / js y las funciones de la nube de firebase, verifique las respuestas de error de la API, luego obtenga un token e intente nuevamente. Asegúrese de que si usa express devuelve .json y no .send, también funciona logger bugs con mocha, así que use simple console.log.
Asegúrese de usar async y emitir completamente

  process.env.NODE_ENV='TESTING';
  const { FIREBASE_UID } = require('dotenv').config()?.parsed;
  const { red, green, white } = require('chalk');
  const chai = require('chai');
  const chaiHttp = require('chai-http');
  const server = require('../lib/api').API;
  const should = chai.should();
  const expect = chai.expect;
  chai.use(chaiHttp);
  const test = chai.request(server).keepOpen();

  const shouldPrint = (details, status) => {
      return white(`details: ${details}, status: ${status}`);
  };

describe('Authorization Middleware Error Check for bad token', () => {

    it(shouldPrint('Bad Request', red(400)), async () => {
        try {
            const res = await test.get('/').send()
            res.should.have.status(400);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('Bad request')
            expect(status).to.equal(400)
        } catch (error) { 
            throw error 
        }
    })


    it(shouldPrint('Unauthorized', red(401)), async () => {
        try {
            const res = await test.get('/').set('Authorization', 'Bearer bad123token').send()
            res.should.exist
            res.should.have.status(401);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('Unauthorized')
            expect(status).to.equal(401) 
        } catch (error) {
            throw error
        }
    })

})

 describe('Get token and ping', () => {
    let adminToken

    it(shouldPrint( 'Create custom jwt for testing', green(200)), async () => {
        try {
            const res = await test.get(`/createToken/${FIREBASE_UID}`).send()
            res.should.exist
            res.should.have.status(200);
            res.should.have.json
            adminToken = (JSON.parse(res.text)).token
        } catch (error) {
            throw error
        }
    })

    it(shouldPrint('PING', green(200)), async () => {
        try {
            const res = await test.get('/')
                .set('x-tenorders-testing', 'true')
                .set('Authorization', `Bearer ${adminToken}`).send()

            res.should.exist
            res.should.have.status(200);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('PING')
            expect(status).to.equal(200)
        } catch (error) {
            throw error
        }   
    })

})
'

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