Швидка та легка міграція з Cypress на Playwright за допомогою OpenAI

💡 Усі статті, обговорення, новини про тестування — в одному місці. Приєднуйтесь до QA спільноти!

Привіт! Я Роман, Senior Test Automation Engineer в TenantCloud.

У цій статті я поділюся досвідом міграції великого проєкту з понад 4 000 файлів із Cypress на Playwright. Завдяки OpenAI нам вдалося провести міграцію всього за три місяці. Розповім про ключові кроки та алгоритми, які допомогли нам успішно завершити цей процес.

Ця стаття також доступна англійською мовою.

Налаштування акаунта OpenAI

Реєстрація в OpenAI: перейдіть на платформу OpenAI та зареєструйте акаунт, якщо ви ще цього не зробили.

Створення API-ключа: після входу в систему перейдіть на Dashboard, відкрийте розділ API key та створіть новий ключ. Цей ключ буде використовуватись для надсилання запитів до OpenAI.

Розуміння обмежень використання та як їх збільшити

Під час використання OpenAI API, зокрема GPT-4 Turbo (GPT-4o), ви починаєте з певними обмеженнями, які залежать від рівня вашого акаунта.

За замовчуванням усі акаунти починають у безплатному рівні (Free Tier), який має обмеження у $100 на місяць. Щоб отримати доступ до вищих лімітів і ефективніше використовувати GPT-4 Turbo, потрібно підвищити рівень використання.

Щоб вийти з безплатного рівня, спочатку потрібно оновити свій акаунт, витративши щонайменше $5. Після цього ви автоматично перейдете на перший рівень. Хоч перший рівень також має обмеження в $100 на місяць, він може надати вищі ліміти для запитів API.

Для відправлення запитів API потрібно поповнити свій кредитний баланс. Однак, ви можете поповнити баланс лише до межі вашого поточного рівня або до встановленого вами ліміту витрат у налаштуваннях акаунта.

Тож підсумуємо: після оновлення до першого рівня шляхом витрати $5 (які зараховуються на ваш кредитний баланс), ви отримаєте ліміт у $100 для витрат на місяць. За потреби можете зменшити цей ліміт у налаштуваннях. Для нашого проєкту з міграції ми витратили приблизно 150—200$.

Підготовка

Створення нової структури папок для Playwright: це дозволить вам працювати систематично, мігруючи проєкт Cypress папку за папкою.

Визначення файлів для міграції: визначте, які файли необхідно повністю мігрувати до Playwright, а які сумісні з новим фреймворком та можуть бути перенесені без змін.

Копіювання файлів з Cypress до Playwright: перед початком міграції скопіюйте ваші файли з папки Cypress до папки Playwright. Це гарантує, що оригінальні файли залишаться незмінними під час міграції, що дасть змогу легко повертатися до старих файлів для перевірки, якщо щось буде упущено або потребуватиме перехресної перевірки.

Автоматизація дрібних змін за допомогою IDE: використовуйте свою IDE для пошуку та заміни дрібних змінних або констант, які відрізняються між Cypress та Playwright.

Міграція основного коду, потім перехід до тестів і виправлень: почніть з міграції основного коду. Після цього переходьте до тестів та їхніх виправлень. Такий підхід гарантує, що основна функціональність буде стабільною перед запуском тестів.

Встановлення OpenAI та створення інструкцій для міграції:

Щоб почати автоматизувати процес міграції, потрібно налаштувати OpenAI у вашому проєкті та створити чіткі інструкції щодо того, як має відбуватись міграція.

У цьому прикладі використовується Node версії 20.15.1.

1. Встановлення OpenAI та додаткових бібліотек

npm install openai glob

2. Створення скрипту для міграції: створіть новий файл під назвою migration.js і додайте наступний код для налаштування клієнта OpenAI:

const openai = new OpenAI({
    organization: your_org_key, // Can be found in profile settings
    apiKey: your_api_key // Key you created
});

3. Визначення інструкцій для міграції: додайте блок інструкцій, які OpenAI буде використовувати для керування процесом міграції. Ось приклад:

