<p>sinon.restore () &amp;&amp; sandbox.restore () no restaura falsificaciones</p>

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

Describe el error
No se pueden borrar las falsificaciones sinon.restore() (ni resetHistory , resetBehavior , ni reset ). Luego intenté crear una nueva caja de arena y limpiarla. No dados. ¿Es esto intencional?

Reproducir

it("Demonstrates how to restore a fake", () => {
  let sandbox = sinon.createSandbox();
  let thing = sandbox.fake();
  thing("Hi");
  expect(thing.calledOnce).to.be.true;
  expect(thing.lastArg).to.equal("Hi");
  sandbox.restore();
  sandbox.resetHistory();
  sandbox.resetBehavior();
  sandbox.reset();
  expect(thing.calledOnce).to.be.false; // Fails. thing.calledOnce === true
  expect(thing.lastArg).to.be.undefined; // Fails if above commented out. thing.lastArg === "Hi"
});

Comportamiento esperado
Esperaba que thing.lastArg fuera undefined o null . Me da "Hi"

Capturas de pantalla
N / A

Contexto (complete la siguiente información):

  • Versión de la biblioteca: Sinon ^ 7.3.2
  • Entorno: nodo 10.16.0
  • URL de ejemplo: N / a
  • Otras bibliotecas que está utilizando: Mocha, Chai

Contexto adicional
Solo estoy probando las capacidades de Sinon mientras lo uso para probar un backend.

Bug Help wanted

Comentario más útil

Muy bien, gracias por la explicación.

El viernes 19 de febrero de 2021 a las 7:02 a.m. Carl-Erik Kopseng [email protected]
escribió:

@scottpatrickwright https://github.com/scottpatrickwright Está cerrado
porque no hay ningún error, como debería ser evidente en el hilo. Fue solo
error de usuario, como en su caso: funciona según lo descrito y previsto :-)

La caja de arena de Sinon puede limpiar las cosas que conoce. Eso significa que Sinon tiene
tener conocimiento de los objetos con los que interactúa. El trozo de ti
describe arriba se hace independiente. Sinon no tiene conocimiento de ninguno de los
objetos a los que se lo asigna. Eso cambia en el segundo ejemplo. Tú podrías
también haga sinon.replace (obj, fieldname, fake) para lograr lo mismo. Es solo
JavaScript 🙂

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 , o
darse de baja
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

Todos 16 comentarios

Tal como está, parece que es un error, pero para ser honesto, no estoy totalmente seguro de esto. Recuerdo que un punto clave sobre las falsificaciones es que se suponía que eran inmutables en algún sentido, pero dado que tienen estado (es decir, saben si han sido llamadas), supongo que la inmutabilidad debe restringirse solo al comportamiento de corte.

@mroderick podría ser la persona adecuada para responder a esta ...

Si este es el comportamiento correcto, al menos deberíamos actualizar los documentos.

@ fatso83 ¡ Muy apreciado! El .restore doc mencionó falsificaciones:

image

desde aqui .

Yo mismo fui mordido por este error, por lo que sería bueno solucionarlo.

Si nadie más hace un PR en los próximos días, puedo ver si puedo encontrar el tiempo para arreglarlo.

Analicé esto ahora y los documentos son un poco engañosos, al igual que la prueba anterior. En realidad, parece hacer (casi) lo que dice, pero primero definamos algunos términos:

restaurar : restaurar una caja de arena significa restaurar todas las funciones stubped a su estado original, lo que significa que los stubs se eliminan de cada objeto donde sobrescribieron el original.
restablecer : restablecer significa que el estado de cada una de las falsificaciones creadas se borra, pero aún están presentes en los objetos.

El problema con la prueba anterior es que

  1. Elimina todas las falsificaciones de la caja de arena.
  2. Luego procede a revisar la colección de falsificaciones en la caja de arena (ahora vacía) e intenta restablecer la lista (vacía) de falsificaciones

Eso no tiene sentido :-)

He probado y las llamadas reset y restore funcionan como deberían. Casi ... reset limpia el estado de calledOnce , pero parece que lastArgument no se ha borrado. Comprobando un poco más para ver si he perdido algún detalle.

Cerrando esto como no reproducible, pero abriendo un nuevo problema en el error fake.lastArg .

Para verificar: https://runkit.com/fatso83/sinon-issue-2065

Puedo confirmar que este error también me está sucediendo, tengo un escenario de prueba que requiere que la implementación esté intacta, pero la función lleva el resultado del stub de una prueba anterior, lo que significa que sandbox.restore() no está haciendo lo que destinado a hacer.

Esto me está sucediendo en la versión 7.5.0

@ oscarr-reyes ¿Puedes comprobar si https://github.com/sinonjs/sinon/commit/54df7f7000a9db2dd05319daa49518f3cd5a5dd7 lo soluciona? Creo que aún no se ha convertido en un nuevo lanzamiento.

