A Puppeteer egy Node.js könyvtár, amely magas szintű API-t biztosít a Chrome vagy a Firefox vezérléséhez. DevTools protokollt vagy WebDriver BiDi-t használ.
Alapértelmezetten fej nélkül (nem indul el láthatóan a böngésző) fut, de beállítható, hogy látható legyen.
Webhely
A teszt elhelyezhető egy kész projektben, vagy létrehozható külön tesztelő projekt. A használathoz szükség van egy Node.js projektre.
Ha meg van a Node.js projekt, telepítsük a puppeteer csomagot:
npm install --save-dev puppeteer
Ha használjuk a pnpm parancsot:
pnpm add --save-dev puppeteer
{ "type": "module" }
import puppeteer from 'puppeteer'; (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://szit.hu'); await page.screenshot({ path: 'example.png' }); await browser.close(); })();
Futtatás:
node test/barmi.js
Készítsünk egy test könyvtárat, ebbe helyezzük el az első tesztünket. Az első példában a a https://szit.hu webhely keresőjét fogjuk tesztelni. Megnézzük a „Programozás” szót ha beírjuk kapunk-e olyan találatot, amiben szerepel a „programozas” kulcsszó.
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://szit.hu/'); await page.type('#qsearch__in', 'Programozás'); await page.click('button[type="submit"]'); await page.waitForSelector('body'); const content = await page.content(); const containsProgramming = content.includes('programozas'); if (containsProgramming) { console.log('Az oldal tartalmazza a "programozas" szót.'); } else { console.log('Az oldal nem tartalmazza a "programozas" szót.'); } await browser.close(); })();
A teszt indítás:
node test/test01.js
Szeretnénk látni a böngészőt 5 másodpercig. Letiltjuk a fej nélküli indítást:
puppeteer.launch({headless: false});
Majd indítunk egy 5 másodperces várakozhást:
await new Promise(resolve => setTimeout(resolve, 5000));
A teljes kód:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('https://szit.hu/'); await new Promise(resolve => setTimeout(resolve, 5000)); await browser.close(); })();
A teszt indítás:
node test/valami.js
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); await page.goto('https://szit.hu/'); await page.screenshot({ path: 'szit.png', fullPage: true}); await page.pdf({ path: 'szit.pdf', format: 'A4'}); await browser.close(); })();
A Puppeteer csak a böngészőt automatizálja. A teszt automatizálásához a Mocha-t fogjuk használni.
Telepítsük:
npm install --save-dev mocha
Lássunk egy példát, hogy használjuk a Puppeteer-t és a Mocha-t együtt.
const puppeteer = require('puppeteer'); const assert = require('assert'); describe('Teszt', function() { let browser; let page; before(async function() { browser = await puppeteer.launch({headless: true}); page = await browser.newPage(); }); after(async function() { await browser.close(); }); it('Az oldalra navigálunk', async function() { await page.goto('https://szit.hu'); const title = await page.title(); assert.strictEqual(title, 'start [szit]') }); it('Oktatás link a főoldalon', async function() { await page.goto('https://szit.hu'); const linkExists = await page.waitForSelector('a[href="/doku.php?id=oktatas"]'); assert.ok(linkExists, 'Az Oktatás link nem található a főoldalon.'); }); it('Kattintunk az Oktatás linkre', async function() { await page.goto('https://szit.hu'); await page.click('a[href="/doku.php?id=oktatas"]'); await page.waitForSelector('body') const currentUrl = await page.url(); assert.strictEqual(currentUrl, 'https://szit.hu/doku.php?id=oktatas'); }); });
Futtatás ha a Mocha a projektbe van telepítve:
npx mocha
Ebben a példában ES modulokat használunk (import a requiure helyett), ezért a package.json fájlban:
{ "type": "module" }
A teszt ezek után:
import puppeteer from "puppeteer"; import assert from "assert"; describe("Triangle", function () { let browser; let page; before(async function () { browser = await puppeteer.launch(); page = await browser.newPage(); }); /* Minden teszt előtt újra betölti a weboldalot. */ this.beforeEach(async function () { await page.goto("https://szit.hu/m/triangle_ts"); }) after(async function () { await browser.close(); }); it("A title ellenőrzése", async function () { const actual = await page.title(); const expected = "Háromszög"; assert.strictEqual(actual, expected); }); it("A h1 elem ellenőrzése", async function () { const actual = await page.$eval("h1", el => el.textContent); const expected = "Háromszög területe"; assert.strictEqual(actual, expected); }); it("Háromszög területe 30, 35 bemenetre 525", async function () { await page.type("#base", "30"); await page.type("#height", "35"); await page.click("#calcButton"); const actual = await page.$eval("#area", el => Number(el.value)); const expected = 525; assert.strictEqual(actual.toFixed(1), expected.toFixed(1)); }); it("Háromszög területe 123, 99 bemenetre 6088.5", async function () { await page.type("#base", "123"); await page.type("#height", "99"); await page.click("#calcButton"); const actual = await page.$eval("#area", el => Number(el.value)); const expected = 6088.5; assert.strictEqual(actual.toFixed(1), expected.toFixed(1)); }); })
A tesztekben változatos szelektorokra van szükségünk. Nézzünk néhány példát.
const content = await page.$eval('.form .input:nth-child(2) .form-label', element => element.textContent.trim())
it('Az alap label tartalma', async function() { const content = await page.$eval('.form .input:first-child .form-label', element => element.textContent.trim()) assert.strictEqual(content, 'Alap') })
it('A magasság label tartalma', async function() { const content = await page.$eval('label[for="height"]', element => element.textContent.trim()) assert.strictEqual(content, 'Magasság') })
Az id alapján hivatkozás:
const inputValue = await page.$eval('#height', element => element.value);
<!DOCTYPE html> <html lang="hu"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Háromszög</title> <link rel="stylesheet" href="bootstrap.css"> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1>Háromszög területe</h1> <div class="form"> <div class="input"> <label for="base" class="form-label"> Alap </label> <input type="text" id="base" class="form-control"> </div> <div class="input"> <label for="height" class="form-label"> Magasság </label> <input type="text" id="height" class="form-control"> </div> <div> <button id="calcButton" class="btn btn-primary mt-2"> Számít </button> </div> <div class="input"> <label for="area" class="form-label"> Terület </label> <input type="text" id="area" class="form-control" readonly> </div> </div> </div> <script type="module" src="app.js"></script> </body> </html>
const doc = { baseInput: document.querySelector('#base'), heightInput: document.querySelector('#height'), areaInput: document.querySelector('#area'), calcButton: document.querySelector('#calcButton') } const state = { base: 0, height: 0, area: 0 } doc.calcButton.addEventListener('click', () => { startCalc() }) function startCalc() { state.base = doc.baseInput.value state.height = doc.heightInput.value state.area = calcArea(state.base, state.height) renderResult() } function calcArea(base, height) { return base * height / 2 } function renderResult() { doc.baseInput.value = '' doc.heightInput.value = '' doc.areaInput.value = state.area doc.baseInput.focus(); }
Ebben a példában ECMASCriptet használunk, így import kulcsszavakkal importálunk.
import puppeteer from 'puppeteer' import assert from 'assert' describe('Területszámítás tesztje', () => { let browser; let page; before(async function () { browser = await puppeteer.launch({headless: true}) page = await browser.newPage() await page.goto('http://localhost:3000') }) after(async function() { await browser.close() }) it('Böngésző címsora', async function() { const title = await page.title() assert.strictEqual(title, 'Háromszög') }) it('h1 tartalma', async function() { const content = await page.$eval('h1', element => element.textContent) assert.strictEqual(content, 'Háromszög területe') }) it('Az alap label tartalma', async function() { const content = await page.$eval('label[for="base"]', element => element.textContent.trim()) assert.strictEqual(content, 'Alap') }) it('A magasság label tartalma', async function() { const content = await page.$eval('label[for="height"]', element => element.textContent.trim()) assert.strictEqual(content, 'Magasság') }) it('Az alap input', async function() { const element = await page.$('#base') assert.ok(element, 'A base input elemnek léteznie kell') }) it('A magasság input', async function() { const element = await page.$('#height') assert.ok(element, 'A height input elemnek léteznie kell') }) it('Input 30 35 és kattintás', async function() { await page.type('#base', '30') await page.type('#height', '35') await page.click('#calcButton') const actual = await page.$eval('#area', elem => elem.value) assert.strictEqual(actual, '525') }) })