描述错误
无法清除伪造品sinon.restore()
(也不能清除resetHistory
, resetBehavior
或reset
)。 然后,我尝试创建一个新的沙箱,并清除该沙箱。 没有骰子。 这是故意的吗?
重现
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"
});
预期行为
我期望thing.lastArg
是undefined
或null
。 它给了我"Hi"
屏幕截图
不适用
上下文(请完成以下信息):
额外的背景
当我使用Sinon测试后端时,只需测试它的功能即可。
实际上,它看起来像个错误,但是老实说,我对此并不完全确定。 我记得关于假货的一个关键点是,它们在某种意义上应该是不可变的,但由于它们确实具有状态(即,他们知道是否已被调用),因此我认为,不可变性必须仅限于存根行为。
@mroderick可能是回答此问题的合适人选...
如果这是正确的行为,我们至少应该更新文档。
@ fatso83非常感谢! .restore
文档提到了伪造品:
从这里开始。
我自己只是被这个错误所困扰,所以这将很容易得到解决。
如果在接下来的几天内没有其他人对此进行公关,我可以看看是否有时间修复它
我现在对此进行了调查,文档和上面的测试有点误导。 它实际上似乎(几乎)完成了它所说的,但是让我们首先定义一些术语:
恢复-恢复沙箱意味着将所有存根函数恢复到原始状态,这意味着如果存根函数重写了存根,则将其从每个对象中删除。
重置-重置表示清除了每个已创建假物的状态,但它们仍存在于对象中。
上述测试的问题在于
那没有道理:-)
我已经测试过,并且reset
和restore
调用都可以正常工作。 几乎... reset
确实清除了calledOnce
,但是lastArgument
似乎没有被清除。 多检查一下,看看我是否丢失了一些细节。
将此操作关闭后无法重现,但在fake.lastArg
错误中打开了一个新问题。
验证: https :
我可以确认这个错误也在我身上发生,我有一个测试场景,要求实现完整无缺,但是该函数带有先前测试的存根结果,这意味着sandbox.restore()
没有做任何事情打算做的。
这是我在7.5.0
版本上发生的事情
@ oscarr-reyes您可以检查https://github.com/sinonjs/sinon/commit/54df7f7000a9db2dd05319daa49518f3cd5a5dd7是否为您解决了这个问题? 我认为它尚未成为新版本。
@ oscarr-reyes您能举一个可复制的例子吗? 我们尚未真正看到此错误。 如果您查看上面的线程以及我的解释,您将看到我们发现的唯一错误是未清除单个标志。 其他一切正常。 因此,除非我们实际看到一些证明,否则没有错误(除了lastArg标志)。
我也面临着同样的问题。
我正在对“ validateCaptcha”中间件进行沙箱处理,还原后,它将继续发出存根。
/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();
});
});
});
我正在检查以确保它不起作用的是:
1)模拟它进行第一次测试
2)将其还原为以下内容
在beforeAll内部有一个注释“ sandbox.restore();” 我尝试过并在那里起作用了...但是没用
我也在每次都要求我的app.js
五分钟前,我将其修改为:
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();
});
});
});
我也看到了这个问题。 为什么关闭?
还原的行为可能对用于设置存根的特定语法敏感。 Afaik都应该这样做,但是restore()是不同的。 一种有效,而另一种具有意想不到的结果。
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直接对db.query
进行赋值时,则sinon
无法知道需要恢复的内容或赋值之前的值。
@scottpatrickwright它已关闭,因为没有错误,应该从线程中显而易见。 就像您的情况一样,这只是用户错误:它按照说明和预期的方式工作:-)
Sinon沙箱可以清除其了解的内容。 这意味着诗乃必须了解与之相互作用的物体。 您上面描述的存根是独立的。 Sinon没有意识到您将其分配给的任何对象。 在第二个示例中,情况有所变化。 您也可以执行sinon.replace(obj, fieldname, fake)
来达到相同目的。 只是JavaScript🙂
足够公平-感谢您的解释。
2021年2月19日星期五,上午7:02,Carl-Erik Kopseng [email protected]
写道:
@scottpatrickwright https://github.com/scottpatrickwright已关闭
因为没有错误,应该从线程中明显看出。 这只是
用户错误,如您所见:它按描述和预期的方式工作:-)Sinon沙箱可以清除其了解的内容。 意思是诗乃有
了解与之交互的对象。 你存根
以上描述是独立的。 Sinon没有意识到任何
您分配给它的对象。 在第二个示例中,情况有所变化。 你可以
也要做sinon.replace(obj,fieldname,fake)来达到相同的效果。 只是
JavaScript🙂-
您收到此邮件是因为有人提到您。
直接回复此电子邮件,在GitHub上查看
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 ,或者
退订
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
。
最有用的评论
足够公平-感谢您的解释。
2021年2月19日星期五,上午7:02,Carl-Erik Kopseng [email protected]
写道: