<p>sinon.restore () &amp;&amp; sandbox.restore () ne restaure pas les faux</p>

Créé le 23 juil. 2019  ·  16Commentaires  ·  Source: sinonjs/sinon

Décrivez le bogue
Impossible de supprimer les faux sinon.restore() (ni resetHistory , resetBehavior , ni reset ). J'ai ensuite essayé de créer un nouveau bac à sable et de vider le bac à sable. Pas de dé. Est-ce intentionnel?

Reproduire

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"
});

Comportement prévisible
Je m'attendais thing.lastArg ce que undefined ou null . Cela me donne "Hi"

Captures d'écran
N / A

Contexte (veuillez compléter les informations suivantes):

  • Version de la bibliothèque: Sinon ^ 7.3.2
  • Environnement: Node 10.16.0
  • Exemple d'URL: N / a
  • Autres bibliothèques que vous utilisez: Mocha, Chai

Contexte supplémentaire
Je teste simplement les capacités de Sinon car je l'utilise pour tester un backend.

Bug Help wanted

Commentaire le plus utile

Assez juste - merci pour l'explication.

Le ven 19 février 2021 à 7 h 02 Carl-Erik Kopseng [email protected]
a écrit:

@scottpatrickwright https://github.com/scottpatrickwright C'est fermé
car il n'y a pas de bogue, comme le montre le fil de discussion. C'était juste
erreur d'utilisateur, comme dans votre cas: cela fonctionne comme décrit et prévu :-)

Le bac à sable Sinon peut nettoyer les choses dont il a connaissance. Cela signifie que Sinon a
avoir connaissance des objets avec lesquels il interagit. Le talon vous
décrit ci-dessus est rendu autonome. Sinon n'a connaissance d'aucune des
objets auxquels vous l'affectez. Cela change dans le deuxième exemple. Vous pourriez
faites aussi sinon.replace (obj, fieldname, fake) pour obtenir la même chose. C'est juste
JavaScript 🙂

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 , ou
Se désabonner
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

Tous les 16 commentaires

Dans l'état actuel des choses, cela ressemble à un bogue, mais pour être honnête, je n'en suis pas totalement sûr. Je me souviens qu'un point clé sur les faux est qu'ils étaient censés être immuables dans un certain sens, mais comme ils ont un état (c'est-à-dire qu'ils savent s'ils ont été appelés), cette immuabilité doit être limitée au seul comportement de stubbing, je suppose.

@mroderick est peut-être la bonne personne pour répondre à cette question ...

Si c'est le bon comportement, nous devrions au moins mettre à jour la documentation.

@ fatso83 Très apprécié! Le .restore doc a mentionné des contrefaçons:

image

d' ici .

J'étais juste mordu par ce bogue moi-même, donc ce serait bien d'être corrigé.

Si personne d'autre ne fait de PR pour cela dans les prochains jours, je peux voir si je peux trouver le temps de le réparer

J'ai examiné cela maintenant et les documents sont un peu trompeurs, tout comme le test ci-dessus. Il semble en fait faire (presque) ce qu'il dit, mais définissons d'abord quelques termes:

restaurer - restaurer un bac à sable signifie restaurer toutes les fonctions stubbed à leur état d'origine, ce qui signifie que les stubs sont supprimés de chaque objet où ils ont écrasé l'original.
reset - la réinitialisation signifie que l'état de chacun des faux créés est effacé, mais ils sont toujours présents sur les objets.

Le problème avec le test ci-dessus est qu'il

  1. Supprime tous les faux du bac à sable
  2. Puis passe par la collection de faux dans le bac à sable (maintenant vide) et essaie de réinitialiser la liste (vide) des faux

Cela n'a pas de sens :-)

J'ai testé et les appels reset et restore fonctionnent comme ils le devraient. Presque ... reset nettoie l'état de calledOnce , mais lastArgument ne semble pas être effacé. Vérifier un peu plus pour voir si j'ai perdu des détails.

Fermer ceci comme non reproductible, mais ouvrir un nouveau numéro sur le bogue fake.lastArg .

Pour vérifier: https://runkit.com/fatso83/sinon-issue-2065

Je peux confirmer que ce bogue m'arrive également, j'ai un scénario de test qui nécessite que l'implémentation soit intacte, mais la fonction porte le résultat du stub d'un test précédent, ce qui signifie que sandbox.restore() ne fait pas ce destiné à faire.

Cela m'arrive sur la version 7.5.0

@ oscarr-reyes Pouvez-vous vérifier si https://github.com/sinonjs/sinon/commit/54df7f7000a9db2dd05319daa49518f3cd5a5dd7 le corrige pour vous? Je pense que cela n'a pas encore fait partie d'une nouvelle version.

@ oscarr-reyes Êtes-vous capable de faire un exemple reproductible? Nous n'avons pas encore vu ce bug. Si vous regardez le fil ci-dessus et mon explication, vous verrez que le seul bogue que nous avons trouvé était qu'un seul drapeau n'avait pas été effacé. Tout le reste fonctionne. Donc, à moins que nous ne voyions réellement une preuve, il n'y a pas de bogue (à part le drapeau lastArg).

J'ai face au même problème.

Je suis en sandbox de mon middleware "validateCaptcha" et quand je le restaure, il continue d'émettre le stub.

/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();
            });
    });
});

