Usar cy.intercept() para gestionar el comportamiento de las solicitudes HTTP en la capa de red.

Con cy.intercept(), usted puede:

  • stub o espiar cualquier tipo de solicitud HTTP.
    • Si cy.intercept() proporciona un objeto de respuesta, o un accesorio, o llama req.reply() entonces la solicitud NO irá al servidor y, en su lugar, se burlará de la prueba.
    • De lo contrario, la solicitud se enviará al servidor y la prueba espiará la llamada de red. La intercepción de espionaje puede incluso modificar la respuesta real del servidor antes de que se devuelva a la aplicación web bajo prueba.
  • modificar el cuerpo, los encabezados y la URL de una solicitud HTTP antes de enviarla al servidor de destino.

  • stub la respuesta a una solicitud HTTP, ya sea de forma dinámica o estática.
  • modificar las respuestas HTTP reales, cambiando el cuerpo, los encabezados o el código de estado HTTP antes de que sean recibidos por el navegador.

  • y mucho más – cy.intercept() da acceso completo a todas las solicitudes HTTP en todas las etapas.

Comparación con cy.route()

A diferencia de cy.route (), cy.intercept():

  • puede interceptar todo tipo de solicitudes de red, incluidas Fetch API, cargas de páginas, XMLHttpRequests, cargas de recursos, etc.
  • no requiere llamar a cy.server () antes de su uso; de hecho, cy.server() no influye cy.intercept() en absoluto.
  • no tiene un método establecido en GET por defecto, pero intercepta * métodos.

Uso

cy.intercept(url, routeHandler?)
cy.intercept(method, url, routeHandler?)
cy.intercept(routeMatcher, routeHandler?)
cy.intercept(url, routeMatcher, routeHandler)

Nota: todas las intersecciones se borran automáticamente antes de cada prueba.

Argumentos

url (string | RegExp)

Especifique la URL para que coincida. Consulte los ejemplos de URL coincidentes para ver cómo se comparan las URL.

cy.intercept('http://example.com/widgets')
cy.intercept('http://example.com/widgets', { fixture: 'widgets.json' })

método (string)

Especifique el método HTTP para hacer coincidir.

cy.intercept('POST', 'http://example.com/widgets', {
  statusCode: 200,
  body: 'it worked!',
})

routeMatcher (RouteMatcher)

routeMatcher es un objeto que se utiliza para hacer coincidir las solicitudes HTTP entrantes que serán manejadas por esta ruta.

Todas las propiedades son opcionales. Todas las propiedades establecidas deben coincidir para que la ruta maneje una solicitud. Si un string se pasa a cualquier propiedad, se comparará globalmente con la solicitud utilizando minimatch.El disponible routeMatcher las propiedades se enumeran a continuación:

{
  /**
   * Match against the username and password used in HTTP Basic authentication.
   */
  auth?: { username: string | RegExp, password: string | RegExp }
  /**
   * Match against HTTP headers on the request.
   */
  headers?: {
    [name: string]: string | RegExp
  }
  /**
   * Match against the requested HTTP hostname.
   */
  hostname?: string | RegExp
  /**
   * If 'true', only HTTPS requests will be matched.
   * If 'false', only HTTP requests will be matched.
   */
  https?: boolean
  /**
   * Match against the request's HTTP method.
   * @default '*'
   */
  method?: string | RegExp
  /**
   * If `true`, this will pass the request on to the next `RouteMatcher` after the request handler completes.
   * Can only be used with a dynamic request handler.
   * @default false
   */
  middleware?: boolean
  /**
   * Match on request path after the hostname, including query params.
   */
  path?: string | RegExp
  /**
   * Matches like 'path', but without query params.
   */
  pathname?: string | RegExp
  /**
   * Match based on requested port, or pass an array of ports
   * to match against any in that array.
   */
  port?: number | number[]
  /**
   * Match on parsed querystring parameters.
   */
  query?: {
    [key: string]: string | RegExp
  }
  /**
   * Match against the full request URL.
   */
  url?: string | RegExp
}

routeMatcher ejemplos de uso:

cy.intercept({
  pathname: '/search',
  query: {
    q: 'some terms',
  },
}).as('searchForTerms')
// this 'cy.wait' will only resolve once a request is made to '/search'
// with the query paramater 'q=some+terms'
cy.wait('@searchForTerms')

