Bu yazımda Puppeteer ve Jest araçlarını kullanarak nasıl E2E (End-to-End) test yazılacağından bahsedeceğim.

Puppeteer, Headless Chrome çözümlerinden biridir. Puppeteer'ı kullanarak Chrome veya Chromium tabanlı herhangi bir tarayıcı kullanarak sağlanan API'lar vasıtasıyla tarayıcıyı kontrol edebilirsiniz. Örneğin DOM'u manipüle etme, sayfa boyutunu değiştirerek tarayıcının verdiği tepkileri ölçme v.b. gibi işlemleri yapabiliriz.

Jest ise Facebook tarafından geliştirilen bir JavaScript test aracıdır. Jest'i kullanarak JavaScript'le yazılmış (Node.JS, Vue, Angular, React v.b.) kodların testlerini yazabiliriz.

Şimdi biz bu iki aracı beraber kullanarak adım adım nasıl arayüz testlerinin yazılabileceğini inceleyeceğiz.

Örnek uygulamayı ASP.NET Core ile yapıp sonrasında bu uygulama üzerinden Puppeteer'ı kullanarak E2E testleri yazacağız.

Öncelikle aşağıdaki komutu kullanarak örnek bir proje oluşturalım.

dotnet new mvc -n AspNetCoreE2ESample

Projemizi oluşturduktan sonra kullanmış olduğumuz IDE veya metin editörüyle projeyi açalım ve Views -> Home -> Index.cshtml dosyasını aşağıdaki şekilde düzenleyelim.

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>

    <form>
        <div class="form-group">
            <label for="exampleInputEmail1">Email address</label>
            <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
            <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
        </div>
        <div class="form-group">
            <label for="exampleInputPassword1">Password</label>
            <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
        </div>
        <div class="form-group form-check">
            <input type="checkbox" class="form-check-input" id="exampleCheck1">
            <label class="form-check-label" for="exampleCheck1">Check me out</label>
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
</div>

Bu düzenlemeyi yaptıktan sonra sayfamızın görüntüsü aşağıdaki gibi olacaktır.

jest-puppeteer-1

Bu düzenlemeye göre yazacak olduğumuz örnek test senaryoları aşağıdaki gibi olacaktır.

  • Sayfa başlığı "Home Page - AspNetCoreE2ESample" olmalı.
  • Sayfadaki E-Mail alanına "[email protected]" yazılabilmeli.
  • Sayfadaki Password alanına "examplePassword" yazılabilmeli.

Şimdi testlerimiz yazmaya başlayabiliriz.

Öncelikle projemizin klasör yapısını aşağıdaki şekilde düzenliyoruz.

jest-puppeteer-2

ASP.NET Core projesine ait kodları src klasörü altına, yazacağımız testlere ait kodları test klasörünün altına yazacağız.

Test yazabilmemiz için gerekli olan bağımlılıkları kurmaya başlayabiliriz. Öncelikle test klasöründeyken terminalimizde npm init komutunu yazarak package.json dosyamızın oluşmasını sağlayalım.

Sonrasında ise aşağıdaki komut ile Jest ve Puppeteer'ı test projemize ekleyelim.

yarn add jest jest-puppeteer puppeteer

Bu komut sayesinde Jest ve Puppeteer'ın paketlerini test projemize ekledik. Sırada Jest'in ayarlarını yapmaya geldi. Bunun için jest.config.js isminde bir dosya oluşturalım ve içeriğini aşağıdaki şekilde düzenleyelim.

module.exports = {
  preset: "jest-puppeteer",
  globals: {
    URL: "https://localhost:5001"
  },
  testMatch: ["**/__test__/**/*.test.js"],
  verbose: true
};

Bu dosyada Jest'in varsayılan ayarlarını düzenliyoruz. Puppeteer'ın çalışırken kullanacağı adresin https://localhost:5001 olduğunu globals'in altında tanımlıyoruz. Ayrıca testMatch ile test klasörünün altında dosya adı .test.js ile biten dosyaların test için kullanılacağı belirttik.

Jest ayarlarını yaptıktan sonra artık testlerimizi yazmaya başlayabiliriz. Öncelikle __test__ isminde bir klasör oluşturalım ve bu oluşturduğumuz klasörün altına index.test.js isminde bir dosya oluşturalım. Dosyanın içeriğini aşağıdaki şekilde düzenleyelim.

const puppeteer = require("puppeteer");
const timeout = 30000;

