Sinon: Prueba que falla inesperadamente después del lanzamiento de la v7.2.0

Creado en 23 jul. 2019  ·  11Comentarios  ·  Fuente: sinonjs/sinon

Describe el error
La actualización de Sinon a la última versión v7 provoca algunos fallos inesperados. El único cambio relevante que pude identificar fue este PR: # 1955 - Reemplazo de deep-equal.js con samsam.deepEqual .
Las pruebas pasan en todas las versiones hasta la 7.2.0, volver a 7.1.1 (una versión anterior) no causa ningún problema y todas las pruebas pasan.

Error observado:

AssertionError: expected addTracks to have been called with arguments [{ language: "en", trackContentType: "CEA608" }]
[[functionStub] { language: "en", trackContentType: "CEA608" }] [{ language: "en", trackContentType: "CEA608" }]

Prueba que produce error:

    it('should call getTextTracksManager, Track, and setCaptionLang', () => {
      sinonSandbox.stub(chromecastReceiver, 'setCaptionLang');
      chromecastReceiver.player.getTextTracksManager = sinonSandbox.stub()
        .returns({ addTracks: sinonSandbox.spy() });
      sinonSandbox.stub(cast.framework.messages, 'Track').returns(() => ({}));

      chromecastReceiver.loadCaptions('off');

      expect(chromecastReceiver.player.getTextTracksManager).to.have.callCount(1);
      expect(cast.framework.messages.Track).to.have.been
        .calledWith(3, cast.framework.messages.TrackType.TEXT);
      expect(chromecastReceiver.textTracksManager.addTracks).to.have.been.calledWith([{
        trackContentType: cast.framework.messages.CaptionMimeType.CEA608,
        language: 'en',
      }]);
      expect(chromecastReceiver.setCaptionLang).to.have.been.calledWith('off');
    });

Reproducir
Pasos para reproducir el comportamiento:

  1. Utilice cualquier versión de Sinon anterior a la 7.1.1
  2. Ejecutar prueba de muestra (arriba)
  3. Ver error

Comportamiento esperado
La prueba debe pasar

Capturas de pantalla
Si corresponde, agregue capturas de pantalla para ayudar a explicar su problema.

Contexto (complete la siguiente información):

  • Versión de la biblioteca: 7.2.0+
  • Entorno: macOS 10.14.5

Por favor, avíseme si puedo proporcionar más información al respecto.

Bug Regression pinned

Comentario más útil

Hola @ fatso83 ,

Gracias por tomarse su tiempo para investigarlo. Hice lo que me pediste y creé una demostración de runkit que muestra el error. Simplemente comente / descomente las diferentes declaraciones require('sinon') y ejecute el código para ver el error.

https://runkit.com/danielkg/sinon-issue-reproducible-bug-template

Publico el código aquí también en caso de que runkit no funcione por alguna razón.

// Employs 'mini-mocha' to emulate running in the Mocha test runner (mochajs.org)
require("@fatso83/mini-mocha").install();
// const sinon = require('[email protected]'); // WORKS!
const sinon = require('[email protected]'); // FAILS!
// const sinon = require('sinon');       // FAILS!
const { assert } = require('@sinonjs/referee');

const SAMPLE_USER = {
    id: 1,
    name: 'Kid',
    age: 22,
    weight: 83.5,
    notes: [{ txt: 'abc' }, { txt: 'def' }, { txt: 'ghi' }],
};

class MyUser {
    constructor(id, name, age, weight, notes = []) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.notes = notes;
    }
}

const createFakeUser = overrides => ({
    id: '007',
    name: 'Bond',
    ...overrides,
});

class Talkie {
    talk(user, topic) {
        console.log('talked to', user.name, 'about', topic);
    }
}

const action = (userId, talkie) => {
    const { name, age, weight, notes } = SAMPLE_USER;
    const user = new MyUser(userId, name, age, weight, notes);

    talkie.talk(user, 'apples');

    return user;
}


describe('stubbing', () => {
    const talkie = new Talkie();

    afterEach(() => {
        sinon.restore();
    });

    beforeEach(() => {
        sinon.spy(talkie, 'talk');
    });

    it('is the same user', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        assert.equals(JSON.stringify(userA), JSON.stringify(userB));
    });

    it('should set the return value', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        sinon.assert.calledWith(talkie.talk, userB, sinon.match.string);
    });
});

Por favor, eche otro vistazo cuando tenga tiempo. Gracias.

Saludos cordiales,
Daniel

Todos 11 comentarios

Gracias por un excelente informe de errores. Sin embargo, tiene un gran déficit: ¡no puedo ejecutar su ejemplo para verificarlo o rastrear el error! No se puede ejecutar por sí solo y, sin una forma de reproducirse, es difícil solucionarlo.

¿Podrías hacer un candidato mínimo para la reproducción? No tiene que replicar todo el ejemplo original, más como una simplificación como var myObject = { aMethod: function(){}, aProp: 42 }; // etc .

Si hubiéramos sabido que esto se estaba rompiendo, por supuesto habríamos mejorado la versión principal, ¡así que una prueba de regresión sería genial!

PD Parece que sinon-chai también está involucrado. Vale la pena enumerarlo.

@ fatso83 Déjame ver cómo puedo obtener un ejemplo aislado y ejecutable para la reproducción

