Playwright ve Cucumber ile BDD Test

Mustafa Yldz
8 min readJul 12, 2024

--

Behavior Driven Development (BDD)

BDD,Davranış Odaklı Geliştirme yazılımın davranışlarını tanımlamaya odaklanan bir geliştirme yöntemidir. Bu yöntem, yazılımın nasıl çalışması gerektiğini belirlemek için iş analistleri, geliştiriciler ve kalite güvence ekipleri arasında işbirliğini teşvik eder. BDD’de genellikle Gherkin dili kullanılarak senaryolar yazılır. Senaryolar şu formatta yazılır:

  • Given (Ön Koşul): Yazılımın başlangıç durumu.
  • When (Olay): Kullanıcının gerçekleştirdiği eylem.
  • Then (Sonuç): Beklenen sonuç veya sistemin tepkisi.

TDD ve BDD Arasındaki Farklar

  • Odak Noktası: TDD, kodun test edilebilirliğine odaklanırken, BDD, yazılımın davranışlarını ve iş gereksinimlerini anlamaya odaklanır.
  • Yazım Tarzı: TDD’de testler, genellikle teknik düzeyde yazılırken, BDD’de senaryolar iş diliyle yazılır.

Cucumber, Gherkin dilini kullanarak Behavior Driven Development (BDD) Davranış Odaklı Geliştirme metodolojisini destekleyen bir test otomasyon aracıdır. Bu yöntem, yazılımın davranışlarını iş kullanıcıları tarafından anlaşılabilir bir dilde tanımlamaya odaklanır.

Cucumber ve Gherkin ile BDD

Gherkin, Cucumber tarafından kullanılan özel bir sözdizimi ve dilidir.

  1. Feature Dosyaları Yazma(Scenarios): Gherkin dilini kullanarak, iş analistleri ve ürün sahipleri tarafından anlaşılabilir test senaryoları yazılır. Bu senaryolar, yazılımın belirli bir işlevselliğini veya özelliğini test eder.
  2. Step Definitions (Adım Tanımlamaları): Her Gherkin adımı için karşılık gelen kod yazılır. Bu kod, testlerin yürütülmesi sırasında belirli eylemleri gerçekleştiren fonksiyonları içerir.

Cucumber’ın Faydaları

  • İşbirliği: Gherkin senaryoları, iş analistleri, geliştiriciler ve test mühendisleri arasında daha iyi iletişim ve işbirliği sağlar.
  • Anlaşılabilirlik: Doğal dil kullanımı sayesinde, teknik olmayan paydaşlar bile test senaryolarını anlayabilir.
  • Otomasyon: Test senaryoları, kolayca otomatikleştirilebilir ve sürekli entegrasyon süreçlerine entegre edilebilir.

Cucumber ve Gherkin, BDD metodolojisinin etkin bir şekilde uygulanmasını sağlar ve yazılımın beklenen davranışlarını doğrulamak için güçlü bir araç sunar.

Özet

  • Cucumber: BDD için kullanılan bir test otomasyon aracıdır.
  • Gherkin: Cucumber tarafından kullanılan, iş kurallarını ve test senaryolarını tanımlamak için kullanılan bir dildir.
  • Given, When, Then: Gherkin dilinde kullanılan temel anahtar kelimelerdir ve senaryoların yapılandırılmasını(steps) sağlar.

Cucumber ve Playwright birlikte kullanılarak, BDD (Behavior Driven Development) senaryolarının yazılması ve yürütülmesi sağlanabilir. Bu iki araç birlikte kullanıldığında, Gherkin dilinde yazılan senaryolar, Playwright ile otomatikleştirilmiş testlere dönüştürülür.

Kurulum ;

  1. Aqua IDE ile Playwright Kurulumu
Kurulumun bu adımında yazılım dili seçilmiyor, create dedikten sonra
Create dedikten sonra bu ekran gelicek ve burada dili seçicez, Javascript olarak seçiyoruz

Cucumber resmi olarak Javascript dilini tam destekliyor,bizde bu yüzden tam desteğini sağladığı Javascript dili üzerinde Playwright testlerimizi koşacağız.

Resmi tam destek Javascript ve Node.js

Javascript ve node.js’i Aqua IDE kurulumunu yapacak,bizim yapmamız gereken diğer kurulum ise cucumber

# NPM
npm install --save-dev @cucumber/cucumber

Şimdi ise Proje içindeki oluşturmamız gereken dosya/klasörleri kuruyoruz

