Merhabalar.

Bir önceki yazımda Puppeteer ve Jest'in kurulumu ve testlerin nasıl yazılacağından bahsetmiştim. Bu yazımda ise birçok test aracında da bulunan Setup ve Teardown yapılarının Puppeteer'da nasıl yapılabileceğinden bahsedeceğim.

Öncelikle Setup, Teardown ve Test Environment kavramlarından bahsedelim.

Setup, tüm testler yazılmadan önce yapılması gereken işlerin yapıldığı bölümdür. Setup test işlemi ilk başladığı zaman sadece 1 kere çalışır. Örneğin veritabanının oluşturulması, mock verilerin oluşturulması, login işlemi sonucu oluşan cookie veya tokenların saklanması v.b. işlemler bu bölümde yapılır.

Teardown, tüm test işlemleri tamamlandıkrtan sonra çalışan bölümdür. Örneğin setup aşamasında veritabanı oluşturulmuşsa oluşan bu veritabanının silinme işlemi veya login olunan bir sistemden logout olunma işlemleri teardown bölümünde gerçekleştirilir.

Test Environment ise Puppeteer ayarlarını yapacağımız bölümdür. Puppeteer'ın ihtiyacı olan ayarları bu bölümde yapabiliriz.

Kavramları açıkladıktan sonra örneğimize geçebiliriz.

Öncelikle aşağıdaki komutla klasörlerimizi ve dosyalarımı oluşturulalım.

$ mkdir puppeteer-setup-teardown-sample
$ cd puppeteer-setup-teardown-sample
$ mkdir __tests__
$ touch setup.js teardown.js puppeteer_environment.js jest.config.js
$ touch __tests__/index.js

Bu komutları yazdıktan sonra aşağıdaki ekran görüntüsüne benzer bir proje ağacına sahip olacağız.

jest-puppeteer-1-2

Şimdi ise npm init komutu ile package.json dosyamızı oluşturalım ve aşağıdaki komutları yazarak ihtiyacımız olan paketleri projemize ekleyelim.

$ yarn add jest puppeteer rimraf

Paketleri ekledikten sonra sıra dosyalarımızın içeriğini yazmaya geldi. jest.config.js dosyasının içeriğini aşağıdaki şekilde düzenleyelim.

module.exports = {
  globalSetup: './setup.js',
  globalTeardown: './teardown.js',
  testEnvironment: './puppeteer_environment.js'
}

globalSetup, globalTeardown ve testEnvironment alanlarında hangi dosyaların setup, teardown ve test environment için kullanıcılacağını belirttik.

Şimdi ise puppeteer_environment.js dosyasının içeriğini düzenleyelim. Bu dosyada Puppeteer'ın ihtiyaç duyacağı fonksiyonları ve ortam değişkenlerini (environment variables) tanımlıyoruz.

const NodeEnvironment = require('jest-environment-node')
const puppeteer = require('puppeteer')
const fs = require('fs')
const os = require('os')
const path = require('path')

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup')

class PuppeteerEnvironment extends NodeEnvironment {
  constructor(config) {
    super(config)
  }

  async setup() {
    console.log('Setup Test Environment.')
    await super.setup()
    const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8')
    if (!wsEndpoint) {
      throw new Error('wsEndpoint not found')
    }
    this.global.__BROWSER__ = await puppeteer.connect({
      browserWSEndpoint: wsEndpoint,
    })
  }

  async teardown() {
    console.log('Teardown Test Environment.')
    await super.teardown()
  }

  runScript(script) {
    return super.runScript(script)
  }
}

module.exports = PuppeteerEnvironment

Sırada ise setup.js dosyamızın içeriğini düzenlemek var. Bu dosya tüm testler çalışmadan önce yapılması gereken işlerin yapılacağı dosyadır.

const puppeteer = require('puppeteer')
const fs = require('fs')
const mkdirp = require('mkdirp')
const os = require('os')
const path = require('path')

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup')

module.exports = async function() {
  console.log('Setup Puppeteer')
  const browser = await puppeteer.launch({ headless: false, slowMo: 500, waitUntil: 'networkidle' })
  
  global.__BROWSER__ = browser
  
  mkdirp.sync(DIR)
  fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint())
}

Bu dosyada Puppeteer'ın browser nesnesini ayarladık. headless değerini false vererek test çalışırken ekrana Chromium uygulamasının gelmesini sağladık. Buna benzer ayarları burada yapabiliriz. Örneğin tarayıcı penceresinin boyutlarını burada belirtebiliriz.

Son olarak teardown.js dosyasını düzenlemek kaldı. Bu dosyada tüm testler tamamlandıktan sonra yapılacak olan işlemlerin tanımlandığı bölümdür.

const rimraf = require('rimraf')
const os = require('os')
const path = require('path')

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup')

module.exports = async function() {
  console.log('Teardown Puppeteer')
  await global.__BROWSER__.close()
  rimraf.sync(DIR)
}

Bu dosyada ekrana gelen Chromium uygulamasının kapatılması ile ilgili işlemi yaptık. Ekstra yapmak istediğiniz işlemler varsa bu dosya üzerinde tanımlayabilirsiniz.

Şimdi test adımlarımızı yazarak uygulamamızı tamamlayabiliriz. Test adımlarını yazabilmek için __tests__/index.js dosyasını açıyoruz ve içeriğini aşağıdaki şekilde düzenliyoruz.

const timeout = 20000;

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

    afterAll(async () => {
      if (page !== undefined) await page.close();
    });

    test("Search test word in Google", async () => {
      jest.setTimeout(timeout);

      page = await global.__BROWSER__.newPage();
      await page.goto("https://google.com");

      await page.waitForSelector("input[name='q']");
      await page.waitForSelector("input[type='submit']");
      await page.type("input[name='q']", "test");
      await page.waitFor(1000);
      await page.click("input[type='submit']");
    });
  },
  timeout
);

Bu testte basit bir şekilde Google'ın ana sayfasında bulunan metin kutucuğuna test yazıp sonrasında ise Google'da Ara düğmesine otomatik olarak bastırıyoruz.

Şimdi testimizi çalıştırıp sonucu görelim. Bunun için 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 testimizi çalıştırabilir hale geldik. Terminalimize yarn test veya npm test komutunu yazarak testimizi çalıştırabiliriz.

jest-puppeteer-3-1

Üstteki görüntüde görüldüğü gibi testimiz başarılı bir şekilde Chromium ekranını açıp arama kutucuğuna test kelimesini yazdı. Testimiz tamamlandığı zaman terminalimizde aşağıdaki gibi bir çıktıyla karşılaşacağız.

jest-puppeteer-2-1

Görüldüğü üzere ilk önce setup.js dosyamız çalışdı. Akabinde puppeteer_environment.js dosyasındaki setup metodu çalıştı. Setup işlemleri tamamlandıktan sonra __tests__/index.js dosyamızda yazmış olduğumuz testler sırası ile çalıştı. Son olarak teardown.js dosyamızda yazmış olduğumuz fonksiyon ve ardından puppeteer_environment.js dosyasındaki teardown metodu çalışarak testimiz tamamlandı.

Puppeteer'da bir testin yaşam döngüsünü bu şekilde incelemiş olduk.

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