¿Alguna actualización?

Este problema se ha marcado automáticamente como obsoleto porque no ha tenido actividad reciente. Se cerrará si no se produce más actividad. Gracias por sus aportaciones.

@mantoni ¿No informó haber experimentado algo como esto en uno de sus proyectos?

Perdón por la falta de actualizaciones, ya no estoy asociado con el proyecto que contenía el problema. Si alguien más está experimentando el mismo problema, sería genial si pudiera proporcionar un ejemplo para la reproducción.

@ fatso83 No recuerdo

Cerrando como no se puede reproducir

Perdón por revivir este problema de entre los muertos, pero me encuentro con el mismo problema.

_El código siguiente está simplificado con fines ilustrativos.

En mi aplicación tengo esta clase

class MyUser {
  // ... some user properties  
}

y lo uso más tarde en una función de controlador Koa como esta

const mqClient = require('./mqClient');

// GET /userDetails/<id> endpoint
async function getUserDetailsController(req, res) {
  const user = new MyUser();

  // populate user with properties etc.
  user.id = '1';
  user.name = 'Hans Gruber';
  user.tasks = [{ id: '42', title: 'execute Nakatomi tower heist' }];

  // ... get more details ...

  // Notify other users about this user
  mqClient.notifyOthers(user);

  res.json({ ok: true, user });
}

Y en mi getUserDetailsController.test.js hago algo como esto:

const mqClient = require('./mqClient');

const createExpectedUser = overrides => {
  id: '1',
  name: 'Hans Gruber',
  tasks: [{ id: '42', title: 'execute Nakatomi tower heist' }],
  ...overrides
};

it('does not fail', async () => {
  sinon.spy(mqClient, 'notifyOthers');

  const expectedUser = createExpectedUser();

  await presetRequest // helper object to run the controller code
    .get('/userDetails/1')
    .expect(200);

  // This works with sinon 7.1.1.
  // This fails with sinon 7.2.0 and onwards.
  sinon.assert.calledWithMatch(mqClient.notifyOthers, expectedUser);
});

Probé esto con sinon 7.1.1 (que usa "2.1.3" de samsam ), y funciona.
La versión 7.2.0 falla (usa 3.3.3 de samsam ).
La versión más reciente 9.2.3 también falla (usa 5.3.0 de samsam ).

Estoy en el Nodo 14.5.3, pero esto también sucede en el Nodo 12.20.0.

Comparé el user en el controlador y el expectedUser en la prueba a través de JSON.stringify manualmente y son 100% iguales. La única diferencia sintáctica es que el controlador usa la clase, mientras que la prueba usa un objeto literal.

¿Alguien tiene una buena idea de por qué sucede esto? ¿O alguien tiene una buena idea sobre cómo solucionar esto?

Saludos cordiales,
Daniel

Mientras no tengamos un caso reproducible para verificar esto, me temo que no podemos justificar pasar nuestras horas libres investigando esto. No tendría nada que buscar ni nada para verificar que tengo razón.

Sin embargo, me encanta corregir errores, así que si puedes dedicar un tiempo a intentar hacer algo _Yo puedo correr_, ¡hazlo! RunKit es un gran servicio para hacerlo: https://runkit.com/fatso83/sinon-issue-reproducible-bug-template

Hola @ fatso83 ,

Gracias por tomarse su tiempo para investigarlo. Hice lo que me pediste y creé una demostración de runkit que muestra el error. Simplemente comente / descomente las diferentes declaraciones require('sinon') y ejecute el código para ver el error.

https://runkit.com/danielkg/sinon-issue-reproducible-bug-template

Publico el código aquí también en caso de que runkit no funcione por alguna razón.

// Employs 'mini-mocha' to emulate running in the Mocha test runner (mochajs.org)
require("@fatso83/mini-mocha").install();
// const sinon = require('[email protected]'); // WORKS!
const sinon = require('[email protected]'); // FAILS!
// const sinon = require('sinon');       // FAILS!
const { assert } = require('@sinonjs/referee');

const SAMPLE_USER = {
    id: 1,
    name: 'Kid',
    age: 22,
    weight: 83.5,
    notes: [{ txt: 'abc' }, { txt: 'def' }, { txt: 'ghi' }],
};

class MyUser {
    constructor(id, name, age, weight, notes = []) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.notes = notes;
    }
}

const createFakeUser = overrides => ({
    id: '007',
    name: 'Bond',
    ...overrides,
});

class Talkie {
    talk(user, topic) {
        console.log('talked to', user.name, 'about', topic);
    }
}

const action = (userId, talkie) => {
    const { name, age, weight, notes } = SAMPLE_USER;
    const user = new MyUser(userId, name, age, weight, notes);

    talkie.talk(user, 'apples');

    return user;
}


describe('stubbing', () => {
    const talkie = new Talkie();

    afterEach(() => {
        sinon.restore();
    });

    beforeEach(() => {
        sinon.spy(talkie, 'talk');
    });

    it('is the same user', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        assert.equals(JSON.stringify(userA), JSON.stringify(userB));
    });

    it('should set the return value', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        sinon.assert.calledWith(talkie.talk, userB, sinon.match.string);
    });
});

Por favor, eche otro vistazo cuando tenga tiempo. Gracias.

Saludos cordiales,
Daniel

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