Как проверить исключительное поведение с Кукольником? - PullRequest
1 голос
/ 29 января 2020

Многие имеют опыт работы с универсальными c автоматизированными тестами с Puppeteer. В основном это имитация поведения пользователей на веб-страницах и утверждение результатов. Но что, если вам нужно протестировать представление состояния с ошибкой, которое вы не можете (или не знаете, как) инициировать действием пользователя? Например, у нас есть форма. Когда пользователь отправляет приложение, приложение отправляет запрос POST на сервер и показывает сообщения об успехе, как только сервер ответит 200 OK. Это ожидаемое поведение. Тем не менее, в реальном мире сервер может быть недоступен или отвечает с внутренней ошибкой. Представьте себе, что приложение с благодарностью освещает этот случай. Но как мы воспроизведем это с Кукольником?

1 Ответ

0 голосов
/ 29 января 2020

Учитывая, что Puppeteer предоставляет множество возможностей по обработке запросов HTTP / S, я пришел к следующему решению. При отправке формы я высмеиваю ответ сервера своим собственным. По сути, я установил перехватчик, который заменяет следующий запрос, соответствующий заданному фрагменту URL-адреса, пользовательским ответом сервера:

await bs.mockRequest( "response.json", { "GET", "500 Internal Server Error", "application/javascript", "{ \"status\": \"FAIL\" }", [] });

Пока он наблюдает за сетью, я могу отправить форму, например, эмулируя нажатие на кнопку отправки. кнопка. Следующий запрос будет заменен так, чтобы тестируемое приложение обрабатывало его как в случае реальной ошибки сервера.

Вот исходный код mockRequest:

class BrowserSession {
  // obtaining page context from Puppeteer
  // @see https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-puppeteerlaunchoptions
  async setup( options ) {
    this.browser = await puppeteer.launch( options );
    this.context = await this.browser.createIncognitoBrowserContext();
    this.page = await this.context.newPage();
  }
  /**
   * Intercept and replace request
   * @param {String} url - URL substring to match
   * @param {Object} newRespond 
   */
  async mockRequest( url, { method, status, contentType, newBody, headers }) {
    const session = await this.page.target().createCDPSession(),
          patterns = [ `*${ url }*` ];

    await session.send( "Network.enable" );

    await session.send( "Network.setRequestInterception", {
      patterns: patterns.map( pattern => ({
        urlPattern: pattern,
        interceptionStage: "HeadersReceived"
      }))
    });

    session.on( "Network.requestIntercepted", async ({ interceptionId, request, responseHeaders, resourceType }) => {

      if ( ( method || "GET" ) !== request.method.toUpperCase() ) {
        await session.send( "Network.continueInterceptedRequest", { interceptionId });
        return;
      }

      const newHeaders = [
        "Date: " + ( new Date() ).toUTCString(),
        "Connection: closed",
        "Content-Length: " + newBody.length,
        "Content-Type: " + contentType,
        ...headers
      ];

      await session.send( "Network.continueInterceptedRequest", {
        interceptionId,
        rawResponse: btoa( `HTTP/1.1 ${ status }\r\n`
          + newHeaders.join('\r\n') + '\r\n\r\n' + newBody )
      });

      session.detach();
    });

  }
}
...