<p>sinon.restore()&amp;&amp; sandbox.restore()不还原假货</p>

创建于 2019-07-23  ·  16评论  ·  资料来源: sinonjs/sinon

描述错误
无法清除伪造品sinon.restore() (也不能清除resetHistoryresetBehaviorreset )。 然后,我尝试创建一个新的沙箱,并清除该沙箱。 没有骰子。 这是故意的吗?

重现

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.lastArgundefinednull 。 它给了我"Hi"

屏幕截图
不适用

上下文(请完成以下信息):

  • 图书馆版本:锡农^ 7.3.2
  • 环境:Node 10.16.0
  • 范例网址:N / a
  • 您正在使用的其他库:摩卡(Mocha),柴(Chai)

额外的背景
当我使用Sinon测试后端时,只需测试它的功能即可。

Bug Help wanted

最有用的评论

足够公平-感谢您的解释。

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

所有16条评论

实际上,它看起来像个错误,但是老实说,我对此并不完全确定。 我记得关于假货的一个关键点是,它们在某种意义上应该是不可变的,但由于它们确实具有状态(即,他们知道是否已被调用),因此我认为,不可变性必须仅限于存根行为。

@mroderick可能是回答此问题的合适人选...

如果这是正确的行为,我们至少应该更新文档。

@ fatso83非常感谢! .restore文档提到了伪造品:

image

这里开始

我自己只是被这个错误所困扰,所以这将很容易得到解决。

如果在接下来的几天内没有其他人对此进行公关,我可以看看是否有时间修复它

我现在对此进行了调查,文档和上面的测试有点误导。 它实际上似乎(几乎)完成了它所说的,但是让我们首先定义一些术语:

恢复-恢复沙箱意味着将所有存根函数恢复到原始状态,这意味着如果存根函数重写了存根,则将其从每个对象中删除。
重置-重置表示清除了每个已创建假物的状态,但它们仍存在于对象中。

上述测试的问题在于

  1. 从沙盒中删除所有假货
  2. 然后继续检查沙箱中的假货(现在为空),并尝试重置(空)假货列表

那没有道理:-)

我已经测试过,并且resetrestore调用都可以正常工作。 几乎... 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

此页面是否有帮助?
0 / 5 - 0 等级