const instructions = `Instructions for migrating from Cypress to Playwright. Here's a summarized version for better clarity:
1. **Import Statements**: Always add import statements at the top of the file.

2. **Constructor**: Always add a constructor with a page member:
\`constructor(protected page: Page) {}\`

If there is already a constructor, combine this member with the existing ones, for example:
\`protected readonly page: Page;\`
\`constructor(page: Page, selector = '[data-test="checkbox"]')\`

3. **Replacing Cypress Commands**: All Cypress commands must be replaced with Playwright syntax.

4. **Object Creation**: When creating new objects in a class like:
\`public navBar = new NavBar({ selector: '[data-test="nav-bar"]' });\`
Pass \`this.page\` to their constructor as the first argument, for example:
\`public navBar = new NavBar(this.page, { selector: '[data-test="nav-bar"]' });\`
`;

Додайте свої інструкції, враховуючи конкретні потреби. Основна мета — надати чіткі вказівки та приклади того, як слід виконувати міграцію.

4. Надання прикладів повністю мігрованого коду: разом з інструкціями створіть у вашому скрипті константи, які будуть містити приклади повністю мігрованого коду.

Ось як може виглядати повний скрипт migration.js з усім об’єднаним:

/*jshint esversion: 8 */
'use strict';
import { OpenAI } from 'openai';
import { globSync } from 'glob';
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'path';
const openai = new OpenAI({
   organization: 'your_key',
   apiKey: 'your_api key',
});
const instructions = `your instructions `;
const migratedCodeExample = `your fully migrated code`;
const migratedCodeExample3 = ``;
const migratedCodeExample4 = ``;
const migratedCodeExample5 = ``;
const files = globSync(
   'modules/users/forms/**/{*.dialog.ts,*.component.ts,*.helper.ts,*.page.ts,*.step.ts,*.tab.ts,*.service.ts,*.form.ts}',
   { ignore: '**/node_modules/**' }
);
const newDirectory = 'updated_files';
mkdirSync(newDirectory, { recursive: true });
async function callChat() {
   for (const filePath of files) {
       const codeToMigrate = readFileSync(filePath, 'utf-8');
       let chat = await openai.chat.completions.create({
           model: 'gpt-4o',
           messages: [
               {
                   role: 'system',
                   content:
                       'You will be provided with class containing cypress commands,' +
                       'and be provided with the instructions of migrating from cypress to playwright, ' +
                       'your task is to fully migrate the provided code to playwright following the instructions and applying your knowledge of commands, ' +
                       'you should migrate file as it is but add changes mentioned in instructions, ' +
                       'output must be in utf-8, typescript file, ' +
                       'only code so that I can easily paste it to the file, ' +
                       'without your explanations, text or comments, without wrapping ts code with quotes',
               },
               {
                   role: 'user',
                   content: `Here is the instructions for the migration \n\n${instructions}\n\n
                   Here's the Cypress code you need to migrate to playwright:\n${codeToMigrate}\n\n
                   Here are some examples of migrate code \n${migratedCodeExample}\n\n${migratedCodeExample2}\n\n${migratedCodeExample3}\n\n${migratedCodeExample4}} \n\n${migratedCodeExample5}`,
               },
           ],
       });
       const directoryPath = path.dirname(filePath);
       const updatedDirectory = path.join(directoryPath, 'updated_files');
       mkdirSync(updatedDirectory, { recursive: true });
       const newFilePath = path.join(updatedDirectory, path.basename(filePath));
       writeFileSync(newFilePath, chat.choices[0].message.content);
   }
}
callChat();

Скрипт автоматизує міграцію файлів Cypress на Playwright за допомогою моделі GPT-4 Turbo від OpenAI. Ось що він робить після запуску node migration.js:

  • Скрипт використовує globSync для пошуку всіх відповідних файлів TypeScript на основі наданого вами шаблону.
  • Створюється нова директорія з назвою updated_files, у якій будуть зберігатися мігровані файли.
  • Для кожного знайденого файлу скрипт зчитує його вміст і надсилає його разом з інструкціями щодо міграції та прикладами до OpenAI.
  • Скрипт записує мігрований код у новий файл у директорії updated_files, зберігаючи оригінальну структуру папок.

Перегляд та завершення міграції

  1. Перевірте мігрований код: уважно перегляньте код, згенерований AI, щоб переконатися, що жодні частини не були пропущені або мігрували неправильно.
  2. Замініть старий код: якщо все виглядає добре, скопіюйте мігрований код з директорії updated_files та замініть старий код у вашому проєкті.
  3. Приберіть зайве: після того, як ви замінили всі необхідні файли, видаліть директорію updated_files для очищення проєкту від тимчасових файлів.