cy.intercept(
  {
    // this RegExp matches any URL beginning with 'http://api.example.com/widgets'
    url: /^http://api.example.com/widgets/,
    headers: {
      'x-requested-with': 'exampleClient',
    },
  },
  (req) => {
    // only requests to URLs starting with 'http://api.example.com/widgets'
    // having the header 'x-requested-with: exampleClient' will be received
  }
})

// in this example, the supplied URL `/users` is merged with the RouteMatcher
// passed as the second argument
cy.intercept('/users', { middleware: true }, (req) => {
  req.headers['authorization'] = `Bearer ${bearerToken}`
})

routeHandler (string | object | Function | StaticResponse)

los routeHandler define lo que sucederá con una solicitud si routeMatcher coincide. Se puede usar para definir estáticamente una respuesta para solicitudes coincidentes, o se puede pasar una función para interceptar dinámicamente la solicitud saliente.

  • Si un cuerda se pasa, las solicitudes a la ruta se cumplirán con esa cadena como cuerpo. Paso "foo" es equivalente a usar un StaticResponse objeto con { body: "foo" }.
  • Si un StaticResponse objeto se pasa, las solicitudes a la ruta se cumplirán con una respuesta utilizando los valores proporcionados en el StaticResponse. A StaticResponse puede definir el cuerpo de la respuesta, así como los encabezados, el código de estado HTTP y más. Consulte Apuntar una respuesta con un StaticResponse objeto para ver un ejemplo de cómo se utiliza.
  • Si una objeto sin StaticResponse teclas se pasa, se enviará como un cuerpo de respuesta JSON. Por ejemplo, pasando { foo: 'bar' } es equivalente a pasar { body: { foo: 'bar' } }.
  • Si un llamar de vuelta se pasa, se llamará siempre que se reciba una solicitud que coincida con esta ruta, siendo el primer parámetro el objeto de solicitud. Desde dentro de la devolución de llamada, puede modificar la solicitud saliente, enviar una respuesta, acceder a la respuesta real y mucho más. Consulte “Solicitudes interceptadas” para obtener más información.

Rendimientos

  • cy.intercept() rendimientos null.
  • cy.intercept() se puede crear un alias, pero de lo contrario no se puede encadenar más.
  • Esperando un alias cy.intercept() La ruta que usa cy.wait () producirá un objeto que contiene información sobre el ciclo de solicitud / respuesta coincidente. Consulte Uso del objeto cedido para ver ejemplos de cómo utilizar este objeto.

Ejemplos de

URL coincidente

Puede proporcionar la URL completa para que coincida

// will match any request that exactly matches the URL
//   matches GET https://prod.cypress.io/users
//   won't match GET https://staging.cypress.io/users
cy.intercept('https://prod.cypress.io/users')

Puede proporcionar un minimatch patrón

// will match any HTTP method to urls that end with 3 or 5
cy.intercept('**/users?_limit=+(3|5)')

Propina: puede evaluar su URL usando la consola de DevTools para ver si el minimatch patrón es correcto.

// paste into the DevTools console while Cypress is running
Cypress.minimatch(
  'https://jsonplaceholder.cypress.io/users?_limit=3',
  '**/users?_limit=+(3|5)'
) // true

// print verbose debug information
Cypress.minimatch(
  'https://jsonplaceholder.cypress.io/users?_limit=3',
  '**/users?_limit=+(3|5)',
  { debug: true }
) // true + lots of debug messages

Incluso puede agregar una afirmación a la prueba para asegurarse de que la URL coincida

// arguments are url and the pattern
expect(
  Cypress.minimatch(
    'https://jsonplaceholder.cypress.io/users?_limit=3',
    '**/users?_limit=+(3|5)'
  ),
  'Minimatch test'
).to.be.true

Para la coincidencia más potente, proporcione una expresión regular

