Начало работы с E2E-тестированием Puppeteer

Node.js Puppeteer тестовое задание E2E

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

Что такое Кукловод

Он предоставляется официальной командой Chrome и предоставляет ряд API-интерфейсов на уровне узла для управления хромом или хромом через протокол Devtools, что означает, что мы можем контролировать поведение браузера, написав код в среде узла. С его помощью мы можем сделать следующее:

  • Создание снимков страницы: изображения, pdf

  • Просканируйте спа-приложение для создания предварительно обработанных страниц.

  • Автоматизация отправки форм, тестирование пользовательского интерфейса, ввод с клавиатуры

  • Сбор данных о производительности приложений (хронология производительности Chrome)

  • проверить расширение хром

Конечно, описанное выше поведение — это очень малая часть способностей кукловода.ДокументацияПоймите, эта статья познакомит вас с практикой Puppeteer в тестировании E2E.

E2E-тестирование

Проще говоря, это моделирование реальных сценариев использования пользователя для тестирования, и ожидается, что приложение может нормально реагировать на действия пользователя.Ключевым моментом является моделирование пользовательской среды и моделирование пользовательских операций.

Для веб-приложений пользовательской средой является браузер, а пользовательские операции в основном перемещаются и щелкают.Это те части, которые нам нужно смоделировать.Теперь мы непосредственно войдем в среду и часть практики.

Раздел окружающей среды

В примерах в этой статье используетсяpuppeteer jest jest-puppeteerРеализовано в среде Mac

В первую очередь необходимо установить вышеперечисленные зависимости, здесь нужно обратить внимание на следующие вопросы:

  • puppeteer по умолчанию загрузит хром, здесь вы можете пройтиexport PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=trueпропустить загрузку хрома

  • Версия Node лучше использовать версию выше 8

Ниже описывается соответствующая конфигурация

Первая — это конфигурация, связанная с шуткой, созданная в корневом каталоге.jest.config.js

//jest.config.js
const config = require('config');
const _ = require('lodash');

module.exports = {
    preset: 'jest-puppeteer', //调用preset
    globals: _.assign({}, config.get('e2e.variable'), { //这里可以注入全局变量
        ENV_URL: config.get('baseUrl')
    }),
    testMatch: ['**/__e2e__/**/*.test.js?(x)'] //指定需要进行测试的文件
};

Следующий шаг — настроить puppeteer и создать его в корневом каталоге.jest-puppeteer.config.js

//jest-puppeteer.config.js
module.exports = {
    launch: {
      	headless: true, //设定运行模式,false的情况下将会工作在有GUI界面的模式,true则不开启GUI界面
        executablePath: //设定本地Chrome路径,官方推荐使用Chrome Canary
            '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'
    }
};

Практическая часть

Теперь, когда среда настроена, пришло время приступить к практике. Для большинства систем, особенно систем управления, первым шагом является вход в систему, поэтому наша первая практика заключается в использовании скрипта puppeteer для имитации входа в систему.Пример здесь основан на входе в систему на стороне автора. .

const loginFunc = page => async () => {
    await page.setViewport({ width: 1280, height: 720 });                           //设置窗口大小
    await page.goto(`${ENV_URL}/login`);                                            //前往登录地址
    const loginIframe = page.frames().find(f => f.name() === 'login-iframe');       //找到登录iframe
    await loginIframe.waitForSelector(
        '#login-tab-container > div.tab-item.tab-right'
    ); 
    await loginIframe.click('#login-tab-container > div.tab-item.tab-right');       //切换登录TAB
    await page.waitFor(1000);                                                       //特殊用途,之后说明
    const username = await loginIframe.waitForSelector('#username');                //找到输入框
    await username.type(USERNAME);                                                  //输入用户名
    const pass = await loginIframe.waitForSelector('#password'); 
    await pass.type(PASSWORD);                                                      //输入密码
    await loginIframe.click('#login-btn');                                          //点击登录按钮
    await page.waitForNavigation();                                                 //等待跳转导航完成
};

module.exports = {
    loginFunc: loginFunc
};

В этом примере показан процесс открытия страницы входа, ввода имени пользователя, пароля и входа в систему, который в основном включаетsetViewport goto frames waitForSelector click waitFor type waitForNavigationЭти API-интерфейсы, давайте поговорим о некоторых из наиболее важных API-интерфейсов, и другие могут ссылаться на официальные документы;

setViewport
设置窗口大小,返回一个promise

waitForSelector 
参数为CSS Selector,返回一个promise,直到指定的元素出现才会resolve,超时后会reject

click 
点击某个元素,返回一个promise

type 
向某个元素输入内容,返回一个promise

waitForNavigation 
URL改变时触发,返回promise,导航结束时resolve,通过history api进行URL更改时也可以通过该方法等待导航结束

frames
可以获取页面中所有的iframe

Я полагаю, что читатель также может почувствовать, что дизайн API PuPpeteer очень квадратный, что очень легко понять. Но на самом деле этот пример представляет собой несколько ступенчатых ям, вот опыт от этого примера:

  • Waitforselector вступит в силу только тогда, когда целевой селектор не имеет DOM, если целевой элемент переданdisplay: none; visibility: hiddenЕсли вы переключаетесь таким образом, этот метод разрешается напрямую.

  • Если в этом процессе переключения все еще есть эффект анимации, то в процессе этого эффекта анимации, будь то элемент в процессе анимации щелчка или ввода, операция не вступит в силу, и она должна дождаться окончания анимации, поэтому в этом примере также добавлен spanwaitFor(1000)Этот код для ожидания окончания анимации

На данный момент мы завершили вход в систему, а затем мы можем объединить с jest для автоматического тестирования.Давайте сначала выпустим примеры в этом разделе:

const utils = require('./utils');

jest.setTimeout(10000);

describe('e2e test', () => {
    beforeAll(utils.loginFunc(page));
    it('e2e test-1', async () => {
        const el = await page.waitForSelector(
            '#root > .services_C2FC97 > .ant-row > .ant-col-8:nth-child(1) > .service-card_C2FC97'
        );
        expect(await el.$eval('p', node => node.innerText)).toBe('test');       //获取指定元素的innerText
    });
});

В этом примере мы сначала ввели функцию loginFunc, написанную выше, в качестве предварительного условия для каждого теста.Объекты страницы и браузера puppeteer автоматически внедряются в среду выполнения., так что его можно вызвать напрямую; в этом примере тест заключается в том, соответствует ли заголовок функциональной карточки на домашней страницеtest; Этот пример очень простой, но я полагаю, что из приведенного выше примера входа читатель уже изучил процедуру написания тестовых сценариев E2E.

Однако здесь следует отметить еще одну вещь,Поскольку время запуска puppeteer и время, необходимое для открытия веб-страницы, трудно оценить, нужно пройтиjest.setTimeout(ms)Чтобы увеличить время выполнения теста, иначе он может завершиться ошибкой из-за тайм-аута выполнения.Ниже приведен окончательный результат выполнения этого примера:

yarn e2e
yarn run v1.9.4
$ cross-env NODE_ENV=test jest -c jest.config.js
Determining test suites to run...
DevTools listening on ws://127.0.0.1:54751/devtools/browser/7d8d289a-5335-4ffc-a65c-f7e98cb34de0
[1129/154120.584773:WARNING:spdy_session.cc(3152)] Received HEADERS for invalid stream 25
 PASS  __e2e__/demo.test.js (6.931s)
  e2e test
    ✓ e2e test-1 (1540ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        7.046s
Ran all test suites.
✨  Done in 10.72s.

На этом вводный урок окончен. Чувствуете себя мастером кнопок? Но на самом деле с помощью puppeteer мы можем добиться некоторых более мощных элементов управления, включая мониторинг сетевых запросов, мониторинг создания страниц и т. д. По сути, мы можем делать это вручную в браузере, а также через Node API, который он предоставляет. часть Содержание приглашает читателей прочитать документ для дальнейшего изучения;

Итак, что же нам может дать E2E-тест? По мнению автора, для долгосрочного итеративного проекта с расширением масштаба проекта время, затрачиваемое на функциональное регрессионное тестирование, неизбежно будет увеличиваться, что значительно повышает нашу эффективность, в то же время за счет плановых тестовых заданий мы может обнаружить проблемы в функции продукта раньше, чтобы гарантировать, что продукт может быть доставлен вовремя, что является наибольшей ценностью, которую он приносит.

Наконец, я рекомендую небольшой инструмент для всехpuppeteer-recorder, это плагин для Chrome, который может удобно записывать тестовые скрипты, чтобы избавиться от проблем с написанием скриптов вручную 😄 (Из-за политики одинакового происхождения этот инструмент не поддерживает запись операций внутри iframe)

@author: Monado