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):
Contexto adicional
Solo estoy probando las capacidades de Sinon mientras lo uso para probar un backend.
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:
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
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
.
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ó: