Dramatik a Mojolicious

V SUSE je opět Hack Week. 🥳 Každoroční tradice, kdy všichni celý týden pracujeme na vášnivých projektech. Někteří z nás tvoří hudbu, jiní využívají čas k experimentování s nejnovějšími technologiemi a zakládání nových Open Source projektů.

Mým projektem bylo tentokrát zjistit, zda existuje lepší způsob, jak provádět automatizované testování webových aplikací Mojolicious v prohlížeči. Selenium byl po dlouhou dobu de facto standardem pro automatizaci prohlížečů, ale dnes jsou k dispozici modernější alternativy, jako je Playwright. Ale jak dobrý je ve skutečnosti Dramatik? Spoiler:Je to velmi dobré. Ale pokračujte ve čtení, abyste zjistili proč a za jakou cenu.

Co je dramatik?

Playwright, stejně jako předtím Selenium, je framework pro automatizaci prohlížeče. Můžete jej použít pro všechny druhy skriptovaných interakcí s webovými stránkami, například nákup těchto GPU Nvidia od online prodejců rychleji než všichni ostatní 😉, ale nejčastěji se používá v testovacích sadách webových aplikací.

Kód je vyvíjen společností Microsoft jako Open Source projekt s licencí Apache 2.0 a distribuován jako balíček NPM. Vše, co potřebujete, je Node a můžete jej nainstalovat s jednou vložkou.

$ npm i playwright

Existují vazby pro jiné jazyky, ale abyste z Playwrighta vytěžili maximum, musíte používat JavaScript. Nyní, pokud jde o podporu prohlížeče, kde vám Selenium dává možnost vybrat si jako backend jakýkoli prohlížeč kompatibilní s WebDriver, Playwright vám stáhne vlastní sestavení Chromium, Firefox a WebKit. A to je vše, co získáte.

Dělají to však z docela dobrých důvodů. Binární soubory prohlížeče mají tendenci bezchybně fungovat na všech podporovaných platformách, které v současnosti zahrnují Windows, macOS a Linux (x86). A když jste zvyklí na pomalost Selenu, zdá se to téměř magické, jak rychle a spolehlivě Playwright běží.

Je to proto, že tam, kde se Selenium drží otevřených protokolů, Playwright využije každý trik v knize pro lepší výkon. Včetně vlastních záplat pro tyto prohlížeče, rozšíření jejich protokolů DevTools a následné použití těchto protokolů k ovládání prohlížečů. Nejsem velkým fanouškem tohoto přístupu, ale s výsledky je těžké polemizovat.

Krátkodobě to má obrovské výhody, ale nutnost udržovat tyto záplaty prohlížeče po neomezenou dobu, pokud nebudou začleněny do upstreamu, může zpomalit životnost projektu.

Použití nástroje Playwright

import assert from 'assert/strict';
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch({ headless: false, slowMo: 50 });
  const context = await browser.newContext();
  const page = await context.newPage();

  await page.goto('https://mojolicious.org/');
  await page.click('text=Documentation');
  await page.click('text=Tutorial');
  assert.equal(page.url(), 'https://docs.mojolicious.org/Mojolicious/Guides/Tutorial');
  await page.screenshot({ path: 'tutorial.png' });

  await context.close();
  await browser.close();
})();

Pokud jste již někdy vyvíjeli web, rozhraní API bude velmi intuitivní a bylo jasně navrženo pomocí async/await v mysli, které jsem velkým fanouškem. Můžete mít několik izolovaných kontextů prohlížeče s vlastními soubory cookie atd. a každý kontext může mít více stránek.

Každá interakce, například page.click() , bude automaticky čekat, až se prvek stane viditelným, s časovým limitem, který je standardně nastaven na 30 sekund. Toto je obrovský krok kupředu oproti Selenium, kde si musíte tuto logiku vybudovat sami a v mnoha zábavných ohledech se zmýlíte. 😅

Můžete emulovat zařízení, jako jsou iPhony, používat geolokaci, měnit časová pásma, volit mezi režimem bez hlavy a bez hlavy pro všechny prohlížeče a mít možnost kdykoli pořizovat snímky obrazovky nebo nahrávat video.

Jednou z nejnovějších funkcí, které byly přidány, byl GUI rekordér, který otevírá okno Chromium a poté zaznamenává všechny interakce uživatelů a současně generuje kód JavaScript za pochodu. Zpočátku jsem k tomu byl trochu skeptický, ale může to výrazně urychlit vývoj testu, protože už nemusíte příliš přemýšlet o CSS selektorech. I když nakonec použijete části vygenerovaného kódu.

Dramatik a Perl

Spuštění Playwrighta proti živým webům je velmi přímočaré. Ale pro automatizované testování webových aplikací také chcete, aby vaše testovací skripty spouštěly a zastavovaly webový server za vás. A to je místo, kde jsou věci trochu složitější, pokud je vaše webová aplikace napsána v jiném jazyce než JavaScript.

use Mojolicious::Lite -signatures;

get '/' => {template => 'index'};

app->start;
__DATA__
@@ index.html.ep
<!DOCTYPE html>
<html>
  <body>Hello World!</body>
</html>

Ke spuštění aplikace v Perlu jsem potřeboval superdémon JavaScript s podporou aktivace socketu. Bohužel jsem nebyl schopen najít modul pro práci na NPM a musel jsem se uchýlit k napsání vlastního. A nyní organizace Mojolicious není jen na CPAN, ale také na NPM. 😇

import assert from 'assert/strict';
import ServerStarter from '@mojolicious/server-starter';
import { chromium } from 'playwright';

(async () => {
  const server = await ServerStarter.newServer();
  await server.launch('perl', ['test.pl', 'daemon', '-l', 'http://*?fd=3']);
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();
  const url = server.url();

  await page.goto(url);
  const body = await page.innerText('body');
  assert.equal(body, 'Hello World!');

  await context.close();
  await browser.close();
  await server.close();
})();

Možná jste si všimli zvláštního umístění poslechu http://*?fd=3 . To je funkce Mojolicious, kterou jsme původně vyvinuli pro systemd nasazení se soubory .socket. Superdémon, v tom případě systemd , naváže naslouchací soket velmi brzy během spouštění systému a poté jej předá službě .socket soubor patří jako deskriptor souboru 3 . To má mnoho výhod, například služby spouštěné jako neprivilegovaní uživatelé, kteří mohou používat privilegované porty.

Každopádně náš případ použití je zde mírně odlišný, ale lze použít stejný mechanismus. A tím, že superdémon aktivuje soket, můžeme se vyhnout vícenásobným rasovým podmínkám. Soket bude aktivní ještě před spuštěním procesu webové aplikace, což znamená page.goto() nikdy nemůže dostat chybu odmítnutí připojení. Místo toho bude jen čekat na přijetí jeho připojení. A důležité pro testování ve velkém měřítku, kdy mnoho testů běží paralelně na stejném počítači, můžeme použít náhodné porty, které nám přiřadí operační systém. Vyhýbání se možnosti konfliktů v důsledku špatného načasování.

Kombinace všeho

A pro svůj poslední trik použiji vynikající Node-Tap, který umožňuje našim testům JavaScriptu používat protokol Test Anything Protocol, což je shodou okolností standard používaný ve světě Perlu pro testování.

#!/usr/bin/env node
import t from 'tap';
import ServerStarter from '@mojolicious/server-starter';
import { chromium } from 'playwright';

t.test('Test the Hello World app', async t => {
  const server = await ServerStarter.newServer();
  await server.launch('perl', ['test.pl', 'daemon', '-l', 'http://*?fd=3']);
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();
  const url = server.url();

  await page.goto(url);
  const body = await page.innerText('body');
  t.equal(body, 'Hello World!');

  await context.close();
  await browser.close();
  await server.close();
});

Možná jste si všimli řádku shebang #!/usr/bin/env node . To je další malý Perl trik. Když interpret Perlu narazí na řádek shebang, který není perl znovu spustí skript. V tomto případě s node a jako vedlejší efekt můžeme použít standardní testovací nástroje Perl jako prove spustit naše testy JavaScriptu hned vedle běžných testů Perl.

$ prove t/*.t t/*.js
t/just_a_perl_test.t ... ok                                                                                                     
t/test.js .. ok
All tests successful.
Files=3, Tests=4,  2 wallclock secs ( 0.03 usr  0.01 sys +  2.42 cusr  0.62 csys =  3.08 CPU)
Result: PASS

Ve skutečnosti můžete dokonce spustit několik těchto testů paralelně s prove -j 9 t/*.js bez námahy zvětšit. Playwright zvládne paralelní běhy a bude fungovat neuvěřitelně dobře v bezhlavém režimu.

Ještě jedna věc

A pokud jste to dotáhli až sem, mám pro vás ještě jednu věc. V mojo-playwright repo na GitHubu můžete najít chatovací aplikaci WebSocket a smíšené testy JavaScript/Perl, které můžete použít k experimentování. Obsahuje také řešení, jak nastavit testovací přípravky pomocí obalových skriptů a jak je spouštět v akcích GitHub. Bavte se!