Tüm yazılar
test-automation

TestFly Part 12: Selenium'da Playwright Tarzı Assertion'lar — not(), ARIA Snapshot ve Strict Mode

TestFly 1.1.0, Playwright for Java'nın assertion ergonomisini Selenium'a taşıyor: zincirlenebilir not() negasyonu, deterministik hasRole()/hasAccessibleName() kontrolleri, YAML tabanlı matchesAriaSnapshot() ve sessizce yanlış elemente tıklamak yerine yüksek sesle hata veren opsiyonel strict mode.

12 Ekim 20265 dk okuma
TestFly Part 12: Selenium'da Playwright Tarzı Assertion'lar — not(), ARIA Snapshot ve Strict Mode

Özet: TestFly 1.1.0, Selenium'dan ayrılmadan Playwright for Java'nın assertion API'sine olan farkı kapatıyor: LocatorAssert.not() zincirdeki bir sonraki kontrolü negatife çeviriyor, hasRole() / hasAccessibleName() / hasAccessibleDescription() DOM attribute'larından tahmin etmek yerine gerçek erişilebilirlik ağacını okuyor, matchesAriaSnapshot() bir alt ağacı Playwright tarzı bir YAML şablonuyla karşılaştırıyor ve opsiyonel locators.strict, belirsiz bir locator'ı sessizce yanlış elemente tıklamak yerine yüksek sesle hataya çeviriyor.


Selenium Assertion'ları Neden not() Metoduna İhtiyaç Duyuyor?

Klasik Selenium/TestNG kodunda negatif assertion'lar genelde iki kötü seçenekten birine dönüşür: pozitif assertion'ı try/catch içine alıp sonucu ters çevirmek, ya da bir koşulun yanlış kalmasını bekleyen ayrı bir polling döngüsü yazmak. İkisi de testin asıl niyetini boilerplate'in içine gömer.

TestFly'ın LocatorAssert'i artık Playwright for Java'daki aynı not()'a sahip — zincirde yalnızca kendisinden hemen sonra gelen assertion'ı negatife çeviriyor:

java
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;

import static io.testfly.assertion.Assertions.assertThat;

public class CheckoutErrorTest extends BaseTest {

    @Test
    public void testErrorBannerClearsAfterRetry() {
        open("/checkout");
        find("#pay-btn").click();

        assertThat(find("#error-banner")).hasText("Payment declined");

        find("#retry-btn").click();

        // Yalnızca not()'tan hemen sonraki assertion negatife döner
        assertThat(find("#error-banner")).not().isVisible();
        assertThat(find("#spinner")).not().isAttached();
    }
}

Playwright'ta olduğu gibi, negatife çevrilmiş assertion'ların çoğu eşleşen bir eleman hiç olmadığında da geçer — not().isVisible(), banner gizli olsa da DOM'dan tamamen kaldırılmış olsa da sağlanır. Eğer test elementin var olmasını ama farklı bir durumda olmasını istiyorsa, önce varlığı doğrula: assertThat(status).isVisible().not().hasText("Error"). not(), doğrulanmış click(), fill() veya clear() aksiyonlarıyla birlikte kullanılamaz.

Deterministik Erişilebilirlik Assertion'ları Nedir?

TestFly zaten hasAriaLabel tarzı attribute kontrolleri sunuyordu. 1.1.0, bir ekran okuyucunun göreceği şekilde hesaplanmış erişilebilirlik ağacını okuyan assertion'lar ekliyor; tek bir gömülü probe script üzerinden — axe-core enjeksiyonu yok, LLM çağrısı yok:

java
@Test
public void testSubmitButtonIsAccessible() {
    open("/signup");

    assertThat(find("#submit"))
        .hasRole(Role.BUTTON)
        .hasAccessibleName("Create account");

    assertThat(find("#email"))
        .hasAccessibleDescription(Pattern.compile("(?i)required"));
}

hasRole(Role | String), açık role attribute'unu ya da HTML etiketinin örtük rolünü kontrol eder. hasAccessibleName ve hasAccessibleDescription, ya tam bir String (boşluklar sadeleştirilmiş, Locator.withName(...)'ın kullandığı eşleşmeyle aynı) ya da kısmi/büyük-küçük harf duyarsız eşleşme için bir Pattern kabul eder. Yalnızca 36 standart ARIA Role değeri ve görünür metin raporlanır; dekoratif görseller ve gizli içerik atlanır, Shadow DOM'a girilmez.

ARIA Snapshot'lar Nasıl Çalışır?

matchesAriaSnapshot(), TestFly'ın Playwright'ın toMatchAriaSnapshot()'ına cevabı: bir locator'ın altındaki erişilebilirlik alt ağacını yakalar ve bunu bir YAML şablonuyla karşılaştırır — tam bir serileştirme diff'i değil, kısmi ve sıralı bir kısıttır.