Ce que je fais pour vérifier que cela ne fonctionne pas, c'est:
1) Mock it pour le premier test
2) Restaurez-le pour les suivants

À l'intérieur beforeAll il y a un commentaire "sandbox.restore ();" que j'ai essayé et là ça a marché ... mais ça ne sert à rien

Je suis également en train d'exiger à chaque fois de mon app.js

Il y a cinq minutes, je l'ai modifié pour:

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();
            });
    });
});

Je vois également ce problème. Pourquoi est-ce fermé?

Il se peut que le comportement de la restauration soit sensible à la syntaxe spécifique utilisée pour configurer le stub. Afaik ces deux _devraient_ être des moyens valables de le faire, mais la restauration () est différente. Dans l'un, cela fonctionne et dans l'autre, cela donne des résultats inattendus.

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 lorsque vous faites des affectations directement à db.query , alors sinon n'a aucun moyen de savoir ce qui doit être restauré ou quelle était la valeur avant l'affectation.

@scottpatrickwright Il est fermé car il n'y a pas de bogue, comme cela devrait être apparent à partir du fil de discussion. C'était juste une erreur de l'utilisateur, comme dans votre cas: cela fonctionne comme décrit et prévu :-)

Le bac à sable Sinon peut nettoyer les choses dont il a connaissance. Cela signifie que Sinon doit avoir connaissance des objets avec lesquels il interagit. Le stub que vous décrivez ci-dessus est rendu autonome. Sinon n'a connaissance d'aucun des objets auxquels vous l'affectez. Cela change dans le deuxième exemple. Vous pouvez également faire sinon.replace(obj, fieldname, fake) pour obtenir la même chose. C'est juste du JavaScript 🙂

Assez juste - merci pour l'explication.

Le ven 19 février 2021 à 7 h 02 Carl-Erik Kopseng [email protected]
a écrit:

@scottpatrickwright https://github.com/scottpatrickwright C'est fermé
car il n'y a pas de bogue, comme le montre le fil de discussion. C'était juste
erreur d'utilisateur, comme dans votre cas: cela fonctionne comme décrit et prévu :-)

Le bac à sable Sinon peut nettoyer les choses dont il a connaissance. Cela signifie que Sinon a
avoir connaissance des objets avec lesquels il interagit. Le talon vous
décrit ci-dessus est rendu autonome. Sinon n'a connaissance d'aucune des
objets auxquels vous l'affectez. Cela change dans le deuxième exemple. Vous pourriez
faites aussi sinon.replace (obj, fieldname, fake) pour obtenir la même chose. C'est juste
JavaScript 🙂

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 , ou
Se désabonner
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

Cette page vous a été utile?
0 / 5 - 0 notes