Belum punya project? Mulai dari Persiapan.
Setup dan terminal
Menampilkan Python. Ganti bahasa di bagian atas untuk melihat TypeScript.Menampilkan TypeScript. Ganti bahasa di bagian atas untuk melihat Python.
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Buat project | uv init --no-package playwright-python | npm init playwright@latest -- playwright-typescript --quiet --no-examples |
| Install paket | uv add pytest pytest-playwright | npm install -D @playwright/test |
| Install browser | uv run playwright install | npx playwright install |
| Cek versi | uv run playwright --version | npx playwright --version |
| Jalankan satu file | uv run pytest tests/test_pertama.py | npx playwright test tests/pertama.spec.ts |
| Buka HTML report | uv run pytest --html=reports/report.html (plugin pytest-html, Modul 12) | npx playwright show-report |
Pengguna PowerShell
PWDEBUG=1 perintah adalah cara menulis di bash. Di PowerShell, tulis $env:PWDEBUG=1 di baris terpisah, lalu perintahnya. Hindari juga && di Windows PowerShell 5.1.
Navigasi & halaman
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Buka URL | page.goto("/path") | await page.goto('/path') |
| Kembali / maju / reload | page.go_back() · page.go_forward() · page.reload() | await page.goBack() · goForward() · reload() |
| Judul & URL | page.title() · page.url | await page.title() · page.url() |
| Tunggu URL | page.wait_for_url("**/shop.html") | await page.waitForURL('**/shop.html') |
| Screenshot | page.screenshot(path="a.png", full_page=True) | await page.screenshot({ path: 'a.png', fullPage: true }) |
| Ukuran layar | page.set_viewport_size({"width": 390, "height": 844}) | await page.setViewportSize({ width: 390, height: 844 }) |
Locator
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Role + nama | get_by_role("button", name="Masuk") | getByRole('button', { name: 'Masuk' }) |
| Nama persis | get_by_role("button", name="Masuk", exact=True) | getByRole('button', { name: 'Masuk', exact: true }) |
| Label | get_by_label("Username") | getByLabel('Username') |
| Placeholder | get_by_placeholder("Misalnya: mouse") | getByPlaceholder('Misalnya: mouse') |
| Teks | get_by_text("Stok habis") | getByText('Stok habis') |
| Alt / title | get_by_alt_text("Logo") · get_by_title("Info") | getByAltText('Logo') · getByTitle('Info') |
| Test id | get_by_test_id("cart-count") | getByTestId('cart-count') |
| CSS | locator("#students tr") | locator('#students tr') |
| Filter teks | .filter(has_text="Mouse") | .filter({ hasText: 'Mouse' }) |
| Filter berisi elemen | .filter(has=page.get_by_role("heading")) | .filter({ has: page.getByRole('heading') }) |
| Urutan | .first · .last · .nth(2) | .first() · .last() · .nth(2) |
| Jumlah | .count() | await .count() |
| Semua teks | .all_inner_texts() | await .allInnerTexts() |
| iframe | page.frame_locator("iframe") | page.frameLocator('iframe') |
Aksi
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Klik / dobel / kanan | .click() · .dblclick() · .click(button="right") | .click() · .dblclick() · .click({ button: 'right' }) |
| Isi / kosongkan | .fill("teks") · .clear() | .fill('teks') · .clear() |
| Ketik per huruf | .press_sequentially("teks") | .pressSequentially('teks') |
| Tombol keyboard | .press("Enter") | .press('Enter') |
| Centang | .check() · .uncheck() · .set_checked(True) | .check() · .uncheck() · .setChecked(true) |
| Dropdown | .select_option("python") · .select_option(label="Python") | .selectOption('python') · .selectOption({ label: 'Python' }) |
| Hover / fokus | .hover() · .focus() | .hover() · .focus() |
| Upload | .set_input_files("a.txt") | .setInputFiles('a.txt') |
| Drag & drop | .drag_to(target) | .dragTo(target) |
Assertion (expect)
| Mengecek | 🐍 Python | 🟦 TypeScript |
|---|
| Terlihat / tersembunyi | to_be_visible() · to_be_hidden() | toBeVisible() · toBeHidden() |
| Aktif / nonaktif | to_be_enabled() · to_be_disabled() | toBeEnabled() · toBeDisabled() |
| Tercentang / kosong / fokus | to_be_checked() · to_be_empty() · to_be_focused() | toBeChecked() · toBeEmpty() · toBeFocused() |
| Teks | to_have_text("…") · to_contain_text("…") | toHaveText('…') · toContainText('…') |
| Nilai / atribut / class | to_have_value() · to_have_attribute() · to_have_class() | toHaveValue() · toHaveAttribute() · toHaveClass() |
| Jumlah | to_have_count(3) | toHaveCount(3) |
| Halaman | expect(page).to_have_url() · to_have_title() | expect(page).toHaveURL() · toHaveTitle() |
| Kebalikan | not_to_be_visible() | .not.toBeVisible() |
| Timeout khusus | to_be_visible(timeout=10_000) | toBeVisible({ timeout: 10_000 }) |
| Respons API | expect(res).to_be_ok() | await expect(res).toBeOK() |
| Soft | Tidak ada (pakai plugin pytest-check) | expect.soft(...) |
Event: dialog, tab, download, network
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Dialog | page.once("dialog", lambda d: d.accept()) | page.once('dialog', d => d.accept()) |
| Tab baru | with context.expect_page() as info: … → info.value | const p = context.waitForEvent('page'); …; await p |
| Download | with page.expect_download() as info: … | const d = page.waitForEvent('download'); …; await d |
| Tunggu respons | with page.expect_response("**/api/x") as info: … | const r = page.waitForResponse('**/api/x'); …; await r |
| Mock respons | page.route("**/api/x", lambda r: r.fulfill(json={...})) | await page.route('**/api/x', r => r.fulfill({ json: {...} })) |
| Blokir | page.route("**/*.png", lambda r: r.abort()) | await page.route('**/*.png', r => r.abort()) |
| Script sebelum halaman | page.add_init_script("…") | await page.addInitScript(() => { … }) |
API testing
| Mau apa | 🐍 Python | 🟦 TypeScript |
|---|
| Buat context | api = playwright.request.new_context(base_url=…) | fixture request (pakai baseURL config) |
| GET + query | api.get("/api/products", params={"q": "mouse"}) | request.get('/api/products', { params: { q: 'mouse' } }) |
| POST JSON | api.post("/api/login", data={...}) | request.post('/api/login', { data: {...} }) |
| PUT / PATCH / DELETE | api.put(url, data=...) · api.patch(...) · api.delete(url) | request.put(url, { data }) · request.patch(...) · request.delete(url) |
| Baca header | res.headers["location"] | res.headers()['location'] |
| Header | headers={"Authorization": f"Bearer {t}"} | headers: { Authorization: 'Bearer ' + t } |
| Status & body | res.status · res.ok · res.json() | res.status() · res.ok() · await res.json() |
Test runner
| Mau apa | 🐍 pytest | 🟦 Playwright Test |
|---|
| Jalankan semua | uv run pytest | npx playwright test |
| Filter nama | -k "login" | -g "login" |
| Tag | @pytest.mark.smoke → -m smoke | { tag: '@smoke' } → --grep @smoke |
| Headed / debug | --headed --slowmo 500 · PWDEBUG=1 | --headed · --debug · --ui |
| Browser | --browser firefox | --project=firefox |
| Yang gagal saja | --lf | --last-failed |
| Data-driven | @pytest.mark.parametrize(...) | for (const c of cases) test(...) |
| Persiapan | @pytest.fixture (+ yield) | test.beforeEach · test.extend |
| Skip | @pytest.mark.skip · pytest.skip() | test.skip() |
| Trace | --tracing on → playwright show-trace | --trace on → npx playwright show-report |
| Codegen | uv run playwright codegen URL | npx playwright codegen URL |