Тестирование PDF-файла при помощи Cypress |
07.09.2023 00:00 |
Автор: Филип Рик (Filip Hric) Недавно на LinkedIn меня спросили, может ли Cypress тестировать содержание PDF-файла. Поначалу я решил, что это невозможно, так как Cypress создан для тестирования веб-приложений. Однако, немного поразмышляв, я осознал, что несколько решений такой проблемы все же существует. Начнем с описания нашего приложения. Его можно клонировать с моей страницы GitHub и посмотреть на решения, описанные в этой статье. По сути это простой html-файл, содержащий ссылки на два PDF-файла. Клик по кнопке скачает их на ваш компьютер. Верификация загрузкиДля начала напишем простой тест на скачивание нашего файла. Код теста будет простым: cy.visit('/') Этот тест завершится сразу после клика по кнопке. Но как мы узнаем, произошло ли что-то на самом деле? Ну, для начала, это можно проверить вручную, заглянув в папку /cypress/downloads, где хранятся все загрузки, сделанные нашими тестами. Целевую папку загрузок можно настроить, изменив атрибут downloadsFolder в файле cypress.config.ts. Но как нам проверить, был ли файл действительно скачан? Самый простой способ – воспользоваться командой cy.readFile(). Эта команда выдаст ошибку, если файл не найден, и отлично подходит для нашего случая. Однако тут стоит отметить, что при запуске тестов через npx cypress open скачанные файлы будут перезаписаны. Это тоже важно, потому что мы можем попасть в ситуацию ложноположительного результата – мы используем команду cy.readFile(), а файл с таким именем уже находится в папке загрузок и был там еще до запуска теста. В случае со скриптом запуска npx cypress этого не произойдет – он автоматически очистит содержимое папки загрузок перед запуском. Чтобы изменить это поведение, можно настроить опцию trashAssetsBeforeRuns в файле cypress.config.ts file. К тому же, создавая тесты, стоит добавить папку cypress/downloads в файл .gitignore, чтобы она нечаянно не разнесла вам репозиторий. Проверка содержимого файлаКоманда cy.readFile() помогает убедиться, что файл был скачан, но не сильно помогает с нашим PDF-файлом. По иронии судьбы, она не может сделать именно то, что заявляет в своем собственном имени – прочитать файл. Вот результат работы этой команды в консоли: К сожалению, в Cypress нет встроенного способа для чтения содержимого нашего файла, поэтому придется придумать что-то самостоятельно. Довольно-таки просто будет воспользоваться cy.task(), но тут есть ряд небольших нюансов, с которыми нужно разобраться. Для начала создадим наш сценарий. Быстрый поиск парсера pdf на npmjs.com приведет нас к симпатичному маленькому пакету pdf-parse. То, как им пользоваться, подробно описано на его страничке, поэтому начнем. const fs = require("fs"); export const readPdf = (pathToPdf: string) => { const resolvedPath = path.resolve(pathToPdf) return text }); Теперь у нас есть функция readPdf, которая принимает аргумент pathToPdf. Это путь к нашей папке загрузок. Теперь можно выполнить вызов при помощи команды cy.task(). Однако прежде чем заняться этим, нужно добавить путь в функцию setupNodeEvents function в файле cypress.config.ts: import { defineConfig } from 'cypress' export default defineConfig({ В настройках мы импортируем наш сценарий, который я сохранил в созданной для своих нужд папке cypress/scripts. В setupNodeEvents я передаю сценарий readPdf. Это означает, что при любом вызове cy.task('readPdf') будет вызван cypress/scripts/readPdf, возвращая содержимое PDF-файла. Теперь все почти отлично. Остался всего один нюанс. По какой-то причине мы получим эту ошибку: Понимание причины заняло у меня некоторое время – я понял, что моя функция еще обрабатывает PDF-файл, а cy.task() не ждет, пока она закончит. Чтобы убедиться, что функция действительно завершила свою работу, нужно обернуть ее в обещание. Обещания в Cypress могут по первости смущать (меня они точно смутили), но в этом случае код довольно прост: const fs = require("fs"); export const readPdf = (pathToPdf: string) => { return new Promise((resolve) => { resolve(text) }); Таким образом мы убедимся, что несмотря на то, что обработка файла занимает время, Cypress подождет ее завершения. По умолчанию он будет ждать до 60 секунд. Это можно изменить в файле cypress.config.ts – опция taskTimeout. Команда cy.task() передаст текст PDF следующей команде, где мы можем сразу его проверить: cy.task('readPdf', 'cypress/downloads/simple.pdf') Вместо contain можно использовать ассерт eq, но в этом случае нужно иметь в виду все пробелы и абзацы, содержащиеся в тексте. Сложность чтения и обработки файла возрастет сообразно сложности тестируемого PDF-файла, но для борьбы с ней есть несколько способов. К примеру, можно организовать все строки в массив. Все фразы или предложения, разделенные новой строкой, станут отдельным элементом массива: export const readPdf = (pathToPdf: string) => { return new Promise((resolve) => { const arr = text.split("\n"); }); |