Yapımızı bu şekilde kuruyoruz.

saucedemoAddtoChart_steps.js

feature dosyasındaki Given-Then-When anahtar kelimesilerinin otomasyon testi ile eşleştirdiğimiz steps.js dosyası

Bu kodlarda async () => { ... } bir arrow function'dır.

Give,Then,When: Cucumber'da kullanılan adım tanımlama anahtar kelimeleridir.Test senaryolarında adımların nasıl gerçekleştirileceğini belirtir.Cucumber adımını tanımlamak için kullanılan bir arrow function içerir. Arrow function, daha kısa bir sözdizimi sunar ve asenkron işlemleri yönetmek için async/await ile birlikte kullanılır

Her Gherkin adımı için karşılık gelen kod yazılır.Give,Then,When

const { When, Then, Given,} = require('@cucumber/cucumber');
const { chromium } = require('playwright');
const assert = require('assert');
const {selectors} = require('../fixtures/saucedemoSelectors')

let browser;
let page;

Given('I am on the login page', async () => {
browser = await chromium.launch();
const context = await browser.newContext();
page = await context.newPage();
await page.goto(selectors.SaucedemoUrl);
});

When('I login with valid credentials', async () => {

await page.fill(selectors.usernameselector, selectors.username);
await page.fill(selectors.passwordselector, selectors.password);
await page.click(selectors.loginButton);
});

Then('I should see the inventory list', async () => {
const isSuccess = await page.isVisible(selectors.inventorylist);
assert.strictEqual(isSuccess, true, 'Inventory list is not visible');
});

When('I logout', async () => {
await page.click(selectors.logoutmenu);
const isLogoutVisible = await page.isVisible(selectors.logoutlink);
if (isLogoutVisible) {
await page.click(selectors.logoutlink);
} else {
throw new Error('Logout link is not visible');
}
});

When('I add the first item to the cart', async () => {
const addToCartButtonSelector = '.inventory_item:first-of-type .btn_inventory';
await page.click(addToCartButtonSelector);
});

Then('the cart badge should display {string}', async (expectedText) => {
const cartBadgeVisible = await page.isVisible(selectors.cartBadgeSelector);
assert.strictEqual(cartBadgeVisible, true, 'Cart badge is not visible');
const cartBadgeText = await page.textContent(selectors.cartBadgeSelector);
assert.strictEqual(cartBadgeText, expectedText, `Cart badge text is not "${expectedText}"`);
});

Then('I should see the item in the cart', async () => {
await page.click(selectors.cartlink);
const cartItemVisible = await page.isVisible(selectors.cartItemSelector);
assert.strictEqual(cartItemVisible, true, 'No product found in the cart');
});
@saucedemo
@addtochart

Feature: 2-Sepete Ekle

Scenario: 2-Successful login and logout
Given I am on the login page
When I login with valid credentials
Then I should see the inventory list
When I logout

Scenario: 2-Add item to cart and verify
Given I am on the login page
When I login with valid credentials
When I add the first item to the cart
Then the cart badge should display "1"
Then I should see the item in the cart

saucedemoAddtoChart.feature

Gherkin dili ile işlevsel testlerin ve kabul testlerinin yazılması

Senaryonların tanımlı olduğu .feature dosyası

@saucedemo

@addtochart

Bu tag lar sayesinde testlerimizi bu tagları terminalden girerek sadece bu tagları içeren testleri çalıştırabiliyoruz.

npx cucumber-js — tags “@saucedemo

tag ile 5 senaryo ve 21 adım buluyor ve sadece bu testleri çalıştırıyor ve playwrigh’ın hızlı run edişi ile testleri seri bişekilde koşuyoruz.Diğer testleri koşmadan,regresyon testleri veya test bakımı yaptığımızda sadece o testi çalıştırıyoruz

Test Raporu

test-results klasörü altında cucumber-report-html dosyasını sağ click browser da açıyoruz.
Açılan rapor dökümanı detaylı bişekilde bize testler hakkında bilgileri sağlıyor.Testlerin geçme durumu kaç saniye sürdüğü ne zaman yapıldığı.
Detaylı bi şekilde stepleri görebiliyoruz.
tag a göre araya yaparak ta testleri arayabiliriz.

Fail test olduğunda bize gerekli açıklamalarıda sağlıyor.

Bu terminaldeki bilgilendirme
Buda rapor dökümanındaki hata mesajının çıktısı.Neden hata olduğunu bize hangi adımda ve hangi kod içinde olduğunu gösteriyor.

Şimdi testlerimizin cucumber ile entegre halde çalışması için gerekli ayarlarını yapacağız.

playwright.config.js

Normalde default olarak import { defineConfig, devices } from ‘@playwright/test’; olarak geliyor biz bu şekilde değiştiriyoruz.
const { defineConfig, devices } = require('@playwright/test');

/**
* @see https://playwright.dev/docs/test-configuration
*/
module.exports = defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},

{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},

{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},

/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },

/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],


});

cucumber.js

cucumber.js dosyasını biz kuruyoruz
module.exports = {
default: {
tags: process.env.npm_config_TAGS || "",
formatOptions: {
snippetInterface: "async-await"
},
paths: [
"test/features/"
],
//publishQuiet: true,
dryRun: false,
require: [
"test/steps/*.js",
"test/fixtures/*.js",
],
requireModule: [
"ts-node/register"
],
format: [
"progress-bar",
"html:test-results/cucumber-report.html",
"json:test-results/cucumber-report.json",
"rerun:@rerun.txt"
],
parallel: 1
},
rerun: {
formatOptions: {
snippetInterface: "async-await"
},
publishQuiet: true,
dryRun: false,
require: [
"test/steps/*.js",
"test/fixtures/*.js",
],
requireModule: [
"ts-node/register"
],
format: [
"progress-bar",
"html:test-results/cucumber-report.html",
"json:test-results/cucumber-report.json",
"rerun:@rerun.txt"
],
parallel: 2
}
}

Fixture kullanımı

fixture dosyalarının olması gereken yer
const saucedemoSelectors = {
SaucedemoUrl: 'https://www.saucedemo.com',
usernameselector: '#user-name',
username: 'standard_user',
invalidusername: 'invalid_user',
passwordselector: '#password',
password: 'secret_sauce',
invalidpassword: 'invalid_password',
loginButton: '#login-button',
inventorylist: '.inventory_list',
logoutmenu: '.bm-burger-button',
logoutlink: '#logout_sidebar_link',
loginwrapper: "div[class='login_wrapper-inner']",
error_message: '[data-test="error"]',
error_message_text: 'Epic sadface: Username and password do not match any user in this service',
cartBadgeSelector: '.shopping_cart_badge',
cartlink: '.shopping_cart_link',
cartItemSelector: '.cart_item',
inventoryItemName: '.inventory_item_name',
buttonAddCart:".btn_primary",
inventoryItem: '.inventory_item',

};

module.exports = { selectors: saucedemoSelectors };

module.exports yapmaz isek test sayfasında bu nesneleri tanıyor ama hata veriyor bu yüzden kesinlikle module.exports yapıyoruz.

const {selectors} = require('../fixtures/saucedemoSelectors')

Bu şekilde test datalarınıda tek bir noktadan çekebiliyoruz ve testlerimizde kullanıyoruz.Daha sonra element seçicilerde değişiklik olursa bu fixture dan dataları değiştiriyoruz,buda bize testlerin bakımında kolaylık sağlıyor,özellikle aynı element seçici çok fazla testte kullanılıyor veya çok adımda kullanıyor ise sadece fixture nesnesindeki kaynaktan değiştirip tüm testlerimizin datasını güncellemiş oluyoruz.

Bileşenin hiyerarşik ilişkisi ;

  • Gherkin: Gherkin, doğal dilde yazılan ve iş gereksinimlerini, kullanıcı davranışlarını tanımlayan bir dil formatıdır. BDD (Behavior-Driven Development) metodolojisi için kullanılır ve Cucumber gibi araçlar tarafından desteklenir.
  • Cucumber: Cucumber, Gherkin dilinde yazılan senaryoları otomatize eden bir BDD aracıdır. Senaryoları test adımlarına bağlar ve bu adımları gerçekleştirmek için çeşitli test otomasyon araçları (örneğin, Playwright) ile entegre edilir.
  • Playwright: Playwright, tarayıcı tabanlı uygulamaları otomatize etmek için kullanılan güçlü bir test otomasyon aracıdır. Chromium, Firefox ve WebKit tabanlı tarayıcıları destekler ve tarayıcıda kullanıcı etkileşimlerini (sayfa gezintisi, form doldurma, tıklama vb.) otomatize etme yeteneği sağlar.

Umarım bu 3 önemli aracın işlevlerini tamamen kavrayıp testlerinizde gerektiğinde uygularsınız.

--

--