代码之家  ›  专栏  ›  技术社区  ›  HolyMoly

使用Puppeter捕获HTTP响应的正确方法是什么?

  •  17
  • HolyMoly  · 技术社区  · 8 年前

    我试图从用户注册中捕获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作为最后一行。将其分配给变量会导致 页 待退回。我需要做的只是在监听器中运行测试。使用时 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()
      })
    

    希望这对其他人有帮助!

    4 回复  |  直到 7 年前
        1
  •  9
  •   Thanwa Ch. tomahaug    6 年前

    我认为你应该按照这些思路做些事情。注意回调函数 done .

    代码所做的是,它为响应附加一个侦听器,然后单击submit按钮。当收到响应时,它会检查状态代码,确认它,并通过调用终止测试 完成 .

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

    我没有测试代码,但它应该会给你正确的想法。

    编辑:调整以反映最终的结果。

        2
  •  7
  •   ericsoco    7 年前

    如果需要操纵请求/响应,请使用 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);
    

    这允许测试流保持线性,并避免在测试之前关闭测试的模糊性 页在…上 处理程序收到 response 事件

        3
  •  3
  •   ggorlen Hoàng Huy Khánh    5 年前

    接受的答案(也被编辑到问题中)不正确。由于点击调用增加了1秒延迟,它引入了竞争条件。在最好的情况下,这会不必要地减慢测试套件的速度,在最坏的情况下,如果请求需要超过一秒的时间才能解决,则会产生错误的失败(如果它被模拟,则不太可能,但它不会改变代码不安全的事实)。

    call done() from the callback . 如果回调中有一次抛出 done 无法访问,呼叫 done(error) 在错误处理程序中,向Jest报告测试用例失败。

    为此,您需要添加 完成 作为传递给 it , test 或 only 功能,以便在区块中可用。这允许Jest的测试运行程序将测试视为异步的,直到 完成 完成 ,测试套件忽略回调的断言。 async / await 没有帮助,因为它是一个独立的异步链,而不是回调。

    完成 作为参数或返回承诺( 异步 隐式返回一个承诺),而不是两者都返回。但是,您可能仍然希望使用 对于木偶师库调用,而不是 then . 您可以使用 异步 生命最终点燃了 完成()

    例如

    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 { /* try-catch pattern shown for illustration */
              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 这可以让你跳过回调 完成 等待响应 是字符串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 ( 异步 / 版本):

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

    指数测验js公司 ( 然后

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

    指数测验js公司 ( 版本):

    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");
        })();
      });
    });
    
        4
  •  1
  •   Zoe - Save the data dump 张群峰    7 年前

    response.url

    response.url()
    

    同样适用于 response.request().method :

    response.request().method()