На що варто звернути увагу

1. AI може не мігрувати весь файл, якщо він надто довгий. Ідеальна довжина файлу — від 100 до 200 рядків. Однак, варто спробувати, щоб зрозуміти, що найкраще працює для вас, оскільки результати можуть варіюватися залежно від вмісту та складності коду.

2. Можуть виникнути помилки ліміту при міграції великої кількості довгих файлів одночасно. Щоб уникнути цього, розбийте папку з файлами на дві або більше частин. Ідеально мігрувати по 10–15 файлів за раз, або до 20, залежно від їхнього вмісту. Експериментуйте, щоб знайти оптимальну кількість файлів, які можна мігрувати одночасно.

3. Іноді AI може не мігрувати код так, як очікується. Якщо це трапляється, найкраще видалити згенеровану міграцію для цієї папки та почати процес заново. Забезпечте, щоб ваші інструкції були чіткими та лаконічними — це може покращити точність міграції.

Легкої міграції!

Корисні посилання:
Usage Tears

👍ПодобаєтьсяСподобалось9
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Дякую за статтю і цікаву ідею!
Після прочитання виникло пару питань:
1) наскільки «чистими» були результати конвертації коду при використанні фінального варіанту конвертора? Судячи з рекомендацій в самій статті виглядає так, що в процесі валідації корректності результату знаходилося доволі багато проблем. Якби ви почали процес міграції з нуля, маючи вже готове фінальне рішення, то приблизно за скільки б пройшла міграція (порівняючи з 3 місяцями, які зайняв весь проект з нуля)?
2) в статті вказано, що Cypress проект складався з 4 тисяч файлів. Це у вас в проекті 4000+ ts-файлів? Бачу, що для кожного блока на сторінці (dialog/component/tab/form) створений окремий класс/файл, також є окремі step-класи, напевно, що це є model-класи, які описують об’єкти. Але все одно 4 тисячі файлів виглядає якось аж занадто багато.

Сам скрипт, тобто інструкції відточувались на декількох файлах, після того і почалась міграція, тобто це по суті з нуля, але після такого досвіду, такий ж проект ми мігрували б ще швидше я гадаю, то вже набивається рука)

З 10 прогонів 3 могли б містити деякі невеличкі нюанси, а саме, пропущені методи, якусь команду не так мігрувало і тд. тобто такі нюанси не давали просто скопіювати і вставити одразу, а вимагали вручну вже такі дрібні штуки дописувати чи фіксити

Такі ж інструкції використовувались і на інших наших менших проектах, які я вже мігрував власноруч, без допомоги команди, там було значно менше файлів тому вкладався в 1-2 тижня разом міграція, фікс, відлагодження рану на СІ

4к файлів, так, це TS файли, це компоненти, форми, сторінки, все описано у стилі page object, крім того ще є класи які юзаються для тестових даних, тобто модельки(сутності) також різні enums, костанти і тд
Варто ще зазначити, що у цю кількість було включено спек файли, які також мігрувались за допомогою АІ, а у нас їх чимало(1173 спек файлів і 1683 тестів у них)
Тому сукупність спек файлів і різних класів дає таку кількість( степ класів немає)
Звісно що enums або файли які не містять CY команд, переносились як є, але наприклад у модельках деколи юзались Cypress.env() і тд, правда це замінювалось через IDE, тим не менш всеодно це відноситься до процесу міграції

Cypress или Playwright кто уже с Zaiper юзал? Playwright, как и Cypress, предназначен для тестирования, но имеет больше возможностей для написания сложных сценариев автоматизации. Он подходит для выполнения действий, таких как парсинг данных или взаимодействие с динамическими веб-приложениями.
Возможности интеграции:
Playwright можно использовать для запуска сложных сценариев автоматизации.
После завершения сценария Playwright может отправлять HTTP-запросы или данные в Zapier через Webhooks или API Zapier.
Пример сценария:
Playwright парсит данные с веб-сайта.
Затем данные передаются в Zapier, который автоматически записывает их, например, в Google Sheets или CRM.
Как я понял Cypress и Playwright можно интегрировать с Zapier, но напрямую они не «дружат», интеграция выполняется через Webhooks или API, теоретически в эту связку еще можно добавить GPTs.

Cypress

почему не подошел?Можно узнать?

Ідея гарна, але спосіб досить примітивний — бо пофайловий аналіз без контексту скоріш за все не спрацює на великих проектах через залежності.

По-перше треба ввести фази міграції. Спершу мігрувати кастом команди — щоб openAi їх не вигадував, а брав поточну реалізацію. Те саме стосується хелперів, пейдж обжектів та інших сапорт команд. Бажано вибудувати дерево залежностей, якщо вони імпортують одне одного і мігрувати одне за одним.

По-друге уже після міграції сапорт коду — його передивитись і скомпонувати таким чином, щоб при міграції самих тестів — використовувались ті функції які є в тих файлах.

А ще треба враховувати різні архітектури — бо у Cypress нема концепту pageobject. Також треба звернути увагу на «костилі» cypress і можливо в PW того самого результату можна буде досягти простішим чином.

Це ще одна фаза — пост-обробки

У нас саме великий проєкт, з багатьма залежностями, різного роду файли, задіяний весь спектр АПІ фреймворка і продумана архітектура

І саме така міграція як описана у статті показала себе дуже ефективно

Все дійсно залежить від інструкцій до АІ, тому що кастомні команди сайпреса, потрібно мігранути на звичайні функції, тому можна вказати так: «всі виклики де є cy. — прибрати, залишити тільки назву фукції, також додати імпорт цієї функції у файл з ./helper

Це у нас працювало дуже добре, тобто все впирається у інструкції і вашу фантазію або кмітливість

Про мігрування page objects, тут нема проблем, імпорти також, тому що нова структура на pw повторює ту, шо була на сайпресі

Звісно що є різні проекти і архітектури і від цього потрібно відштовхуватися

Якщо коротко то міграцію можна описати так:
Всі імпорти залишаємо, якщо юзалась кастомна команда, забрати cy. І додати імпорт з хелперу, далі замінити синтаксис cy. на this.page, додати конструктор, розбити чейнінг, додати await перед кожною дією, додати async в методи всі крім тих що повертають Locator, should() замінити на expect() при тому шо потрібно врахувати порядок виклику

Тобто всі ці нюанси, та багато інших були описані у інструкціях і успішно виконувались з файлу у файл

Пост обробка звісно була, як і описано у статті

Через те що у нас правильна архітектура, у нас були «зацепи» можна було за щось зачіпитись і написати логіку для «replace», міграція через АІ це по суті replace через умови
Тому, чим менш структурований і послідовний проект, тим складніше буде мігрувати і потрібно буде крутитись із інструкціями

На початку статті не побачив те, заради чого її відкрив: пояснення «навіщо».

Навіщо мігрувати? Чи використовувати АІ для цього?
Міграція проводилась, тому що сайпрес зараз не підтримується як належить і не впроваджує нові потрібні функціональності і став повністю платним для використання паралелізації
АІ використовували тому що очевидно це швидше ніж міграція вручну, під час ручної міграції визначили повторювальні патерни, відповідно їх описали у інструкції для АІ

Загалом, саме те, дякую. Взагалі, мені ще років з 5 тому було ясно що вони більше орієнтуються на бізнес який спроможний платити за подібні інструменти.

«почніть з міграції основного коду» — це бізнес логіка?

Так, тобто спочатку мігруєте код який юзається в тестах(функції, класи), а потім самі тести, тому що в одному тесті, може бути задіяно багато функціоналу і мігрувати/фіксити тест не вийде поки весь core не мігрований

просто із заголовку я подумав саме про міграцію тестів на інший фреймворк))) але щоб мігрувати логіку до тестів мабуть треба мати добру документацію

Логіка до тестів це і є ваш код в самих тестах, кліки, перевірки, хтось має абстракцію на це, а хтось ні
Якщо говорити про сайпрес, то міграція тестів на PW, це додавання await на кожний рядок, зміна it() на test() цю всю логіку можна прописувати у інструкціях для АІ

Дякую за статтю, актуально.

прикольно) гарний кейс оптимізації рутини

мігби пліз відформатувати код в прикладі? 😇

Підписатись на коментарі