vyvchy
    Теми розділу

    07 · Інструменти автоматизації

    BDD-інструменти: CucumberJS і Gherkin — механіка степів

    Зміст

    Фіча-файл виглядає як текст, який може прочитати будь-хто в команді, а падає він як код. Саме на цьому шві й виникають питання, на які не відповідає жоден текст про BDD як підхід: чому крок пішов у зовсім інший метод, ніж ти думав; чому хук піднімає браузер для всіх сценаріїв, хоч лежить у теці однієї фічі; чому «впало десять кроків», хоч насправді впав один. Усе це не про філософію підходу, а про механіку: як інструмент зіставляє рядок із функцією, звідки в цій функції беруться аргументи й де живе стан між кроками.

    Ця глава — канонічний виклад саме механіки степів на сайті: інші глави посилаються сюди. І вона має бейдж поглиблення — при першому проході розділу її можна пропустити й повернутися тоді, коли на проєкті реально зʼявиться Cucumber. Сам підхід — навіщо BDD, розмова трьох амігос, й коли Gherkin виправданий — живе у главі BDD і Gherkin: обіцянки і реальність; тут ми дивимося на нього з боку коду, який усе це виконує.

    Крок Gherkin — це виклик, а не рядок тексту

    Ключове формулювання, з якого варто починати: крок — це аналог виклику методу, а кроки оголошені у файлах *.feature. Тобто фіча-файл не «документація, яку потім хтось автоматизує» — це список викликів, записаний іншим синтаксисом. Сам Gherkin при цьому використовує набір спеціальних ключових слів, які надають структури й значення виконуваним специфікаціям; корисно тримати в голові й розведення понять: Cucumber — інструмент, Gherkin — назва його DSL.

    Звʼязок між рядком і кодом тримає (step definition) — метод плюс вираз, що привʼязує його до одного або кількох кроків Gherkin. Два слова тут несучі:

    • метод — тіло, яке виконається;
    • вираз — те, за чим інструмент знаходить це тіло.

    Зіставляється текст після ключового слова, а не рядок цілком. У кроці Given у кошику 3 товари на зіставлення йде у кошику 3 товари; слово Given у пошуку участі не бере взагалі. Наслідок неочевидний і його варто запамʼятати: конкретне ключове слово не розрізняє дефініції — той самий вираз під Given і під Then дає ту саму дефініцію.

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

    нуль

    дві й більше

    одна

    Старт прогону

    Усі степ-дефініції завантажено

    Крок фічі: текст після ключового слова

    Скільки дефініцій збіглося?

    undefined: крок не реалізовано

    ambiguous: інструмент не вибирає сам

    Зібрати групи захоплення
    привести до типів параметрів

    Викликати метод, World доступний як this

    нуль

    дві й більше

    одна

    Старт прогону

    Усі степ-дефініції завантажено

    Крок фічі: текст після ключового слова

    Скільки дефініцій збіглося?

    undefined: крок не реалізовано

    ambiguous: інструмент не вибирає сам

    Зібрати групи захоплення
    привести до типів параметрів

    Викликати метод, World доступний як this

    Друга половина механіки — як інструмент розуміє, що крок упав. Тут теж є пастка з тих, що коштують годину: падіння визначається винятком, а не поверненим значенням. Повернути false чи null з кроку не означає провалити його — такий крок буде зеленим. І симетрично: крок, який іде після невизначеного (undefined), відкладеного (pending) чи впалого кроку, не виконується взагалі й позначається пропущеним. Тому в одному сценарії «десять червоних кроків» не буває: буває один впалий і девʼять пропущених.

    Feature: Кошик
    
      Scenario: Промокод дає знижку на три товари
        Given у кошику 3 товари
        When користувач застосовує промокод "SUMMER"
        Then у кошику видно знижку 10%
    import { Given } from '@cucumber/cucumber';
    
    // Вираз, а не назва методу, звʼязує цей код із рядком фічі
    Given('у кошику {int} товари', async function (count: number) {
      await seedCart(count);
    });

    Параметризація: типізований аргумент замість розбору рядка

    Одна дефініція обслуговує кілька кроків — і саме звідси починається параметризація. Вираз степ-дефініції буває двох видів: або Cucumber Expression. У регулярному кожна група захоплення передається в метод аргументом. У Cucumber Expression те саме роблять фігурні дужки з іменем типу.

    Головне, що тут плутають: параметр приходить у метод уже приведеним до типу, а не рядком. Якщо вираз групи захоплення збігається з регуляркою зареєстрованого типу параметра, захоплений рядок перетворюється перед передачею в метод: {int} віддає ціле число, бо його вбудований regexp — \d+. Тобто параметризація степів — це типізовані параметри, а не «розпарсити рядок усередині кроку».

    import { Given, When } from '@cucumber/cucumber';
    
    // count тут — число, не рядок: тип задано у виразі
    Given('у кошику {int} товари', async function (count: number) {
      await seedCart(count);
    });
    
    // Той самий метод обслуговує будь-який промокод
    When('користувач застосовує промокод {string}', async function (code: string) {
      await applyPromo(code);
    });

    Це перший із двох рівнів параметризації. Другий живе не в коді, а в самій фічі: Scenario Outline (його синонім — Scenario Template) ганяє той самий сценарій багато разів на різних комбінаціях значень. Розподіл праці простий: Scenario Outline множить дані сценарію, а вираз степу множить рядки, які влучають в один метод.

    фрагментів Given/When/Then між сценаріями — не побічний ефект, а частина задуму BDD із самого початку. Але саме тут ховається межа: чим ширший вираз, тим більше рядків він ловить — включно з тими, яких автор не мав на увазі. Про це — у розділі про степи-спагеті нижче.

    World і хуки: де живе стан сценарію

    World

    Питання «як передати дані між кроками» має штатну відповідь, і це World — ізольований на кожен сценарій, доступний крокам і більшості хуків як this. Змінну, покладену одним кроком, читає наступний; усе покладене таким чином відкидається з кінцем сценарію.

    Три властивості, які роблять цей механізм передбачуваним:

    • Новий екземпляр на кожен сценарій — і (retry) не виняток: він не успадковує стан попередньої спроби, тож «на другій спробі позеленіло, бо щось лишилося» — не про World.
    • World недоступний у глобальних хуках BeforeAll і AfterAll, бо кожен із них виконується поза будь-яким сценарієм. Глобальну підготовку доводиться тримати окремо від контексту сценарію — і це не деталь стилю, а те, що визначає архітектуру звʼязки з браузером (наступний розділ).
    • this конфліктує зі через інший скоуп. Сучасний вихід — імпортований обʼєкт world замість this; тому в кроках, які лізуть у стан, стрілочні функції не використовують без розуміння наслідків.
    import { Given, Then, setWorldConstructor, World, IWorldOptions } from '@cucumber/cucumber';
    
    class ShopWorld extends World {
      cartSize = 0;
      constructor(options: IWorldOptions) {
        super(options);
      }
    }
    setWorldConstructor(ShopWorld);
    
    Given('у кошику {int} товари', function (this: ShopWorld, count: number) {
      this.cartSize = count; // покладено тут
    });
    
    Then('у кошику лишається {int} товари', function (this: ShopWorld, count: number) {
      if (this.cartSize !== count) throw new Error(`очікували ${count}, маємо ${this.cartSize}`);
    });

    Хуки

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

    І тут головна пастка структурування: місце оголошення хука нічого не звужує. Файл із хуком, покладений поруч з однією фічею, не робить хук «локальним» — він однаково виконається для всіх сценаріїв прогону. Вибірковість дають лише умовні хуки (за тегами). У JS-проєкті хуки оголошують у features/support/env.js або будь-якому іншому файлі під каталогом features/support.

    СценарійПрогінСценарійПрогінBeforeAll — World недоступнийстарт сценаріюновий екземпляр WorldBefore — готуємо стан у thisкроки читають і пишуть thisAfter — прибираємоWorld відкинутоAfterAll — World недоступнийСценарійПрогінСценарійПрогінBeforeAll — World недоступнийстарт сценаріюновий екземпляр WorldBefore — готуємо стан у thisкроки читають і пишуть thisAfter — прибираємоWorld відкинутоAfterAll — World недоступний

    CucumberJS плюс Playwright: хто тут ранер

    Перше, що треба вирішити на цій звʼязці, — хто керує прогоном. (test runner) тут Cucumber: він завантажує дефініції, зіставляє кроки, викликає методи, веде хуки й статуси. Отже, Playwright у цій схемі працює не своїм ранером, а бібліотекою, і всю ієрархію доводиться будувати руками: обрати тип браузера → запустити браузер → створити контекст → створити сторінку. Дзеркально виглядає й прибирання: закриття контексту й браузера — обовʼязок твого коду. Порівняй із власним ранером Playwright, де page і context приходять як вбудовані , створюються ліниво (лише якщо тест назвав їх в аргументах) і закриваються самі — про це Playwright: фікстури, хуки і конфігурація, а про саму ієрархію — Playwright: архітектура, браузери і контексти.

    Далі два факти з доки складаються в готову архітектуру. Браузер — дорогий, тож його логічно піднімати раз на прогін, у BeforeAll. Але World у BeforeAll недоступний, тож браузер живе поза World — у модульній змінній файлу підтримки. А контекст і сторінка навпаки: кожен тест (тут — сценарій) має дістати свіжий контекст, еквівалентний новому профілю браузера, з ізоляцією майже без накладних витрат. Ізоляція названа причиною відтворюваності й захисту від каскадних падінь — а World, який і так новий на кожен сценарій, для неї ідеальний дім.

    // features/support/hooks.ts
    import { BeforeAll, Before, After, AfterAll } from '@cucumber/cucumber';
    import { chromium, Browser } from 'playwright';
    import { ShopWorld } from './world'; // у класі World оголошено поля context і page
    
    let browser: Browser; // поза World: BeforeAll його не бачить
    
    BeforeAll(async () => {
      browser = await chromium.launch();
    });
    
    Before(async function (this: ShopWorld) {
      this.context = await browser.newContext(); // свіжий профіль на сценарій
      this.page = await this.context.newPage();
    });
    
    After(async function (this: ShopWorld) {
      await this.context.close(); // у бібліотеці прибирає твій код
    });
    
    AfterAll(async () => {
      await browser.close();
    });

    Що змінюється у звичках разом із ранером. Модель у бібліотеки інша: там 30 секунд на більшість операцій, тоді як у ранера Playwright більшість операцій власного таймауту не мають, зате кожен тест має свій, який його валить. Тобто звичка «мене підстрахує таймаут тесту» тут не працює автоматично — межі прогону задає Cucumber, а не Playwright. Практичний наслідок: у кроках варто спиратися на очікування самої бібліотеки, а не на власні паузи, і памʼятати, що крок валить саме виняток:

    import { Then } from '@cucumber/cucumber';
    
    Then('користувач бачить повідомлення {string}', async function (this: ShopWorld, text: string) {
      await this.page.getByText(text).waitFor(); // таймаут кине виняток — крок стане failed
    });

    Дві ролі в одному сценарії теж робляться контекстами: два контексти з різними станами замість двох браузерів. Якщо кроки виглядають як «зайшов адміном, потім користувачем», у World має бути два контексти, а не один із перелогіном.

    Структура фіч-файлів у репо

    Правила Gherkin задають кістяк, який ніяк не обійти:

    • Кожен непорожній рядок має починатися з ключового слова. Вільного тексту між кроками не буває.
    • Перше первинне (primary) ключове слово документа — завжди Feature, і Feature у файлі може бути лише одна. Тобто «файл на модуль» неможливий за побудовою: файл — це одна фіча.
    • Rule — необовʼязкове ключове слово з версії 6, і воно представляє одне бізнес-правило. Це готовий рівень групування між фічею і сценаріями.
    • Background існує проти повторення однакових Given у всіх сценаріях фічі.

    Тепер найважливіше про репозиторій — і найменш очевидне. Оскільки всі степ-дефініції завантажуються до старту виконання фічі, простір імен виразів фактично спільний на весь прогін. Тека не є скоупом: дефініція, покладена в features/checkout/, так само доступна фічі профілю, а вираз, який випадково збігся, зіштовхне два файли, що ніколи не мали зустрітися. Те саме з хуками: місце оголошення нічого не звужує. Каталог, який дока задає прямо, лише один — features/support для хуків і файлів підтримки.

    Звідси робоча розкладка виглядає так:

    РівеньЩо тут лежитьЧим тримається
    features/**/*.featureодна фіча = один файл, Rule — групування правил, Background — спільні передумовиправилами самого Gherkin
    каталог степівдефініції, згруповані за доменом (кошик, оплата, профіль)домовленістю команди, не інструментом
    features/supportхуки, World, конфігурація підтримкипрямою вказівкою доки

    Практичне правило рев'ю: якщо дефініції розкладені за теками «щоб не конфліктували» — це самообман. Конфлікт лікується унікальністю виразу, а не місцем файлу.

    Степи-спагеті: як вони виглядають у коді

    «Степи-спагеті» — не оцінка стилю, а конкретні механізми, які дають конкретні симптоми. Їх варто знати поіменно, бо на рев'ю вони виглядають по-різному.

    Неоднозначність. Дефініції мусять бути унікальні, щоб інструмент знав, що виконувати. На два збіги він не вибирає сам і не бере «першу підхожу» — він повідомляє окремий статус ambiguous. Це машинна межа проти надто широких виразів: чим більше у виразі загальних слів («користувач бачить», «сторінка відкрита»), тим швидше він зіткнеться з чужим.

    Ключове слово, яке нічого не гарантує. Оскільки Given/When/Then у пошуку не беруть участі, ніщо не забороняє тому самому методу виконуватися і як , і як перевірка. Звідси класика «Then, який щось робить», і сценарії, де перевірка тихо змінює стан системи.

    Стан, який зʼїв незалежність. World робить передачу стану легальною — і тому легко зловживаною. Практичний критерій для рев'ю: якщо крок читається лише разом із попереднім, стан їде через World, і сценарій перестає бути незалежним описом поведінки.

    Імперативність. Терміни офіційні: (declarative scenario) описує намір, (imperative scenario) — кроки інтерфейсу. Різниця сформульована як «what, not how»: сценарій описує задуману поведінку, а не реалізацію. Декларативні сценарії легше підтримувати й вони менш крихкі, і вигода дуже конкретна — при зміні реалізації правиться код кроків, а не сценарій, бо конкретні значення живуть у визначеннях. При цьому догми «декларативно завжди» дока не встановлює: імперативний стиль поданий без осуду, «in some contexts this style of test is appropriate».

    Перевірка не того боку. Результат у Then має бути спостережуваним виходом — звітом, інтерфейсом, повідомленням, а не поведінкою, глибоко захованою в системі, як-от запис у БД. Дока каже це прямо, з наказовою інтонацією: спокусі перевіряти в Then базу — опиратися. Формально це рівень настанови (should), а не заборони, але сказано прямо, а не між рядків.

    І межа, яку варто визнавати вголос: реалізація й підтримка кроків природною мовою — складна задача сама по собі, а надто складні кроки роблять дебаг важким і дорогим. Це формулювання ISTQB CTAL-TAE §3.1.4, і воно ж — коректна відповідь на «чому ваша BDD-сюїта така дорога». Там же названо й головну пастку підходу: команди зводять BDD до «тестів природною мовою», не залучаючи бізнес і розробників.

    Типові помилки

    • Виглядає як «крок не знайшов дефініцію через ключове слово», а насправді ключове слово в пошуку не бере участі. Той самий текст під Given і під Then — та сама дефініція, і жодного «пошуку серед Given-ів» не існує.
    • Виглядає як «інструмент узяв першу підхожу дефініцію», а насправді він не вибирає. Два збіги — це статус ambiguous, а не тихий вибір. Якщо ви впевнені, що «спрацював не той степ», — швидше за все вираз ширший, ніж здається.
    • Виглядає як «хук локальний для цієї фічі», а насправді місце оголошення нічого не звужує. Хук сценарію виконується для кожного сценарію прогону; звузити його можна лише умовними хуками за тегами.
    • Виглядає як «упало десять кроків», а насправді впав один. Кроки після впалого, невизначеного чи відкладеного не виконуються взагалі й позначаються пропущеними — читати треба перший червоний, а не останній.
    • Виглядає як «крок повернув false, отже провалився», а насправді falsy-значення кроку не валить. Провал — це виняток; перевірка без дає зелений крок при будь-якому результаті.
    • Виглядає як «стан протік між сценаріями», а насправді протекло те, що лежить поза World. Кожен сценарій дістає новий екземпляр World навіть на ретраї; тече модульна змінна, спільний браузер або дані в системі.
    • Виглядає як «Then перевіряє результат», а насправді він перевіряє запис у БД. Правило Gherkin приписує спостережуваний вихід, а проти зазирання в базу дока застерігає прямо й наказово — «опирайтеся спокусі», а не «на ваш розсуд».
    • Виглядає як «детальний сценарій точніший», а насправді він імперативний. Кроки на кожен клік означають, що при зміні UI правиться фіча-файл — той самий артефакт, який мав бути стабільним описом поведінки.

    Підсумок

    • Степ-дефініція — це метод плюс вираз; зіставляється лише текст після ключового слова, а самі Given/When/Then на пошук не впливають.
    • Усі дефініції завантажуються до старту прогону, тому простір імен виразів спільний, а тека скоупом не є: конфлікт лікує унікальність виразу, а не структура репозиторію.
    • Параметр приходить у крок типізованим ({int} — це число), тож параметризація степів — про типи параметрів, а не про розбір рядків усередині методу.
    • World — ізольований скоуп сценарію: новий екземпляр на кожен сценарій навіть при ретраї, відкидається в кінці й недоступний у BeforeAll/AfterAll; звідси й розкладка «браузер поза World, контекст і сторінка — у World».
    • Крок валить виняток, а не повернуте значення; кроки після впалого пропускаються — тому перший червоний у звіті і є діагнозом.

    Можливі питання

    • «Як рядок у фіча-файлі знаходить свій код?» Сильна відповідь: вираз степ-дефініції зіставляється з текстом після ключового слова; усі дефініції завантажені до старту; групи захоплення збираються, приводяться до типів параметрів і передаються в метод. Інтервʼюер слухає, чи звучить «ключове слово в зіставленні не бере участі».
    • «Як передати дані між кроками?» Очікують World і його межі: новий екземпляр на сценарій (включно з ретраєм), стан відкидається в кінці, у глобальних хуках його немає. Відповідь «глобальна змінна» одразу показує, що людина не бачила паралельного прогону.
    • «Два кроки з однаковим текстом — що станеться?» Правильно: ambiguous, інструмент не вибирає сам. Слабка відповідь — «спрацює перший знайдений».
    • «Чим Before відрізняється від BeforeAll Перевіряють розуміння скоупу: Before — перед першим кроком кожного сценарію й з доступом до World; BeforeAll — поза сценарієм і без World. Бонус — сказати, що місце оголошення хука нічого не звужує, а звужують теги.
    • «Ви ганяєте Cucumber із Playwright — хто з них ранер?» Cucumber; Playwright тут бібліотека, тож browser → context → page будуєш і закриваєш сам. Хороший кандидат додає, що контекст логічно тримати в World, а браузер — поза ним.
    • «Чому BDD-сюїти часто дорогі в підтримці?» Тут очікують не скарг, а механізмів: надто широкі вирази, кроки, що читаються лише разом, імперативні сценарії, перевірки в Then не того боку системи. Формулювання ISTQB — складність реалізації й підтримки кроків природною мовою плюс дорогий дебаг складних кроків — звучить як відповідь інженера, а не як враження.

    Джерела

    Крок Gherkin — це виклик, а не рядок тексту

    • Cucumber — Step definitions — означення степ-дефініції як методу з виразом і те, що зіставляється лише текст після ключового слова.
    • Cucumber — Cucumber reference — крок як аналог виклику методу, завантаження всіх дефініцій до старту фічі, три кроки зіставлення, байдужість до ключового слова, виняток проти falsy-значення і пропущені кроки після впалого.
    • Cucumber — Gherkin Reference — Gherkin як набір ключових слів, що надає структури виконуваним специфікаціям.
    • Martin Fowler — GivenWhenThen — розведення інструмента й мови: Cucumber — інструмент, Gherkin — назва його DSL.
    • CucumberJS — World — World, доступний крокам як this, тобто те, з чим викликається знайдений метод.

    Параметризація: типізований аргумент замість розбору рядка

    • Cucumber — Step definitions — одна дефініція на кілька кроків, два види виразів, групи захоплення як аргументи й приведення захопленого рядка до зареєстрованого типу параметра ({int} → ціле число).
    • Cucumber — Gherkin ReferenceScenario Outline як прогін того самого сценарію на різних комбінаціях значень і синонім Scenario Template.
    • Dan North — Introducing BDD — перевикористання фрагментів Given/When/Then між сценаріями закладене в задум підходу.

    World і хуки: де живе стан сценарію

    • CucumberJS — World — World як ізольований скоуп сценарію й this кроків, новий екземпляр на кожен сценарій включно з ретраєм, відкидання стану з кінцем сценарію, недоступність у BeforeAll/AfterAll і конфлікт зі стрілочними функціями.
    • Cucumber — Cucumber reference — означення хуків, «хук сценарію виконується для кожного сценарію», незалежність від місця оголошення, умовні хуки як єдиний спосіб звузити дію і каталог features/support як їхній дім.
    • Cucumber — Step definitions — крок як метод, у який приходить типізований аргумент і World.

    CucumberJS плюс Playwright: хто тут ранер

    • Playwright — Library — ієрархія browser → context → page, яку в бібліотеці створюють вручну й по черзі; закриття контексту й браузера як обовʼязок коду; ліниві вбудовані фікстури ранера як протилежність; 30 секунд на більшість операцій у бібліотеці проти таймауту на тест у ранера.
    • Playwright — головна сторінка — свіжий контекст на кожен тест, рівносильний новому профілю браузера, з ізоляцією майже без накладних витрат.
    • Playwright — Authentication — ізоляція контекстів як причина відтворюваності й захисту від каскадних падінь; дві ролі — два контексти з різними станами.
    • Playwright — Test Isolation (browser contexts) — контекст як механізм ізоляції й багатокористувацьких сценаріїв.
    • Playwright — Timeouts — рівні таймаутів власного ранера (таймаут тесту, окремий таймаут асерту), на тлі яких і видно, що межі прогону тут задає Cucumber.
    • CucumberJS — World — недоступність World у BeforeAll/AfterAll і новий екземпляр на кожен сценарій як підстава розкладки «браузер поза World, контекст у World».
    • Cucumber — Cucumber reference — хуки як точки підготовки й прибирання середовища навколо кожного сценарію; виняток як єдиний спосіб провалити крок.

    Структура фіч-файлів у репо

    • Cucumber — Gherkin Reference — вимога починати кожен непорожній рядок ключовим словом, Feature як перше ключове слово й одна Feature на файл, Rule з версії 6 як одне бізнес-правило, Background проти повторюваних Given.
    • Cucumber — Cucumber reference — завантаження всіх дефініцій до старту фічі, незалежність хука від місця оголошення, каталог features/support як дім хуків, вимога унікальності дефініцій.
    • Cucumber — Step definitions — вираз як єдиний ключ пошуку дефініції.

    Степи-спагеті: як вони виглядають у коді

    • Cucumber — Cucumber reference — вимога унікальності дефініцій і окремий статус ambiguous замість вибору навмання; байдужість пошуку до ключового слова.
    • Cucumber — Step definitions — вираз як єдиний ключ пошуку, через який і стикаються надто широкі степи.
    • CucumberJS — World — передача стану між кроками як штатний механізм, з якого й ростуть залежні кроки.
    • Cucumber Docs — Writing better Gherkin — офіційні терміни imperative / declarative, формула «what, not how», менша крихкість декларативних сценаріїв і застереження, що імперативний стиль інколи доречний.
    • Cucumber — Gherkin Reference — настанова перевіряти в Then лише спостережуваний вихід і пряме застереження не зазирати в базу.
    • ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §3.1.4: складність реалізації й підтримки кроків природною мовою, дорогий дебаг складних кроків і пастка «BDD як спосіб писати тести природною мовою».

    Типові помилки

    • Cucumber — Cucumber reference — байдужість пошуку до ключового слова, статус ambiguous, пропущені кроки після впалого, виняток проти falsy-значення, незалежність хука від місця оголошення й умовні хуки.
    • CucumberJS — World — новий екземпляр World на кожен сценарій включно з ретраєм і відкидання стану в кінці — тобто межа того, що World узагалі може «протекти».
    • Cucumber — Gherkin Reference — правило про спостережуваний вихід у Then і пряма настанова не перевіряти базу.
    • Cucumber Docs — Writing better Gherkin — чому імперативний сценарій крихкий: конкретика має жити у визначеннях кроків.
    • Cucumber — Step definitions — вираз як єдиний ключ пошуку й типізований аргумент замість розбору рядка.

    Можливі питання

    • Cucumber — Step definitions — механіка зіставлення й типізованих параметрів, яку й перевіряє перше питання.
    • Cucumber — Cucumber reference — порядок завантаження й зіставлення, статус ambiguous, семантика хуків і результатів кроку.
    • CucumberJS — World — World як штатна відповідь на «як передати дані між кроками» і його межі в глобальних хуках.
    • Playwright — Library — розкладка обовʼязків між бібліотекою й ранером, з якої випливає відповідь про звʼязку з Cucumber.
    • Cucumber Docs — Writing better Gherkin — declarative проти imperative як мова відповіді про дорогу підтримку.
    • ISTQB® Certified Tester Advanced Level Test Automation Engineering (CTAL-TAE) v2.0 — §3.1.4: названі поіменно вигоди й обмеження BDD, включно з ціною підтримки кроків.

    Пояснення

    «Поясни» працює з власним API-ключем Anthropic: запит іде з вашого браузера прямо до Anthropic.

    Свій API-ключ (BYOK)

    Вставте власний ключ Anthropic — пояснення працюватиме на реальній моделі. Ключ зберігається лише у вашому браузері (localStorage), нікуди не надсилається, крім api.anthropic.com, і не логується.