cy.intercept(//users?_limit=(3|5)$/).as('users')
cy.get('#load-users').click()
cy.wait('@users').its('response.body').should('have.length', 3)

// intercepts _limit=5 requests
cy.get('#load-five-users').click()
cy.wait('@users').its('response.body').should('have.length', 5)

Esperando una solicitud

Utilice cy.wait () con cy.intercept() alias para esperar a que se complete el ciclo de solicitud / respuesta.

Con URL

cy.intercept('http://example.com/settings').as('getSettings')
// once a request to http://example.com/settings responds, this 'cy.wait' will resolve
cy.wait('@getSettings')

Con RouteMatcher

cy.intercept({
  url: 'http://example.com/search*',
  query: { q: 'expected terms' },
}).as('search')

// once any type of request to http://example.com/search with a querystring containing
// 'q=expected+terms' responds, this 'cy.wait' will resolve
cy.wait('@search')

Usando el objeto cedido

Usando cy.wait () en un cy.intercept() El alias de ruta produce un objeto de intercepción que representa el ciclo de solicitud / respuesta:

cy.wait('@someRoute').then((interception) => {
  // 'interception' is an object with properties 'id', "https://foroayuda.es/cypress/api/commands/request" and 'response'
})

Puedes encadenar .its() y .should() para hacer valer contra los ciclos de solicitud / respuesta:

// assert that a request to this route was made with a body that included 'user'
cy.wait('@someRoute').its('request.body').should('include', 'user')

// assert that a request to this route received a response with HTTP status 500
cy.wait('@someRoute').its('response.statusCode').should('eq', 500)

// assert that a request to this route received a response body that includes 'id'
cy.wait('@someRoute').its('response.body').should('include', 'id')

Aliasing de solicitudes individuales

Los alias se pueden establecer por solicitud configurando el alias propiedad de la solicitud interceptada:

cy.intercept('POST', '/graphql', (req) => {
  if (req.body.hasOwnProperty('query') && req.body.query.includes('mutation')) {
    req.alias = 'gqlMutation'
  }
})

// assert that a matching request has been made
cy.wait('@gqlMutation')

Aliasing de solicitudes GraphQL individuales

Los alias se pueden establecer por solicitud configurando el alias propiedad de la solicitud interceptada.

Esto es útil contra los puntos finales GraphQL para esperar consultas y mutaciones específicas.

Dado que el operationName La propiedad es opcional en las solicitudes GraphQL, podemos alias con o sin esta propiedad.

Con operationName propiedad:

cy.intercept('POST', '/graphql', (req) => {
  if (req.body.operationName.includes('ListPosts')) {
    req.alias = 'gqlListPostsQuery'
  }
})

// assert that a matching request for the ListPosts Query has been made
cy.wait('@gqlListPostsQuery')
cy.intercept('POST', '/graphql', (req) => {
  if (req.body.operationName.includes('CreatePost')) {
    req.alias = 'gqlCreatePostMutation'
  }
})

// assert that a matching request for the CreatePost Mutation has been made
cy.wait('@gqlCreatePostMutation')

Sin operationName propiedad:

cy.intercept('POST', '/graphql', (req) => {
  const { body } = req

  if (body.hasOwnProperty('query') && body.query.includes('ListPosts')) {
    req.alias = 'gqlListPostsQuery'
  }
})

// assert that a matching request for the ListPosts Query has been made
cy.wait('@gqlListPostsQuery')
cy.intercept('POST', '/graphql', (req) => {
  const { body } = req

  if (body.hasOwnProperty('query') && body.query.includes('CreatePost')) {
    req.alias = 'gqlCreatePostMutation'
  }
})

// assert that a matching request for the CreatePost Mutation has been made
cy.wait('@gqlCreatePostMutation')

Esperando errores

Puede usar cy.wait () para esperar solicitudes que terminan con errores de red:

cy.intercept('GET', '/should-err', { forceNetworkError: true }).as('err')

// assert that this request happened, and that it ended in an error
cy.wait('@err').should('have.property', 'error')

Apuntando una respuesta

Con una cuerda

// requests to '/update' will be fulfilled with a body of "success"
cy.intercept('/update', 'success')

Con un accesorio

// requests to '/users.json' will be fulfilled
// with the contents of the "users.json" fixture
cy.intercept('/users.json', { fixture: 'users.json' })

Con un StaticResponse objeto

A StaticResponse El objeto representa una respuesta a una solicitud HTTP y se puede utilizar para stub de rutas:

const staticResponse = {
  /* some StaticResponse properties here... */
}

cy.intercept('/projects', staticResponse)

Por ejemplo, para apuntar una respuesta con un cuerpo JSON:

cy.intercept('/projects', {
  body: [{ projectId: '1' }, { projectId: '2' }],
})

O para los encabezados de código auxiliar, el código de estado y el cuerpo de una sola vez:

cy.intercept('/not-found', {
  statusCode: 404,
  body: '404 Not Found!',
  headers: {
    'x-not-found': 'true',
  },
})

Ver “StaticResponse objetos “para obtener más información sobre StaticResponses.

Interceptar una solicitud

Afirmar en una solicitud

cy.intercept('POST', '/organization', (req) => {
  expect(req.body).to.include('Acme Company')
})

Modificar una solicitud saliente

Puede utilizar la devolución de llamada del controlador de solicitudes para modificar la solicitud antes de que se envíe.

cy.intercept('POST', '/login', (req) => {
  // set the request body to something different before it's sent to the destination
  req.body = 'username=janelane&password=secret123'
})

Agregar un encabezado a una solicitud saliente

Puede agregar un encabezado a una solicitud saliente o modificar un encabezado existente

cy.intercept('/req-headers', (req) => {
  req.headers['x-custom-headers'] = 'added by cy.intercept'
})

Nota: el nuevo encabezado NO se mostrará en la pestaña Red del navegador, ya que la solicitud ya salió del navegador. Aún puede confirmar que se agregó el encabezado esperando en la intercepción como se muestra a continuación:

cy.intercept('/req-headers', (req) => {
  req.headers['x-custom-headers'] = 'added by cy.intercept'
}).as('headers')

// the application makes the call ...
// confirm the custom header was added
cy.wait('@headers')
  .its('request.headers')
  .should('have.property', 'x-custom-headers', 'added by cy.intercept')

Agregar, modificar o eliminar un encabezado a todas las solicitudes salientes

Puede agregar, modificar o eliminar un encabezado a todas las solicitudes salientes usando un beforeEach() en el cypress/support/index.js expediente

// Code from Real World App (RWA)
// cypress/support/index.ts
import './commands'

beforeEach(() => {
  cy.intercept(
    { url: 'http://localhost:3001/**', middleware: true },
    // Delete 'if-none-match' header from all outgoing requests
    (req) => delete req.headers['if-none-match']
  )
})

Ejemplo del mundo real

Clonar el Aplicación del mundo real (RWA) y consulte el cypress / support / index.ts archivo para un ejemplo de trabajo.

Apuntando dinámicamente una respuesta

Puedes usar el req.reply() función para controlar dinámicamente la respuesta a una solicitud.

cy.intercept('/billing', (req) => {
  // functions on 'req' can be used to dynamically respond to a request here

  // send the request to the destination server
  req.reply()

  // respond to the request with a JSON object
  req.reply({ plan: 'starter' })

  // send the request to the destination server, and intercept the response
  req.continue((res) => {
    // 'res' represents the real destination's response
    // See "Intercepting a response" for more details and examples
  })
})

Consulte “Solicitudes interceptadas” para obtener más información sobre req objeto y sus propiedades y métodos.

Devolver una promesa

Si se devuelve una promesa de la devolución de llamada de ruta, se esperará antes de continuar con la solicitud.

cy.intercept('POST', '/login', (req) => {
  // you could asynchronously fetch test data...
  return getLoginCredentials().then((credentials) => {
    // ...and then, use it to supplement the outgoing request
    req.headers['authorization'] = credentials
  })
})

Pasar una solicitud al siguiente controlador de solicitudes

Si req.reply() o req.continue() no se llama explícitamente dentro de un controlador de solicitudes, las solicitudes pasarán al siguiente controlador de solicitudes hasta que no quede ninguna.

// you could have a top-level middleware handler that sets an auth token on all requests
// setting `middleware: true` will cause this to always be called first
cy.intercept('http://api.company.com/', { middleware: true }, (req) => {
  req.headers['authorization'] = `token ${token}`
})

// and then have another handler that more narrowly asserts on certain requests
cy.intercept('POST', 'http://api.company.com/widgets', (req) => {
  expect(req.body).to.include('analytics')
})

// a POST request to http://api.company.com/widgets would hit both
// of those callbacks, middleware first, then the request would be sent out
// with the modified request headers to the real destination

Interceptar una respuesta

Dentro de una devolución de llamada pasada a req.continue(), puede acceder a la respuesta real del servidor de destino.

cy.intercept('/integrations', (req) => {
  // req.continue() with a callback will send the request to the destination server
  req.continue((res) => {
    // 'res' represents the real destination response
    // you can manipulate 'res' before it's sent to the browser
  })
})

Consulte “Respuestas interceptadas” para obtener más información sobre el res objeto. Consulte “Control de la solicitud de salida con req.continue()“para obtener más información sobre req.continue().

Afirmar en una respuesta

cy.intercept('/projects/2', (req) => {
  req.continue((res) => {
    expect(res.body).to.include('My Project')
  })
})

Devolver una promesa

Si se devuelve una Promesa de la devolución de llamada de ruta, se esperará antes de enviar la respuesta al navegador.

cy.intercept('/users', (req) => {
  req.continue((res) => {
    // the response will not be sent to the browser until 'waitForSomething()' resolves
    return waitForSomething()
  })
})

Acelerar o retrasar la respuesta a todas las respuestas entrantes

Puede acelerar o retrasar todas las respuestas entrantes mediante un beforeEach() en el cypress/support/index.js expediente

// Code from Real World App (RWA)
// cypress/support/index.ts
import { isMobile } from './utils'
import './commands'
// Throttle API responses for mobile testing to simulate real world conditions
if (isMobile()) {
  cy.intercept({ url: 'http://localhost:3001/**', middleware: true }, (req) => {
    req.on('response', (res) => {
      // Throttle the response to 1 Mbps to simulate a mobile 3G connection
      res.setThrottle(1000)
    })
  })
}

Ejemplo del mundo real

Clonar el Aplicación del mundo real (RWA) y consulte el cypress / support / index.ts archivo para un ejemplo de trabajo.

Solicitudes interceptadas

Si se pasa una función como controlador de una cy.intercept(), se llamará con el primer argumento como un objeto que representa la solicitud HTTP interceptada:

cy.intercept('/api', (req) => {
  // `req` represents the intercepted HTTP request
})

Desde aquí, puede hacer varias cosas con la solicitud interceptada:

  • puede modificar y afirmar las propiedades de la solicitud (cuerpo, encabezados, URL, método …)
  • la solicitud se puede enviar al servidor ascendente real
    • opcionalmente, puede interceptar la respuesta de este
  • se puede proporcionar una respuesta para eliminar la solicitud
  • los oyentes se pueden adjuntar a varios eventos en la solicitud

Solicitar propiedades de objeto

El objeto de solicitud (req) tiene varias propiedades de la propia solicitud HTTP. Todas las siguientes propiedades en req se puede modificar excepto para httpVersion:

{
  /**
   * The body of the request.
   * If a JSON Content-Type was used and the body was valid JSON, this will be an object.
   * If the body was binary content, this will be a buffer.
   */
  body: string | object | any
  /**
   * The headers of the request.
   */
  headers: { [key: string]: string }
  /**
   * Request HTTP method (GET, POST, ...).
   */
  method: string
  /**
   * Request URL.
   */
  url: string
  /**
   * The HTTP version used in the request. Read only.
   */
  httpVersion: string
}

req también tiene algunas propiedades opcionales que se pueden configurar para controlar el comportamiento específico de Cypress:

{
  /**
   * If provided, the number of milliseconds before an upstream response to this request
   * will time out and cause an error. By default, `responseTimeout` from config is used.
   */
  responseTimeout?: number
  /**
   * Set if redirects should be followed when this request is made. By default, requests will
   * not follow redirects before yielding the response (the 3xx redirect is yielded)
   */
  followRedirect?: boolean
  /**
   * If set, `cy.wait` can be used to await the request/response cycle to complete for this
   * request via `cy.wait('@alias')`.
   */
  alias?: string
}

Cualquier modificación a las propiedades de req se conservará en otros controladores de solicitudes y, finalmente, se fusionará con la solicitud HTTP saliente real.

Controlando la solicitud saliente con req.continue()

Vocación req.continue() sin ningún argumento hará que la solicitud se envíe saliente, y la respuesta se devolverá al navegador después de que se haya llamado a otros oyentes. Por ejemplo, el siguiente código modifica un POST solicitud y luego la envía al servidor ascendente:

cy.intercept('POST', '/submitStory', (req) => {
  req.body.storyName = 'some name'
  // send the modified request and skip any other matching request handlers
  req.continue()
})

Si se pasa una función a req.continue(), la solicitud se enviará al servidor ascendente real y se llamará a la devolución de llamada con la respuesta una vez que la respuesta se haya recibido completamente del servidor. Ver “Respuestas interceptadas”

Nota: llamando req.continue() evitará que la solicitud se propague al siguiente controlador de solicitudes coincidente en línea. Consulte “Ciclo de vida de la interceptación” para obtener más información.

Proporcionar una respuesta de código auxiliar con req.reply()

los req.reply() La función se puede utilizar para enviar una respuesta de código auxiliar para una solicitud interceptada. Pasando una cadena, objeto o StaticResponse para req.reply(), la solicitud puede impedir que llegue al servidor de destino.

Por ejemplo, el siguiente código elimina una respuesta JSON de un interceptor de solicitudes:

cy.intercept('/billing', (req) => {
  // dynamically get billing plan name at request-time
  const planName = getPlanName()
  // this object will automatically be JSON.stringified and sent as the response
  req.reply({ plan: planName })
})

En lugar de pasar un objeto simple o una cadena a req.reply(), también puede pasar un StaticResponse objeto. Con un StaticResponse, puede forzar un error de red, retrasar / acelerar la respuesta, enviar un dispositivo y más.

Por ejemplo, el siguiente código sirve para un dispositivo elegido dinámicamente con un retraso de 500 ms:

cy.intercept('/api/users/*', async (req) => {
  // asynchronously retrieve fixture filename at request-time
  const fixtureFilename = await getFixtureFilenameForUrl(req.url)
  req.reply({
    fixture: fixtureFilename,
    delay: 500,
  })
})

Ver el StaticResponse documentación para obtener más información sobre las respuestas de stubbing de esta manera.

req.reply() también admite taquigrafía, similar a res.send(), para evitar tener que especificar un StaticResponse objeto:

req.reply(body) // equivalent to `req.reply({ body })`
req.reply(body, headers) // equivalent to `req.reply({ body, headers })`
req.reply(statusCode, body, headers) // equivalent to `req.reply({ statusCode, body, headers})`

También hay dos funciones de conveniencia disponibles en req:

{
  /**
   * Destroy the request and respond with a network error.
   */
  destroy(): void
  /**
   * Respond to this request with a redirect to a new 'location'.
   * @param statusCode HTTP status code to redirect with. Default: 302
   */
  redirect(location: string, statusCode?: number): void
}

Nota: llamando req.reply() finalizará la fase de solicitud y detendrá la solicitud de propagándose al siguiente controlador de solicitud coincidente en línea. Consulte “Ciclo de vida de la interceptación” para obtener más información.

Solicitar eventos

Para uso avanzado, varios eventos están disponibles en req, que representan diferentes etapas del ciclo de vida de la interceptación.

Llamando req.on, puedes suscribirte a diferentes eventos:

cy.intercept('/shop', (req) => {
  req.on('before:response', (res) => {
    /**
     * Emitted before `response` and before any `req.continue` handlers.
     * Modifications to `res` will be applied to the incoming response.
     * If a promise is returned, it will be awaited before processing other event handlers.
     */
  })

  req.on('response', (res) => {
    /**
     * Emitted after `before:response` and after any `req.continue` handlers - before the response is sent to the browser.
     * Modifications to `res` will be applied to the incoming response.
     * If a promise is returned, it will be awaited before processing other event handlers.
     */
  })

  req.on('after:response', (res) => {
    /**
     * Emitted once the response to a request has finished sending to the browser.
     * Modifications to `res` have no impact.
     * If a promise is returned, it will be awaited before processing other event handlers.
     */
  })
})

Consulte “Respuestas interceptadas” para obtener más detalles sobre el res objeto cedido por before:response y response. Consulte “Ciclo de vida de la interceptación” para obtener más detalles sobre cómo realizar pedidos.

Respuestas interceptadas

La respuesta se puede interceptar de dos formas:

  • pasando una devolución de llamada a req.continue() dentro de un controlador de solicitudes
  • escuchando el before:response o response solicitar eventos (ver “Solicitar eventos”)

El objeto de respuesta, res, se pasará como primer argumento a la función del controlador:

cy.intercept('/url', (req) => {
  req.on('before:response', (res) => {
    // this will be called before any `req.continue` or `response` handlers
  })

  req.continue((res) => {
    // this will be called after all `before:response` handlers and before any `response` handlers
    // by calling `req.continue`, we signal that this request handler will be the last one, and that
    // the request should be sent outgoing at this point. for that reason, there can only be one
    // `req.continue` handler per request.
  })

  req.on('response', (res) => {
    // this will be called after all `before:response` handlers and after the `req.continue` handler
    // but before the response is sent to the browser
  })
})

Propiedades del objeto de respuesta

El objeto de respuesta (res) cedido a los controladores de respuesta tiene varias propiedades de la propia respuesta HTTP. Todas las siguientes propiedades en res se puede modificar:

{
  /**
   * The body of the response.
   * If a JSON Content-Type was used and the body was valid JSON, this will be an object.
   * If the body was binary content, this will be a buffer.
   */
  body: string | object | any
  /**
   * The headers of the response.
   */
  headers: { [key: string]: string }
  /**
   * The HTTP status code of the response.
   */
  statusCode: number
  /**
   * The HTTP status message.
   */
  statusMessage: string
}

res también tiene algunas propiedades opcionales que se pueden configurar para controlar el comportamiento específico de Cypress:

{
  /**
   * Kilobits per second to send 'body'.
   */
  throttleKbps?: number
  /**
   * Milliseconds to delay before the response is sent.
   */
  delay?: number
}

Cualquier modificación a las propiedades de res se conservará en otros controladores de respuesta y, finalmente, se fusionará con la respuesta HTTP entrante real.

Terminando la respuesta con res.send()

Para finalizar la fase de respuesta de la solicitud, llame res.send(). Opcionalmente, puede pasar un StaticResponse para res.send(), que se fusionará con la respuesta real.

Cuando res.send() se llama, la fase de respuesta finalizará inmediatamente y no se llamará a ningún otro controlador de respuesta para la solicitud actual. He aquí un ejemplo de cómo res.send() puede ser usado:

cy.intercept('/notification', (req) => {
  req.continue((res) => {
    if (res.body.status === 'failed') {
      // sends a fixture body instead of the existing 'res.body'
      res.send({ fixture: 'success.json' })
    }
  })
})

Ver el StaticResponse documentación para obtener más información sobre el formato.

res.send() también admite taquigrafía, similar a req.reply(), para evitar tener que especificar un StaticResponse objeto:

res.send(body) // equivalent to `res.send({ body })`
res.send(body, headers) // equivalent to `res.send({ body, headers })`
res.send(statusCode, body, headers) // equivalent to `res.send({ statusCode, body, headers})`

También hay dos funciones de conveniencia disponibles en res:

{
  /**
   * Wait for 'delay' milliseconds before sending the response to the client.
   */
  setDelay: (delay: number) => IncomingHttpResponse
  /**
   * Serve the response at 'throttleKbps' kilobytes per second.
   */
  setThrottle: (throttleKbps: number) => IncomingHttpResponse
}

Nota: llamando res.send() terminará la fase de respuesta y evitará que la respuesta se propague al siguiente controlador de respuesta coincidente en la línea. Consulte “Ciclo de vida de la interceptación” para obtener más información.

StaticResponse objetos

A StaticResponse representa una respuesta cortada a una solicitud HTTP. Puede suministrar un StaticResponse a Cypress de 3 formas:

  • Directamente a cy.intercept(), para apuntar una respuesta a una ruta: cy.intercept('/url', staticResponse)
  • Para req.reply(), para apuntar una respuesta de un controlador de solicitudes: req.reply(staticResponse)
  • Para res.send(), para apuntar una respuesta de un controlador de respuesta: res.send(staticResponse)

Las siguientes propiedades están disponibles en StaticResponse. Todas las propiedades son opcionales:

{
  /**
   * Serve a fixture as the response body.
   */
  fixture?: string
  /**
   * Serve a static string/JSON object as the response body.
   */
  body?: string | object | object[]
  /**
   * HTTP headers to accompany the response.
   * @default {}
   */
  headers?: { [key: string]: string }
  /**
   * The HTTP status code to send.
   * @default 200
   */
  statusCode?: number
  /**
   * If 'forceNetworkError' is truthy, Cypress will destroy the browser connection
   * and send no response. Useful for simulating a server that is not reachable.
   * Must not be set in combination with other options.
   */
  forceNetworkError?: boolean
  /**
   * Milliseconds to delay before the response is sent.
   */
  delay?: number
  /**
   * Kilobits per second to send 'body'.
   */
  throttleKbps?: number
}

Consulte “Apuntar una respuesta con un StaticResponse object “para ver ejemplos de stubbing con cy.intercept().

Ciclo de vida de la interceptación

El ciclo de vida de un cy.intercept() la intercepción comienza cuando se envía una solicitud HTTP desde su aplicación que coincide con uno o más registrados cy.intercept() rutas. A partir de ahí, cada intercepción tiene dos fases: solicitud y respuesta.

cy.intercept() Las rutas coinciden en orden inverso a la definición, excepto para las rutas que se definen con { middleware: true }, que siempre se ejecuta primero. Esto le permite anular los cy.intercept() declaraciones definiendo una superposición cy.intercept().

Fase de solicitud

Los siguientes pasos se utilizan para manejar la fase de solicitud.

  1. Comience con la primera ruta coincidente de acuerdo con el algoritmo anterior (primero el middleware, seguido de los controladores en orden inverso).
  2. Era un manejador (cuerpo, StaticResponse, o función) suministrado a cy.intercept()? Si no es así, continúe con el paso 7.
  3. Si el manejador era un cuerpo o StaticResponse, finalice inmediatamente la solicitud con esa respuesta.
  4. Si el controlador era una función, llame a la función con req, la solicitud entrante, como primer argumento. Consulte “Solicitudes interceptadas” para obtener más información sobre req objeto.
    • Si req.reply() se llama, finalice inmediatamente la fase de solicitud con la respuesta proporcionada. Consulte “Proporcionar una respuesta de código auxiliar con req.reply()“.
    • Si req.continue() se llama, finaliza inmediatamente la fase de solicitud y envía la solicitud al servidor de destino. Si se proporciona una devolución de llamada a req.continue(), se llamará durante la fase de respuesta
  5. Si el manejador devolvió una Promesa, espere a que se resuelva.
  6. Fusionar cualquier modificación del objeto de solicitud con la solicitud real.
  7. Si hay otra coincidencia cy.intercept(), vuelva al paso 2 y continúe siguiendo los pasos con esa ruta.
  8. Envíe la solicitud saliente al servidor de destino y finalice la fase de solicitud. La fase de respuesta comenzará una vez que se reciba una respuesta.

Fase de respuesta

Una vez que se recibe la respuesta HTTP del servidor ascendente, se aplican los siguientes pasos:

  1. Obtener una lista de registrados before:response oyentes de eventos.
  2. Para cada before:response oyente (si lo hay), llámelo con el res objeto.
    • Si res.send() se llama, finaliza la fase de respuesta y fusiona los argumentos pasados ​​con la respuesta.
    • Si se devuelve una Promesa, espérela. Fusionar cualquier propiedad de respuesta modificada con la respuesta real.
  3. Si un req.continue() con devolución de llamada se declara para esta ruta, llame a la devolución de llamada con el res objeto.
    • Si res.send() se llama, finaliza la fase de respuesta y fusiona los argumentos pasados ​​con la respuesta.
    • Si se devuelve una Promesa, espérela. Fusionar cualquier propiedad de respuesta modificada con la respuesta real.
  4. Obtenga una lista de registrados response oyentes de eventos.
  5. Para cada response oyente (si lo hay), llámelo con el res objeto.
    • Si res.send() se llama, finaliza la fase de respuesta y fusiona los argumentos pasados ​​con la respuesta.
    • Si se devuelve una Promesa, espérela. Fusionar cualquier propiedad de respuesta modificada con la respuesta real.
  6. Envíe la respuesta al navegador.
  7. Una vez que la respuesta esté completa, obtenga una lista de after:response oyentes de eventos.
  8. Para cada after:response oyente (si lo hay), llámelo con el res objeto (menos res.send)
    • Si se devuelve una Promesa, espérela.
  9. Finaliza la fase de respuesta.

Historia

Versión Cambios
7.0.0 Remoto matchUrlAgainstPath opción de RouteMatcher, orden de controlador inverso, eventos de solicitud agregados, coincidencia de URL de subcadena eliminada, eliminado cy.route2 alias, agregado middleware Opción RouteMatcher, renombrada res.delay() para res.setDelay() y res.throttle() para res.setThrottle().
6.4.0 Renombrado delayMs propiedad a delay (compatible con versiones anteriores).
6.2.0 Adicional matchUrlAgainstPath opción a RouteMatcher.
6.0.0 Renombrado cy.route2() para cy.intercept().
6.0.0 Remoto experimentalNetworkStubbing y lo convirtió en el comportamiento predeterminado.
5.1.0 Experimental agregado cy.route2() comando bajo experimentalNetworkStubbing opción.

Notas

cy.intercept() no se puede depurar usando cy.request()

cy.request() envía solicitudes a los puntos finales reales, omitiendo los definidos mediante cy.intercept()

La intencion de cy.request() se utiliza para comprobar los puntos finales en un servidor real en ejecución sin tener que iniciar la aplicación de interfaz.

Ver también