Test Data
.env, data JSON, pengaturan retry/timeout/browser, dan menyimpan status login.
Modul ini memisahkan data dan rahasia dari kode test, lalu mengatur konfigurasi supaya test yang sama bisa jalan di laptop, CI, atau server staging.
Kamu tidak menulis password produksi di test case, dan satu test case bisa dijalankan dengan banyak set data. Modul ini membawa dua kebiasaan itu ke dalam kode: rahasia di .env, data di file JSON.
1. Rahasia di .env, bukan di kode
Password, token, dan URL server jangan ditulis di kode test, karena kode masuk ke Git dan bisa dibaca siapa pun yang punya akses. Simpan di file .env.
# .env di folder project ← TIDAK di-commit (tambahkan ke .gitignore)
BASE_URL=https://playground.aminhamzah.com
TOKOQA_USERNAME=customer
TOKOQA_PASSWORD=rahasia123# .env.example ← DI-commit, berisi contoh nilai (bukan nilai asli) untuk anggota tim baru
BASE_URL=https://playground.aminhamzah.com
TOKOQA_USERNAME=isi-username
TOKOQA_PASSWORD=isi-passwordBuat file .env di folder project, sejajar dengan pyproject.toml atau package.json. Lalu tambahkan satu baris .env di file .gitignore, supaya file ini tidak ikut ke Git. Di Windows Explorer, pastikan namanya persis .env, bukan .env.txt.
Cara membacanya dari kode:
# conftest.py: dimuat sekali sebelum test berjalan
from dotenv import load_dotenv
load_dotenv() # paket python-dotenv: mencari .env dari folder ini ke atas
# di test
import os
username = os.environ["TOKOQA_USERNAME"] # error jelas kalau variabelnya lupa diisi// playwright.config.ts: pola dari docs resmi (npm i -D dotenv)
import dotenv from 'dotenv';
import path from 'path'; // alat untuk menyusun path file
// Docs memakai __dirname (CommonJS). Di project ES module, padanannya import.meta.dirname.
dotenv.config({ path: path.resolve(import.meta.dirname, '.env'), quiet: true });
// di test
const username = process.env.TOKOQA_USERNAME!;Di GitHub Actions, file .env tidak ada. Nilainya diambil dari Secrets repository sebagai environment variable, tanpa mengubah kode test (Modul 15).
2. Test data dari file JSON
Data yang banyak, misalnya isian checkout yang salah, simpan di file terpisah. Kasus baru bisa ditambah tanpa menyentuh kode.
Memuat data/checkout_cases.json…
Memuat data/checkout-cases.json…
Lalu setiap baris data dijadikan satu test:
Memuat tests/academy/test_m11_data.py…
uv run pytest tests/academy/test_m11_data.py -vMemuat tests/academy/m11-data.spec.ts…
npx playwright test m11-data --project=chromiumCSV juga bisa dipakai (modul csv di Python, paket csv-parse di Node). Data yang harus unik setiap kali test jalan, misalnya email pendaftaran, buat saat test berjalan: f"user_{uuid4().hex[:8]}@contoh.com" (Python) / 'user_' + Date.now() + '@contoh.com' (TS).
3. Konfigurasi
Pengaturan pytest ada di pyproject.toml (bagian [tool.pytest.ini_options]), ditambah opsi yang bisa kamu ketik saat menjalankan test:
[tool.pytest.ini_options] # pengaturan pytest
testpaths = ["tests"] # file test dicari di folder ini
pythonpath = ["."] # supaya folder pages/ bisa di-import
base_url = "https://playground.aminhamzah.com" # URL dasar untuk page.goto
addopts = "--tracing retain-on-failure --screenshot only-on-failure --video retain-on-failure --output test-results" # simpan trace, screenshot, dan video hanya kalau gagal
markers = ["smoke: test penting", "regression: test lengkap"] # tag yang boleh dipakai| Opsi CLI pytest-playwright | Fungsi |
|---|---|
--browser chromium/firefox/webkit | Pilih browser (boleh diulang untuk beberapa sekaligus) |
--browser-channel chrome | Pakai Google Chrome / Edge asli |
--headed, --slowmo 500 | Tampilkan browser, perlambat setiap aksi |
--device "iPhone 13" | Pura-pura jadi perangkat tertentu |
--base-url https://staging... | Ganti server yang diuji |
--tracing / --video / --screenshot | on, off, retain-on-failure / only-on-failure |
Mau mengubah pengaturan context, misalnya bahasa, zona waktu, atau ukuran layar? Timpa fixture browser_context_args di conftest.py:
@pytest.fixture(scope="session") # fixture bawaan pytest-playwright, ditimpa untuk semua test
def browser_context_args(browser_context_args): # nilai bawaannya ikut diterima
return { # pengaturan context baru
**browser_context_args,
"viewport": {"width": 1366, "height": 768},
"locale": "id-ID",
"timezone_id": "Asia/Jakarta",
}Semua pengaturan ada di playwright.config.ts:
export default defineConfig({ // isi konfigurasi Playwright Test
testDir: './tests',
timeout: 30_000, // timeout per test
expect: { timeout: 5_000 }, // timeout per assertion
retries: process.env.CI ? 2 : 0, // retry hanya di CI
workers: process.env.CI ? 1 : undefined,
reporter: [['list'], ['html', { open: 'never' }]],
use: {
baseURL: 'https://playground.aminhamzah.com',
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
locale: 'id-ID',
timezoneId: 'Asia/Jakarta',
viewport: { width: 1366, height: 768 },
},
// webServer: { command: 'npm run start', url: 'http://localhost:3000' }, // kalau aplikasinya perlu dinyalakan dulu
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
{ name: 'mobile', use: { ...devices['iPhone 13'] } },
],
});Projects artinya menjalankan test yang sama dengan pengaturan berbeda (browser, perangkat, atau server). Mau menjalankan satu project saja? Ketik npx playwright test --project=mobile.
4. Retry
Retry menjalankan ulang test yang gagal. Di CI, ini membantu kalau gagalnya karena hal di luar kendali, misalnya jaringan lambat.
Playwright menandai test seperti ini sebagai flaky. Selidiki penyebabnya (Modul 12), karena test flaky yang didiamkan membuat hasil test tidak bisa dipercaya.
5. Storage state: login sekali, pakai berkali-kali
Login lewat UI di setiap test memakan waktu. Storage state menyimpan cookies dan localStorage ke file JSON, dan context baru yang memakai file ini langsung dalam kondisi sudah login.
# Simpan setelah login
context.storage_state(path="auth.json")
# Pakai di context baru
context = browser.new_context(storage_state="auth.json")// Simpan setelah login
await context.storageState({ path: 'auth.json' });
// Pakai di context baru
const context = await browser.newContext({ storageState: 'auth.json' });Contoh lengkapnya ada di test simpan dan pakai ulang storage state di file asli Modul 11 di atas.
Cara resmi untuk project besar: buat project setup yang login sekali dan menyimpan auth.json, lalu project lain menunggu project itu selesai dulu:
// tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
setup('login sekali', async ({ page }) => { // test khusus persiapan: login sekali
await page.goto('/login-toko.html');
await page.getByLabel('Username').fill(process.env.TOKOQA_USERNAME!); // kredensial dari .env
await page.getByLabel('Password').fill(process.env.TOKOQA_PASSWORD!); // password dari .env
await page.getByRole('button', { name: 'Masuk' }).click(); // klik Masuk
await expect(page.getByTestId('greeting')).toBeVisible(); // sudah masuk
await page.context().storageState({ path: 'playwright/.auth/user.json' }); // simpan status login ke file
});
// playwright.config.ts → projects:
// { name: 'setup', testMatch: /.*\.setup\.ts/ },
// { name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' }, dependencies: ['setup'] },Cara untuk project besar: buat fixture scope="session" yang login sekali dan menyimpan auth.json, lalu timpa browser_context_args supaya memakai storage_state itu. Semua test langsung dalam kondisi login.
File storage state berisi cookie atau token yang masih aktif, jadi siapa pun yang memegangnya bisa masuk sebagai kamu. Masukkan ke .gitignore, sama seperti .env.
Lebih jauh (opsional)Trik komunitas
- Setup project + storage state (TypeScript) adalah cara resmi untuk login sekali lalu dipakai semua test.
- Pengaturan yang dicek otomatis di Python:
pydantic-settingsmembaca.envke dalam class dan langsung protes kalau ada variabel yang lupa diisi. - Data acak dengan Faker:
faker(Python) atau@faker-js/faker(TypeScript) membuat nama, email, dan alamat yang berbeda setiap kali test jalan. - Satu pengaturan, banyak server: ambil
BASE_URLdari environment variable, jadi test yang sama bisa diarahkan ke lokal, staging, atau produksi. - Storage state lengkap: aplikasi yang menyimpan sesi di IndexedDB bisa ikut disimpan dengan opsi
indexed_db=True/indexedDB: true(v1.51+).
import os # untuk membaca environment variable
BASE_URL = os.getenv("BASE_URL", "https://playground.aminhamzah.com") # uv run pytest --base-url juga bisa
context.storage_state(path="auth.json", indexed_db=True) # ikut simpan IndexedDB (untuk aplikasi yang memakainya)// playwright.config.ts
use: { baseURL: process.env.BASE_URL ?? 'https://playground.aminhamzah.com' },
// simpan sesi termasuk IndexedDB
await context.storageState({ path: 'auth.json', indexedDB: true });Latihan
Lihat apa yang terjadi kalau password salah
Ubah TOKOQA_PASSWORD di .env menjadi salah, jalankan test Modul 11, baca errornya, lalu kembalikan nilainya.
Hasiltest yang login lewat .env gagal, lalu lulus lagi setelah dikembalikan
Yang gagal adalah test yang memakai TOKOQA_USERNAME dan TOKOQA_PASSWORD dari .env, misalnya test login dan semua test yang memakai fixture logged_in_shop / loggedInShop. Pesannya kira-kira: sapaan "Halo" tidak pernah muncul, karena halaman tetap di form login dengan pesan "Username atau password salah".
Pelajarannya: password cukup diubah di satu tempat (.env lokal atau Secrets di CI), dan kode test tidak perlu disentuh.
Tambah kasus data tanpa mengubah kode
Tambahkan kasus baru di data/checkout_cases.json (Python) atau data/checkout-cases.json (TypeScript): kode pos berisi huruf, misalnya 40A11. Jalankan test Modul 11 tanpa menyentuh kodenya.
Hasilsatu test baru lulus dengan pesan "Kode pos harus 5 digit angka."
Tambahkan satu baris ini di file JSON-nya (di project contoh Academy baris ini sudah ada). Nama kolomnya mengikuti kasus lain di file yang sama: postal_code di Python, postalCode di TypeScript.
{ "case": "kode pos berisi huruf", "recipient": "Rina", "phone": "081234567890", "postal_code": "40A11", "error": "Kode pos harus 5 digit angka." }Saat dijalankan, test validasi alamat otomatis bertambah satu, lengkap dengan nama kasusnya. Pesannya sama dengan kasus "kode pos bukan 5 digit", tapi tetap layak jadi kasus sendiri: aturan "harus angka" dan aturan "harus 5 digit" bisa rusak secara terpisah.
Jalankan di ukuran layar ponsel
Jalankan test Modul 10 dengan profil perangkat iPhone 13.
Hasiltest tetap lulus di layar kecil
uv run pytest tests/academy/test_m10_pom.py --device "iPhone 13" --browser webkit # emulasi iPhone 13 di WebKit# Tambahkan project baru di playwright.config.ts:
# { name: 'iphone', use: { ...devices['iPhone 13'] } },
npx playwright test m10-pom --project=iphoneProfil perangkat mengatur ukuran layar, user agent, dan layar sentuh sekaligus.
Storage state untuk KlinikQA
Brief: KlinikQA menyimpan token login di localStorage (klinikqa_token). Storage state ikut menyimpan localStorage, jadi login cukup sekali.
- Login ke KlinikQA lewat UI sebagai
pasien/sehat123. - Simpan storage state context itu ke file.
- Buat browser context baru dari file itu, lalu buka
/klinik.html.
Hasilhalaman langsung menyapa Halo, Budi Santoso tanpa mengisi form login
Memuat tests/latihan/test_m11_latihan.py…
Memuat tests/latihan/m11-latihan.spec.ts…