describe("Test index page", () => {
  let browser;
  let page;

  beforeAll(async () => {
    jest.setTimeout(timeout);
    browser = await puppeteer.launch({
      headless: false,
      args: [`--window-size=1280,720`]
    });
    page = await browser.newPage();
    await page.goto(URL, { waitUntil: "domcontentloaded" });
  }, timeout);

  afterEach(async () => {
    await page.waitFor(1000);
  });

  afterAll(async () => {
    await page.close();
    await browser.close();
  });

  test("Title of the page", async () => {
    const expectedPageTitle = "Home Page - AspNetCoreE2ESample";
    const title = await page.title();
    expect(title).toBe(expectedPageTitle);
  });

  test("Should email address field value is [email protected]", async () => {
    const inputFieldName = "#exampleInputEmail1";
    const expectedValue = "[email protected]";
    await page.click(inputFieldName);
    await page.type(inputFieldName, "[email protected]");

    let inputValue = await page.$eval(inputFieldName, el => el.value);

    expect(inputValue).toBe(expectedValue);
  });

  test("Should password field value is examplePassword", async () => {
    const inputFieldName = "#exampleInputPassword1";
    const expectedValue = "examplePassword";
    await page.click(inputFieldName);
    await page.type(inputFieldName, "examplePassword");

    let inputValue = await page.$eval(inputFieldName, el => el.value);

    expect(inputValue).toBe(expectedValue);
  });
});

Şimdi yazdığımız test kodları inceleyelim.

describe, beforeAll, afterEach, afterAll ve test metotları Jest'e ait metotlardır.

beforeAll metodunda mevcut test başlamadan önce yapılacak olan işlemler tanımlanır ve sadece bir kez çalışır. Burada Puppeteer'ın ayarlarını yapıyoruz.
Puppeteer'ın 1280x720 px boyutlarında tarayıcı penceresi açacağını launch metodunda belirttik. Ayrıca browser.newPage() ile tarayıcıda yeni bir sekme açtık. En sonpage.goto() ile tarayıcıda https://localhost:5001 sayfasını açtık.

afterEach metodunda ise her bir test() metodu çalıştıktan sonra yapılacak olan işlemleri tanımladık. Bizim yazdığımız yapıda ise her test adımı çalıştıktan sonra 1000 milisaniye beklenilmesini sağladık.

afterAll metoduyla birlikte tüm test adımları bittikten sonra yapılacak olan işlemleri tanımladık. page.close() ve browser.close() metodlarını bu metot içerisinde çağırarak öncelikle tarayıcı üzerinde açmış olduğumuz sekmeyi kapatıyoruz. Sonrasından ise Puppeteer'ın açmış olduğu tarayıcıyı kapatıyoruz.

İlk test adımında page.title() ile sayfanın title değerini alıyoruz ve Jest'in except ve toBe metotlarını kullanarak assertion tanımı yapıyoruz.

İkinci test adımında ise sayfada ID değeri exampleInputEmail1 olan input'u bulup ilk önce tıklıyoruz. Sonrasında ise [email protected] değerini ilgili input'a yazıyoruz ve page.$eval() ile input'un değerini okuyoruz. Input'tan gelen değerin beklediğimiz değer olup olmadığının kontrolü except ve toBe metotlarıyla kontrol ediyoruz.

Üçüncü ve son test adımında ise ikinci testte yapmış olduklarımızın aynısını yapıyoruz. İkinci testten farklı olarak exampleInputPassword1 isimli input'ta gerekli işlemleri yapıyoruz.

Test adımlarımızı yazdıktan sonra testimizin doğru çalışıp çalışmadığının kontrolünü yapmaya geldi. Öncelikle package.json dosyamızın scripts bölümünü aşağıdaki şekilde düzenliyoruz.

"scripts": {
  "test": "node node_modules/jest/bin/jest.js"
}

Artık terminalimize aşağıdaki kodu yazarak test adımlarını izleyebiliriz.

yarn test

jest-puppeteer-3

İlgili komutu çalıştırdıktan sonra açılan tarayıcı penceresinde tüm yapılan işlemleri izleyebiliyoruz. Testler tamamlandığında tarayıcı penceresi kapanacak ve aşağıdaki gibi bir sonuçla karşılaşacağız.

jest-puppeteer-4

Çıkan test sonuçlarına göre 3 adet test çalışmış. Tüm testlerin çalışması yaklaşık 5 saniye sürmüş. Tüm testler başarıyla süreci tamamlamıştır.

Jest'e ait assertion metotlarına https://jestjs.io/docs/en/expect adresinden ulaşabilirsiniz.

Örnek uygulamaya https://github.com/mennan/jest-puppeteer-sample adresinden erişebilirsiniz.