java
@Test
public void testNavigationLandmarkStructure() {
    open("/dashboard");

    assertThat(By.tagName("nav")).matchesAriaSnapshot("""
        - link "Home"
        - link "Docs"
        - button "Account" [expanded=false]
        """);
}

Playwright tarzı eşleşme kuralları:

KuralDavranış
Roltam olarak eşleşmeli
Tırnaklı isimbüyük/küçük harf duyarsız alt dize eşleşmesi
/regex/ isimfind() ile eşleştirilir
[attribute] / [level=2]şablondaki her attribute sayfada bulunmalı; sayfadaki fazla attribute'lar yok sayılır

Bozuk bir şablon, timeout'u beklemeden hemen IllegalArgumentException ile hata verir. Başarısızlık durumunda assertion hatası hem şablonu hem de yakalanan snapshot'ı içerir, böylece hiçbir şeyi yeniden çalıştırmadan fark görülebilir. Baştan bir şablon yazmak için, TestFly'ın o an ne gördüğünü yazdır:

java
System.out.println(find("nav").ariaSnapshot());
// ya da tüm sayfa için:
System.out.println(ariaSnapshot());

ve yazdırılan YAML'ı, yalnızca önemli düğümlere indirgeyerek teste yapıştır.

Strict Mode Sessiz Çoklu-Eleman Hatalarını Nasıl Önler?

Varsayılan olarak, bir locator birden fazla görünür elemente eşleştiğinde, TestFly — klasik Selenium gibi — sessizce ilkini tıklar ya da okur. Yeniden adlandırılmış bir CSS sınıfının ya da A/B testi yapılan bir duplicate banner'ın, kimse fark etmeden haftalarca yanlış elemente karşı geçen bir teste dönüşmesinin tam sebebi budur.

Proje başına açılır:

yaml
# testfly.yml
locators:
  strict: true

locators.strict: true ile, birden fazla görünür elemente eşleşen ve first(), nth() veya last() ile daraltılmamış bir locator üzerindeki aksiyon artık hemen hata fırlatır:

text
Strict mode violation: css=".card .btn-buy" resolved to 3 visible elements;
use first()/nth()/last() or narrow the locator. Candidates: <button.btn-buy#card-1>, <button.btn-buy#card-2>, <button.btn-buy#card-3>

isVisible() ve isEnabled(), ilk eşleşmeyi sessizce kontrol etmek yerine aynı ihlali yüzeye çıkarır; count(), elements() ve assertThat(...) (sayma/numaralandırma için) etkilenmez, çünkü belirsizlik orada beklenen durumdur. Strict mode bir ihlali işaretlediğinde locator'ı açıkça daralt:

java
find(".card .btn-buy").nth(1).click();          // ikinci kart, açıkça belirtilmiş
find(".card").filter(withText("Pro Plan"))
             .find(".btn-buy").click();          // içeriğe göre daraltılmış

Gizli duplicate'ler — masaüstü navigasyonun yanında duran kapalı bir mobil nav, gizli bir modal klonu — kontrol çalışmadan önce filtrelenir, böylece responsive layout'lar yanlış strict-mode ihlallerine yol açmaz.

SSS

not(), mevcut Selenium assertion metodlarının yerini mi alıyor?

Hayır. not(), LocatorAssert üzerinde bir değiştiricidir — aynı zincirde kendisinden hemen sonra gelen assertion'ı negatife çevirir. Mevcut tüm pozitif assertion'lar değişmeden kalır.

Erişilebilirlik assertion'ları axe-core ya da harici bir kütüphane gerektiriyor mu?

Hayır. hasRole, hasAccessibleName, hasAccessibleDescription ve matchesAriaSnapshot, tarayıcının hesaplanmış erişilebilirlik ağacını doğrudan okuyan tek bir gömülü probe script kullanır — axe-core enjeksiyonu ve LLM çağrısı yoktur.

locators.strict'i açmak mevcut testleri bozar mı?

Bozabilir, bu tasarım gereği — asıl amaç da bu. Daha önce sessizce birden fazla görünür elemente eşleşen her locator artık açıkça hata verir. Çözüm, Playwright'ın da önerdiği aynı çözüm: locator'ı first(), nth(), last() ya da daha spesifik bir seçiciyle daraltmak.

Strict mode, count() veya elements()'i etkiler mi?

Hayır. Bu metodlar özellikle birden fazla eşleşmeyle çalışmak için var, bu yüzden strict mode onlara uygulanmaz — yalnızca aksiyonlara (click, fill, …) ve boolean kontrollere (isVisible()/isEnabled()) uygulanır.

#TestFly#Selenium#Playwright#Accessibility#ARIA#Java#SDET
Paylaş X LinkedIn

Yorumlar

  • Henüz yorum yok. İlk yorumu sen yaz.