Te sugerimos que pruebes esta resolución en un ambiente controlado antes de pasarlo a producción, un saludo.
Solución:
Creo que deberías hacer algo en ese sentido. Tenga en cuenta la función de devolución de llamada done
.
Lo que hace el código es que adjunta un oyente para las respuestas y luego hace clic en el botón enviar. Cuando se recibe una respuesta, verifica el código de estado, lo afirma y finaliza la prueba llamando done
.
Es posible que desee tener un if
-declaración que verifica que es la respuesta real de su formulario lo que está verificando en la devolución de llamada, ya que el controlador de respuesta podría emitir eventos para otras solicitudes concurrentes.
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"]', '[email protected]')
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)
)
No he probado el código, pero debería darte la idea correcta.
Editar: ajustado para reflejar lo que funcionó al final.
Si necesita manipular la solicitud / respuesta, use page.setRequestInterception(true)
y page.on
/page.once
(como se documenta).
Sin embargo, si todo lo que necesita es afirmar algo sobre la respuesta, la forma más simple e idiomática de hacerlo es con page.waitForResponse
:
const updateDashboardResponse = await page.waitForResponse(response =>
response.url().includes('updateDashboard')
);
expect(updateDashboardResponse.status()).toBe(200);
Esto permite que el flujo de prueba permanezca lineal y evita la ambigüedad en torno al cierre de una prueba antes de una page.on
el manejador recibe un response
evento.
La respuesta aceptada (que también se editó en la pregunta) es incorrecta. Introduce una condición de carrera debido a un retraso de 1 segundo agregado a la llamada de clic. En el mejor de los casos, esto ralentiza innecesariamente la suite de pruebas y, en el peor, genera false fallas en caso de que la solicitud tarde más de un segundo en resolverse (poco probable si se burla, pero no cambia el hecho de que el código no es seguro).
Siempre que haya una devolución de llamada en un caso de prueba de Jest, la forma correcta de asegurarse de que se haya ejecutado y de que todas las afirmaciones que dependen de su activación se hayan realizado sin agregar demoras artificiales es llamar done()
desde la devolución de llamada. Si hay un lanzamiento en la devolución de llamada que hace done
inalcanzable, llamar done(error)
en el controlador de errores para informar el fallo del caso de prueba a Jest.
Para hacer esto, necesitará agregar done
como el parámetro de la devolución de llamada pasado al it
, test
o only
función para que esté disponible en el bloque. Esto permite que el ejecutor de pruebas de Jest trate la prueba como asincrónica y no la resuelva hasta done
se llama. Sin done
, la suite de pruebas ignora las afirmaciones de la devolución de llamada. async
/await
no ayuda porque es una cadena asincrónica separada de la devolución de llamada.
Solo necesitas especificar done
como parámetro o devolver una promesa (async
devuelve implícitamente una promesa), nunca ambos. Sin embargo, es probable que aún desee utilizar await
para llamadas a la biblioteca Titiritero en lugar de then
. Puedes usar un async
IIFE que eventualmente dispara el done()
llame cuando todas las afirmaciones se hayan disparado para obtener lo mejor de ambos mundos.
Por ejemplo,
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"]', '[email protected]');
await page.type('input[id="Password"]', 'LukeSkywalker123', delay: 100);
await page.click('input[type="submit"]');
)();
);
Teniendo esto en cuenta, esta respuesta muestra un enfoque probablemente mejor utilizando waitForResponse
que le permite omitir la devolución de llamada y done
enteramente. La devolución de llamada a waitForResponse
es un string URL o predicado de función que debería devolver true para la respuesta de destino que se está esperando:
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"]', '[email protected]');
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);
);
También debo mencionar waitFor
está en desuso a favor de waitForSelector
en los fragmentos anteriores y que .url
y .method
son funciones. No he verificado el código anterior; está ahí para relacionarse con la publicación original y mostrar los patrones de alto nivel.
Ejemplo mínimo
index.html
Esta es la página web que estamos probando.
index.test.js
(async
/await
versión):
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
versión):
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
versión):
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");
)();
);
);
Recuerda que puedes comunicar este tutorial si te valió la pena.