バグを説明する
偽物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
ドキュメントは偽物について言及しました:
ここから。
私自身このバグに少しだけ触れていたので、これを修正するといいでしょう。
今後数日以内に他の誰もPRを行わない場合は、修正する時間を見つけることができるかどうかを確認できます。
私は今これを調べましたが、上記のテストと同様に、ドキュメントは少し誤解を招く可能性があります。 それは実際には(ほぼ)それが言うことをしているように見えますが、最初にいくつかの用語を定義しましょう:
復元-サンドボックスを復元するとは、すべてのスタブ関数を元の状態に復元することを意味します。つまり、元のオブジェクトを上書きすると、各オブジェクトからスタブが削除されます。
リセット-リセットとは、作成された各偽物の状態がクリアされているが、それらはオブジェクトにまだ存在していることを意味します。
上記のテストの問題は、
それは意味がありません:-)
テストしましたが、 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を実行しています
5分前に私はそれを次のように変更しました:
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()は異なります。 1つは機能し、もう1つは予期しない結果をもたらします。
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は、割り当てられたオブジェクトを認識しません。 これは2番目の例で変わります。 同じことを達成するためにsinon.replace(obj, fieldname, fake)
を実行することもできます。 ただのJavaScriptです🙂
十分に公平です-説明に感謝します。
7:02で金、2021年2月19日にはカール・エリック・Kopseng [email protected]
書きました:
@scottpatrickwrighthttps ://github.com/scottpatrickwright閉鎖されています
スレッドから明らかなように、バグがないためです。 それだけでした
あなたの場合のように、ユーザーエラー:それは説明され意図されたように機能します:-)Sinonサンドボックスは、知っていることをクリーンアップできます。 それはシノンが持っていることを意味します
それが相互作用するオブジェクトの知識を持っていること。 あなたのスタブ
上記の説明はスタンドアロンになります。 シノンは、
割り当てるオブジェクト。 これは2番目の例で変わります。 あなたは出来る
また、sinon.replace(obj、fieldname、fake)を実行して、同じことを実現します。 それはただ
JavaScript🙂—
あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 、または
退会
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
。
最も参考になるコメント
十分に公平です-説明に感謝します。
7:02で金、2021年2月19日にはカール・エリック・Kopseng [email protected]
書きました: