我正在尝试从用户注册中捕获http响应状态。
我的代码如下所示:
it.only('returns a 400 response if email is taken', async () => {
await page.goto(`${process.env.DOMAIN}/sign-up`)
await page.waitFor('input[id="Full Name"]')
await page.type('input[id="Full Name"]', 'Luke Skywalker')
await page.type('input[id="Email"]', 'LukeSkywalker@voyage.com')
await page.type('input[id="Password"]', 'LukeSkywalker123', {delay: 100})
await page.click('input[type="submit"]', {delay: 1000})
const response = await page.on('response', response => response)
console.log('request status', response.status)
// expect(response).toEqual(400)
})
文档举例说明拦截请求并用它做事:
await page.setRequestInterception(true);
page.on('request', request => {
request.respond({
status: 404,
contentType: 'text/plain',
body: 'Not Found!'
});
});
我尝试了类似的模式无济于事,以及许多其他模式。我所做的一切都会返回page
,这是一个巨大的物体,没有任何状态,我可以看到。任何帮助深表感谢。
工作原理:
感谢@tomahaug指导我正确的方向。我的第一个问题是放置,需要在发出请求之前设置监听器,我在请求之后就有了它。说得通。我最大的问题是将监听器分配给变量,以便我可以将expect作为我的最后一行。将其分配给变量会导致返回page
。我需要做的只是在监听器内运行测试。在使用done()
投掷和错误时,我关闭了我的测试,如下所示,我的代码的工作版本:
it.only('returns a 400 response if email is taken', async () => {
await page.goto(`${process.env.DOMAIN}/sign-up`)
await page.waitFor('input[id="Full Name"]')
await page.type('input[id="Full Name"]', 'Luke Skywalker')
await page.type('input[id="Email"]', 'LukeSkywalker@voyage1.com')
await page.type('input[id="Password"]', 'LukeSkywalker123', {delay: 100})
await page.on('response', response => {
if (response.request().method === 'POST' && response.url === `${process.env.USERS_API_DOMAIN}/sessions`) {
expect(response.status).toEqual(400)
}
})
await page.click('input[type="submit"]', {delay: 1000})
})
after(async function () {
await browser.close()
})
希望这有助于其他人!
答案 0 :(得分:5)
我相信你应该按照这些方针做点什么。请注意回调函数done
。
代码的作用是,它附加一个响应的监听器,然后单击提交按钮。收到响应后,它会检查状态代码,断言它,并通过调用done
来终止测试。
您可能希望有一个if
- 语句,检查它是您在回调中检查的表单的实际响应,因为响应处理程序可能会为其他并发请求发出事件。
it.only('returns a 400 response if email is taken', () => {
await page.goto(`${process.env.DOMAIN}/sign-up`)
await page.waitFor('input[id="Full Name"]')
await page.type('input[id="Full Name"]', 'Luke Skywalker')
await page.type('input[id="Email"]', 'LukeSkywalker@voyage.com')
await page.type('input[id="Password"]', 'LukeSkywalker123', {delay: 100})
await page.on('response', (response) => {
if (
response.request().method === 'POST' &&
response.url === `${process.env.USERS_API_DOMAIN}/sessions`)
{
expect(response.status).toEqual(400)
}
})
await page.click('input[type="submit"]', {delay: 1000})
})
我没有测试过代码,但它应该给你正确的想法。
编辑:调整以反映最终的结果。
答案 1 :(得分:2)
如果您需要操纵请求/响应,请使用page.setRequestInterception(true)
和page.on
/ page.once
(as documented)。
但是,如果您只需要声明有关响应的内容,那么最简单,最惯用的方法是使用page.waitForResponse
:
const updateDashboardResponse = await page.waitForResponse(response =>
response.url().includes('updateDashboard')
);
expect(updateDashboardResponse.status()).toBe(200);
这使测试流程保持线性,并避免在page.on
处理程序接收到response
事件之前关闭测试的不确定性。
答案 2 :(得分:0)
response.url
是一个函数,您必须调用它:
response.url()
response.request().method
也是如此:
response.request().method()
答案 3 :(得分:0)
接受的答案(也已编辑到问题中)不正确。由于将1秒钟的延迟添加到点击通话中,因此引入了竞争条件。最好的情况是,这不必要地减慢了测试套件的速度,最坏的情况是,如果请求花费的时间超过一秒钟才能解决,则它会生成错误的失败(如果被嘲笑是不太可能的,但它不会改变代码不安全的事实)。 / p>
只要在Jest测试用例中存在回调,便会确保call done()
from the callback的正确方法是确保其已被执行,并且根据其触发进行了所有断言,而没有添加人为延迟。如果在回调中抛出异常,导致done
无法访问,请在错误处理程序中调用done(error)
,以将测试用例失败报告给Jest。
为此,您需要将done
作为参数添加到传递给it
,test
或only
函数的回调中,以便在块。这允许Jest的测试运行程序将测试视为异步,并且直到调用done
才解决它。如果没有done
,则测试套件将忽略回调的断言。 async
/ await
没有帮助,因为它是与回调不同的异步链。
您只需要指定done
作为参数或返回一个承诺(async
隐式返回一个承诺),而不必两者都做。但是,您仍可能希望对await
使用then
来进行Puppeteer库调用。您可以使用async
IIFE,当所有断言都激发出来时,它最终会激发done()
调用。
例如,
it.only('returns a 400 response if email is taken', done => {
(async () => {
page.on('response', response => {
if (response.request().method === 'POST' &&
response.url === `${process.env.USERS_API_DOMAIN}/sessions`) {
try {
expect(response.status).toEqual(400);
done();
}
catch (err) {
done(err);
}
}
});
await page.goto(`${process.env.DOMAIN}/sign-up`);
await page.waitFor('input[id="Full Name"]');
await page.type('input[id="Full Name"]', 'Luke Skywalker');
await page.type('input[id="Email"]', 'LukeSkywalker@voyage.com');
await page.type('input[id="Password"]', 'LukeSkywalker123', {delay: 100});
await page.click('input[type="submit"]');
})();
});
考虑到这一点,this answer显示了一种使用waitForResponse
的更好的方法,它使您可以完全跳过回调和done
。 waitForResponse
的回调是一个字符串URL或函数谓词,对于正在等待的目标响应应返回true:
it.only('returns a 400 response if email is taken', async () => {
await page.goto(`${process.env.DOMAIN}/sign-up`);
await page.waitFor('input[id="Full Name"]');
await page.type('input[id="Full Name"]', 'Luke Skywalker');
await page.type('input[id="Email"]', 'LukeSkywalker@voyage.com');
await page.type('input[id="Password"]', 'LukeSkywalker123', {delay: 100});
await page.click('input[type="submit"]');
const response = await page.waitForResponse(response =>
response.request().method === 'POST' &&
response.url === `${process.env.USERS_API_DOMAIN}/sessions`
);
expect(response.status).toEqual(400);
});
我还应该提到,以上摘录中的waitFor
已被waitForSelector
取代,并且.url
和.method
是函数。我尚未验证以上代码;它与原始帖子相关并显示高级模式。
index.html
这是我们正在测试的网页。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<button>Post</button>
<script>
document
.querySelector("button")
.addEventListener("click", e =>
fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
body: JSON.stringify({
title: "foo",
body: "bar",
userId: 1,
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
.then(response => response.json())
.then(json => console.log(json))
)
;
</script>
</body>
</html>
index.test.js
(async
/ await
版本):describe("index page", () => {
it("should respond to POST", async () => {
const url = "https://jsonplaceholder.typicode.com/posts";
await page.goto("http://localhost:1234", {waitUntil: "load"});
await page.click("button");
const response = await page.waitForResponse(response =>
response.request().method() === "POST" &&
response.url() === url
);
const expectedBody = {
body: "bar",
id: 101,
title: "foo",
userId: 1,
};
expect(await response.json()).toEqual(expectedBody);
});
});
index.test.js
(then
版本):describe("index page", () => {
it("should respond to POST", () => {
const url = "https://jsonplaceholder.typicode.com/posts";
const expectedBody = {
body: "bar",
id: 101,
title: "foo",
userId: 1,
};
return page.goto("http://localhost:1234", {
waitUntil: "load"
})
.then(() => page.click("button"))
.then(() => page.waitForResponse(response =>
response.request().method() === "POST" &&
response.url() === url
))
.then(response => response.json())
.then(body => expect(body).toEqual(expectedBody))
;
});
});
index.test.js
(done
版本):describe("index page", () => {
it("should respond to POST", done => {
(async () => {
const url = "https://jsonplaceholder.typicode.com/posts";
const expectedBody = {
body: "bar",
id: 101,
title: "foo",
userId: 1,
};
await page.setRequestInterception(true);
page.on("response", async response => {
if (response.request().method() === "POST" &&
response.url() === url) {
try {
const body = await response.json();
expect(body).toEqual(expectedBody);
done();
}
catch (err) {
done(err);
}
}
});
await page.goto("http://localhost:1234", {
waitUntil: "load"
});
page.click("button");
})();
});
});