@ oscarr-reyes ¿Puedes hacer un ejemplo reproducible? En realidad, todavía no hemos visto este error. Si miras el hilo de arriba y mi explicación, verás que el único error que encontramos fue que no se había borrado una sola bandera. Todo lo demás funciona. Entonces, a menos que veamos alguna prueba, no hay ningún error (aparte de la bandera lastArg).

Me he enfrentado al mismo problema.

Estoy en la zona de pruebas de mi middleware "validateCaptcha" y cuando lo restauro continúa emitiendo el código auxiliar.

/src/middlewares/captcha.js

const request = require("got");

const validateCaptcha = async (req, res, next) => {
    // if (process.env.NODE_ENV !== "production") return next();

    const captcha = req.body["g-recaptcha-response"] || req.body.g_recaptcha_response;

    // g-recaptcha-response is the key that browser will generate upon form submit.
    // if its blank or null means user has not selected the captcha, so return the error.
    if (captcha === undefined || captcha === "" || captcha === null)
        return res
            .status(400)
            .json({ message: "Please, verify that you are not a robot" });

    // Put your secret key here.
    const secretKey = process.env.GOOGLE_CAPTCHA_API_SECRET_KEY;

    // req.connection.remoteAddress will provide IP address of connected user.
    const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${captcha}`;

    try {

        // Hitting GET request to the URL, Google will respond with success or error scenario.
        const { body } = await request.post(verificationUrl, { responseType: "json" });

        // Success will be true or false depending upon captcha validation.
        if (body.success !== undefined && !body.success)
            return res
                .status(400)
                .json({ message: "Captcha validation error" });
    } catch (error) {
        return res
            .status(503)
            .json({ message: "Couldn't validate captcha" });
    }

    next();
};

module.exports = {
    validateCaptcha,
};

/test/api/user.spec.js

require("../setup.spec");
const supertest = require("supertest");
const captcha = require("../../src/middlewares/captcha");
const sinon = require("sinon");
let app;
let agent;
let sandbox;

const login = (anAgent, userCredentials) =>
    anAgent
        .post("/api/users/signIn")
        .send(userCredentials);

const logout = (anAgent) =>
    anAgent
        .post("/api/users/signOut");

describe("User endpoints", function () {
    this.beforeAll(async () => {
        sandbox = sinon.createSandbox();
        sandbox
            .stub(captcha, "validateCaptcha")
            .callsFake(async (req, res, next) => {
                console.log("Validate Captcha FAKE");
                return next();
            });
        // sandbox.restore();
    });

    this.beforeEach(async () => {
        app = require("../../src/app");
        agent = supertest.agent(app);
        const sequelize = require("../../src/models");
        await sequelize.sync({ force: true });

        const Customer = require("../../src/models/customer");
        const User = require("../../src/models/user");
        await Customer.create(
            {
                firstName: "Test",
                lastName: "Customer",
                user: {
                    email: "[email protected]",
                    password: "boo",
                },
            },
            {
                include: [User],
            }
        );
    });

    this.afterEach(async () => {
        sandbox.restore();
    });

    it("should create a new user", function (done) {
        agent
            .post("/api/users/signUp")
            .send({
                firstName: "firstName",
                lastName: "lastName",
                email: "[email protected]",
                password: "aPassword",
            })
            .expect(201)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });

    it("should sign in", function (done) {
        login(agent, { email: "[email protected]", password: "boo" })
            .expect(200)
            .end((err, res) => {
                const { message, user } = res.body;
                message.should.be.equal("valid");
                user.should.have.property("email").equal("[email protected]");
                user.should.have.property("customer").have.property("firstName").equal("Test");
                user.should.have.property("customer").have.property("lastName").equal("Customer");

                agent
                    .get("/api/users/me")
                    .expect(200)
                    .end((err, res) => {
                        const user = res.body;
                        user.should.have.property("email").equal("[email protected]");
                        user.should.have.property("customer").have.property("firstName").equal("Test");
                        user.should.have.property("customer").have.property("lastName").equal("Customer");
                        err ? done(err) : done();
                    });
            });
    });

    it("should sign out", async function () {
        await login(agent, { email: "[email protected]", password: "boo" });
        await logout(agent)
            .expect(302)
            .expect("Location", "/");

        return agent
            .get("/api/users/me")
            .expect(401);
    });

    it("should return unauthorized", function (done) {
        agent
            .get("/api/users/me")
            .expect(401)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });
});

Lo que estoy haciendo para comprobar que no funciona es:
1) Burlarse de él para la primera prueba
2) Restaurarlo para los siguientes

Dentro de beforeAll hay un comentario "sandbox.restore ();" que lo he probado y ahí funcionó ... pero es inútil

También estoy requiriendo cada vez que mi app.js

Hace cinco minutos lo modifiqué a:

require("../setup.spec");
const decache = require("decache");
const supertest = require("supertest");
const sequelize = require("../../src/models");

const sinon = require("sinon");
const sandbox = sinon.createSandbox();
let agent;

const login = (anAgent, userCredentials) =>
    anAgent
        .post("/api/users/signIn")
        .send(userCredentials);

const logout = (anAgent) =>
    anAgent
        .post("/api/users/signOut");

describe("User endpoints", function () {
    this.beforeAll(async () => {

    });

    this.beforeEach(async () => {
        decache("../../src/app");
        decache("../../src/middlewares/captcha");

        const captcha = require("../../src/middlewares/captcha");

        sandbox
            .stub(captcha, "validateCaptcha")
            .callsFake(async (req, res, next) => {
                console.log("Validate Captcha FAKE");
                return next();
            });

        const app = require("../../src/app");
        agent = supertest.agent(app);
        await sequelize.sync({ force: true });


        const Customer = require("../../src/models/customer");
        const User = require("../../src/models/user");
        await Customer.create(
            {
                firstName: "Test",
                lastName: "Customer",
                user: {
                    email: "[email protected]",
                    password: "boo",
                },
            },
            {
                include: [User],
            }
        );
    });

    this.afterEach(async () => {
        sandbox.restore();
    });

    it("should create a new user", function (done) {
        agent
            .post("/api/users/signUp")
            .send({
                firstName: "firstName",
                lastName: "lastName",
                email: "[email protected]",
                password: "aPassword",
            })
            .expect(201)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });

    it("should sign in", function (done) {
        login(agent, { email: "[email protected]", password: "boo" })
            .expect(200)
            .end((err, res) => {
                const { message, user } = res.body;
                message.should.be.equal("valid");
                user.should.have.property("email").equal("[email protected]");
                user.should.have.property("customer").have.property("firstName").equal("Test");
                user.should.have.property("customer").have.property("lastName").equal("Customer");

                agent
                    .get("/api/users/me")
                    .expect(200)
                    .end((err, res) => {
                        const user = res.body;
                        user.should.have.property("email").equal("[email protected]");
                        user.should.have.property("customer").have.property("firstName").equal("Test");
                        user.should.have.property("customer").have.property("lastName").equal("Customer");
                        err ? done(err) : done();
                    });
            });
    });

    it("should sign out", async function () {
        await login(agent, { email: "[email protected]", password: "boo" });
        await logout(agent)
            .expect(302)
            .expect("Location", "/");

        return agent
            .get("/api/users/me")
            .expect(401);
    });

    it("should return unauthorized", function (done) {
        agent
            .get("/api/users/me")
            .expect(401)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });
});

También estoy viendo este problema. ¿Por qué esta cerrado?

Puede ser que el comportamiento de la restauración sea sensible a la sintaxis específica utilizada para configurar el stub. Afaik, ambas _deberían_ ser formas válidas de hacer esto, pero restore () es diferente. En uno funciona y en el otro tiene resultados inesperados.

const sinon = require('sinon')

// restore does not work as expected

let db = {
  query: () => {
    return 'my query 1'
  }
}
const dbStub = sinon.stub().resolves('somejson')
db.query = dbStub
db.query() // somejson
sinon.restore()
db.query() // resolves nothing

// restore works as expected

db = {
  query: () => {
    return 'my query 1'
  }
}
sinon.stub(db, 'query').resolves('somejson')
db.query() // somejson
sinon.restore()
db.query() //my query 1

@scottpatrickwright cuando haces asignaciones directamente a db.query , entonces sinon no tiene forma de saber qué necesita ser restaurado o cuál era el valor antes de la asignación.

@scottpatrickwright Está cerrado porque no hay ningún error, como debería ser evidente en el hilo. Fue solo un error del usuario, como en su caso: funciona como se describe y se pretendía :-)

La caja de arena de Sinon puede limpiar las cosas que conoce. Eso significa que Sinon debe tener conocimiento de los objetos con los que interactúa. El código auxiliar que describe arriba es independiente. Sinon no se da cuenta de ninguno de los objetos a los que lo asigna. Eso cambia en el segundo ejemplo. También puede hacer sinon.replace(obj, fieldname, fake) para lograr lo mismo. Es solo JavaScript 🙂

Muy bien, gracias por la explicación.

El viernes 19 de febrero de 2021 a las 7:02 a.m. Carl-Erik Kopseng [email protected]
escribió:

@scottpatrickwright https://github.com/scottpatrickwright Está cerrado
porque no hay ningún error, como debería ser evidente en el hilo. Fue solo
error de usuario, como en su caso: funciona según lo descrito y previsto :-)

La caja de arena de Sinon puede limpiar las cosas que conoce. Eso significa que Sinon tiene
tener conocimiento de los objetos con los que interactúa. El trozo de ti
describe arriba se hace independiente. Sinon no tiene conocimiento de ninguno de los
objetos a los que se lo asigna. Eso cambia en el segundo ejemplo. Tú podrías
también haga sinon.replace (obj, fieldname, fake) para lograr lo mismo. Es solo
JavaScript 🙂

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 , o
darse de baja
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

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