Kompletní průvodce frontendovým unit testováním s Jestem

  • Jednotkové testování s Jestem vám umožňuje rychle, izolovaně a spolehlivě validovat funkce, komponenty a služby frontendu.
  • Test Trophy vyvažuje statické, jednotkové, integrační a E2E testování, aby maximalizoval důvěru bez prudkého nárůstu nákladů.
  • Knihovna pro testování Reactu a jest-preset-angular integrují Jest s Reactem a Angularem, což podporuje testování zaměřené na chování uživatelů.
  • Dobré postupy, jako jsou popisné názvy, dobře používané simulace a řízené pokrytí, proměňují testy v živou dokumentaci systému.

Jak provádět jednotkové testování na frontendu s Jestem

Když začnete brát vývoj frontendu vážně, dříve či později dosáhnete stejného bodu: potřebujete unit testy, které vám dodají jistotu, že se kódu bez obav budete moci dotknout. A právě v tomto bodě se Jest, spolu s nástroji jako React Testing Library nebo jest-preset-angular, stane vašimi nejlepšími spojenci.

V této příručce se klidně, ale přímočaře podíváme na to, jak naplánovat a implementovat strategii frontendového unit testování pomocí Jestu : jaké typy testů dávají smysl, jak je konfigurovat v projektech React, Angular nebo TypeScript, jak psát dobré testy (aniž byste se museli zabředávat do detailů implementace) a jaké nástroje máte k dispozici pro porovnávání výsledků, práci s DOM, mocky, asynchronní analýzou, pokrytím a mnoha dalšími funkcemi.

Proč jsou jednotkové testy ve frontendovém vývoji tak důležité?

Zkušení vývojáři chápou velmi jednoduchý fakt: jejich kód bude obsahovat chyby . Nejde o to být chytřejší nebo méně chytří, ale o to akceptovat, že bez dobré testovací sady může jakákoli změna narušit klíčové funkce… a uživatel to zjistí dříve než vy.

Vývojové pracovní postupy s Dev Home
Související článek:
Jak implementovat JWT ověřování v Node.js API

Jednotkové testování zahrnuje testování malých částí kódu izolovaně : funkcí, metod, komponent nebo služeb. Myšlenka je jednoduchá: při zadání konkrétního vstupu očekáváte konkrétní výstup. Pokud to platí dnes i v budoucnu, chování zůstane stabilní, i když se interní kód změní.

Mezi nejdůležitější výhody dobrých jednotkových testů patří několik docela hmatatelných věcí: včasná detekce chyb, dokumentace chování systému a usnadnění rozsáhlých refaktoringů, aniž by se váš život proměnil v ruletu při nasazení.

Testovací trofej a typy testů ve frontendu

V posledních letech se stala populární tzv. „Test Trophy“ , moderní alternativa ke klasické testovací pyramidě. Tento model se místo posedlosti procentem pokrytí snaží vyvážit úsilí, náklady a míru spolehlivosti napříč různými typy testů.

Testovací trofej obvykle zohledňuje čtyři úrovně: statické, jednotkové, integrační a end-to-end testování . Každá z nich poskytuje jiný typ zpětné vazby a je vhodné je kombinovat, než se zaměřovat pouze na jednu.

Statické testování: lintery a analýza kódu

Statické testy jsou ty, které se používají bez spuštění kódu . Jsou podobné korektuře knihy na pravopisné chyby ještě před přečtením článku. Zde přicházejí na řadu nástroje jako ESLint pro JavaScript nebo specifická pravidla pro TypeScript.

  • Ověřují, zda kód splňuje určitá pravidla a standardy. (pojmenování, formát, zakázané vzory atd.).
  • Odhalují běžné chyby předtím, než se dostanou do běhového prostředí, například podezřelé použití proměnných, nefunkční importy nebo nesprávně odvozené typy.
  • Upřednostňují homogenní styl což usnadňuje týmovou práci a údržbu.

V moderních projektech TypeScript je typické kombinovat ESLint a samotný kompilátor TS , aby se zachytily stylistické chyby i typové problémy ještě před spuštěním testu s Jestem.

Jednotkové testy: první linie obrany

Jednotkové testy jsou testy prováděné na nejmenší logické jednotce : čisté funkci, metodě, hooku, malé komponentě nebo jednoduché službě. V backendovém vývoji obvykle hovoříme o třídách a metodách; ve frontendovém vývoji může být jednotkou také komponenta nebo část zapouzdřené logiky.

V ekosystému JavaScriptu a TypeScriptu uvidíte názvy jako Jest, Mocha, Chai nebo Vitest, ačkoli Jest se stal de facto standardem pro frontend, hlavně díky své integraci s knihovnou React Testing Library a předvolbám jako jest-preset-angular.

Je důležité si uvědomit, že jednotkové testy se nezabývají interní implementací , ale očekávaným výstupem: při známém vstupu by funkce nebo komponenta měla produkovat určitý výsledek, bez ohledu na to, jak je interně napsána.

Integrační testy: zajištění vzájemné komunikace jednotlivých částí

Integrační testování se zaměřuje na to, jak se různé moduly nebo komponenty kombinují . Nedíváte se pouze na izolovanou funkci, ale na interakci mezi službami, komponentami a obchodní logikou.

  • Definují scénáře, kde spolupracuje několik stran: formulář, který volá službu, která následně transformuje data a zobrazuje je v rozhraní.
  • Pomáhají detekovat chyby na hranicích mezi modulycož je místo, kde se často objevují chyby v datech, typy nebo API smlouvy.
  • Ve frontendu s TypeScript se můžete spolehnout Supertest, Cypress nebo dokonce testy s Jestem, které procvičují několik komponent a služeb najednou.

Ve světě Reactu se tato „integrace“ obvykle testuje pomocí knihovny React Testing Library a Jestu , čímž se vykreslují komponenty, které již používají jiné interní komponenty a simulované služby. V Angularu je běžné sestavit komponentu pomocí TestBedu a použít Jest jako renderovací engine místo Karmy/Jasmine.

Komplexní testování (E2E): kompletní cesta uživatele

E2E testy simulují skutečné chování uživatele při navigaci v aplikaci: otevírání stránek, klikání, vyplňování formulářů a čekání na odpovědi ze strany serveru.

  • Praktikují komplexní aplikaci, z rozhraní do API (nebo simulovaného prostředí velmi blízkého produkčnímu).
  • Ověřují kritické tokynapříklad přihlašování, nákupy, složité formuláře nebo procesy registrace.
  • Obvykle se implementují s Cypřiš, dramatik, loutkář nebo selen ve webových prostředích.

Tyto testy jsou pomalejší a křehčí, ale poskytnou nejvyšší úroveň spolehlivosti pro klíčové funkce. Trik spočívá v jejich moudrém používání, pokrytí pouze skutečně kritických cest a spoléhání se na jednotkové a integrační testy pro zbytek.

Co přesně je jednotkový test a k čemu je dobrý?

frontendové unit testování s Jestem

Kromě označení si mnoho lidí klade otázku: co se počítá jako unit test ve frontend vývoji ? Izolovaná komponenta? Funkce? Celá stránka?

Velmi užitečná definice pochází z klasického TDD: jednotkový test představuje malý scénář, funkční požadavek nebo kritérium přijetí . Nemusí být omezen na jednu malou funkci, ale měl by být rychlý, stabilní a cílený.

Klíčové vlastnosti užitečného jednotkového testu

  • Zaměřuje se na omezenou jednotku chování: funkce, metoda, komponenta nebo malý tok.
  • Je rychlý a izolovanýNezávisí to na síti, skutečných databázích ani na časovačích. Pokud existují externí závislosti, jsou simulovány.
  • Poskytněte jasnou zpětnou vazbuKdyž selže, víte, který požadavek již není splněn, nejen to, že se „něco“ pokazilo.
  • Slouží jako živá dokumentacePřečtením testu pochopíte, co se od daného kusu kódu očekává.

V moderním frontendovém vývoji dává velký smysl, že mnoho z těchto jednotkových testů jsou ve skutečnosti malé integrační testy : komponenta s jejími potomky, hook, který používá službu atd., pokud zůstanou rychlé a spolehlivé.

Jest jako framework pro frontendové testování

Jest si vydobyl místo dominantního testovacího frameworku v ekosystému JavaScriptu . Velké společnosti jako Facebook, Airbnb, Twitter a Spotify ho používají k testování svých frontendových aplikací založených na Reactu, Angularu a dalších.

Jednou z jeho velkých výhod je, že pro zahájení práce v projektech JavaScript nebo TypeScript nevyžaduje téměř žádnou konfiguraci a je dodáván s vestavěnými nástroji pro mocky, špiony, asserce a covering kódu, čímž se vyhnete závislosti na tisíci dalších knihoven.

Základní funkce: describe, test/it, beforeEach a afterEach

Typická struktura testovacího souboru Jest je založena na několika klíčových blocích, které budete vidět znovu a znovu:

  • popis(jméno, fn)Toto seskupuje související testy pod jeden popis. Pomáhá to uspořádat a číst výsledky v konzoli.
  • test(jméno, fn) o to(jméno, fn)Definujte konkrétní test. Obě funkce jsou ekvivalentní; vyberte si tu, která vám vyhovuje.
  • předKaždým(fn)Provádí se před každým skupinovým testem. Ideální pro konfigurovat počáteční stav, napodobeniny nebo běžné případy.
  • poKaždém(fn)Tento příkaz se spustí po každém testu. Je užitečný pro čištění, obnovu simulovaných propojení nebo uzavírání simulovaných připojení.

V jakémkoli jednotkovém testu, v rámci funkce, kterou předáváte metodě test nebo it , budete vždy dodržovat víceméně stejný vzorec: připravíte data, spustíte funkci nebo vykreslíte komponentu a použijete expect(…) k potvrzení očekávaného výsledku.

Porovnávače a srovnání v Jestu

Jádrem assercí v Jestu je funkce `expect` , která je propojena s různými metodami pro kontrolu různých podmínek. Mezi nejběžnější patří:

  • .toBe(hodnota): kontroluje striktní rovnost pomocí Object.isIdeální pro čísla, řetězce a booleovské hodnoty.
  • .toEqual(obj): provádí rekurzivní porovnání objektů a polí, ideální pro složité datové struktury.
  • .nenapříklad obrátit porovnávač očekávat(false).nebýt.pravda.
  • .toBeDefined(): kontroluje, zda hodnota není undefined.
  • .toContain o očekávat.arrayContaining: ověřit, zda pole nebo řetězec obsahuje určité prvky.

Na tomto základě Jest přidává mnoho dalších specifických funkcí: .toHaveBeenCalled, .toHaveBeenCalledTimes, .toHaveBeenCalledWith pro mocky, .toThrow pro chyby nebo rozšířené matchery, když integrujete knihovny jako @testing-library/jest-dom pro práci s DOM.

Testování DOM s knihovnou React Testing Library

Pokud jde o komponenty Reactu, nejběžnějším přístupem je v dnešní době použití knihovny React Testing Library ve spojení s Jestem . Filozofie této knihovny je jasná: testovat komponenty stejně jako by je testoval uživatel , bez ohledu na interní implementační detaily.

Místo kontroly vnitřního stavu komponenty se zaměřuje na dotazování DOMu na viditelný text, roli přístupnosti nebo přidružené tagy, což zase podporuje osvědčené postupy přístupnosti.

Typy dotazů: getBy, queryBy a findBy

Knihovna React Testing Library nabízí různé typy funkcí pro vyhledávání prvků v renderovaném DOMu, obvykle prostřednictvím objektu screen :

  • dostat se…: vyhledat prvek a Pokud ho nemůže najít, vyhodí chybu.To je to, co chcete, když prvek musí existovat, aby test prošel.
  • dotazOd…: provede stejné vyhledávání, ale vrací null Pokud něco neexistuje, aniž by se tím prolomil test. Užitečné pro ověření, zda něco neexistuje.
  • najítOd…stejné jako getBy, ale orientované na asynchronní operaceVrací promise a čeká na zobrazení elementu v DOMu po HTTP požadavku, časovém limitu atd.

Tyto varianty umožňují pokrýt jak synchronní scénáře (prvky, které musí být přítomny od začátku), tak asynchronní scénáře (obsah, který dorazí po volání API nebo interakci uživatele).

Doporučené dotazy pro nalezení prvků

Oficiální dokumentace Testovací knihovny navrhuje pořadí preferencí pro dotazy, které se vždy snaží napodobit, jak uživatel vnímá rozhraní :

  1. získatRolí (s možností nameToto je nejsémantičtější dotaz, protože vyhledává prvky podle jejich přístupné role (tlačítko, nadpis, textové pole atd.). Měl by být vaše první volba téměř vždy.
  2. získatByLabelTextideální pro pole formulářeUmožňuje vám najít vstupy a textové oblasti podle jejich přidruženého popisku, stejně jako by to udělala čtečka obrazovky.
  3. získatByPlaceholderText: užitečné, když je viditelný pouze jeden zástupný symbol, i když nenahrazuje správný popisek.
  4. získatByText: pro viditelný obsah v neinteraktivních prvcích: odstavcích, divech, rozpětích atd.
  5. získatByDisplayValue: velmi praktické pro předvyplněné vstupy, kontrola hodnoty, kterou vidí uživatel.
Excel s Pythonem
Související článek:
Excel s Pythonem: Integrace skriptů a automatizace analýzy

Kromě toho existují i ​​takzvané „sémantické dotazy“ :

  1. získatByAltText: vyhledává obrázky nebo jiné prvky s atributem alt, nezbytné pro přístupnost.
  2. získatByTitlespoléhá na atribut titleToto však čtečky obrazovky ne vždy přečtou.

Nakonec, jako poslední možnost, získat pomocí testovacího ID, který vyhledává prvky s atributem data-testid. Nejlépe je to vyhradit pro případy, kdy neexistuje jiný rozumný způsob, jak položku najít. (dynamický text, čistě dekorativní prvky atd.).

Synchronní vs. asynchronní testování v Jestu

V JavaScriptu se stále častěji pracuje s promisy, HTTP voláními a časovači a vaše testy se musí odpovídajícím způsobem přizpůsobit. Test je považován za asynchronní, když čeká na operace, které nejsou vyřešeny ve stejném taktu smyčky událostí.

Test je jednoznačně synchronní , když:

  • Nepoužívá asynchronní funkce ni await.
  • Nevolá asynchronní API. ani službám, které plní sliby.
  • Nezávisí to na setTimeout, setInterval nebo podobné.

Naproti tomu se jedná o asynchronní test , když:

  • Funkce test je označena async. a zaměstnat await.
  • Funguje s funkcemi, které vracejí sliby. (fetch, axios, HTTP služby atd.).
  • V knihovně pro testování Reactu, použijte metody findBy nebo wait čekat na změny v DOMu.

Klíčem je zajistit, aby Jest Trpělivě počkejte, až tyto operace skončí.Chcete-li to provést, můžete z testu vrátit promise, použít async/await nebo ve starších API použít callback. done který Jest vloží do testovací funkce.

Vytváření jednotkových testů s Jestem v UI komponentách

Pro ilustraci testování skutečných komponent si představte, že máte v Reactu tlačítko a několik složitějších komponent. Obvyklý přístup je vytvořit soubory jako Button.test.tsx nebo HomeComponent.spec.ts a použít Jest s příslušnou testovací knihovnou.

Typickým prvním případem je kontrola, zda se komponenta vykresluje se správným textem . Vykreslíte tlačítko pomocí knihovny React Testing Library, vyhledáte text „Click Me“ nebo něco podobného a ověříte, zda se tento element v dokumentu nachází, pomocí porovnávače, jako je toBeInTheDocument.

Dalším běžným vzorem je použití jest.fn() k vytváření falešných funkcí, které fungují jako obslužné rutiny událostí nebo zpětná volání. To umožňuje ověřit, zda byly volány, když uživatel klikne, změní vstup nebo provede určitou akci.

U složitějších komponent, jako jsou formuláře nebo modální okna, je velmi běžné připravit objekt obslužné rutiny s několika falešnými funkcemi pomocí jest.fn() , předat ho jako props a poté použít expect(handlers.something).toHaveBeenCalled() , aby se zajistilo, že logika události bude spuštěna, když nastane čas.

Můžete dokonce zkontrolovat složitější podmínky, například podle určitého státu (například nemovitost) currentState (z kontejneru) se zobrazí tlačítko s jedním nebo druhým textem. V těchto případech sestavíte komponentu s různými počátečními hodnotami a ověříte, zda se text nebo role tlačítek mění podle očekávání.

Základní konfigurace Jestu v projektech React s TypeScriptem

Pro použití Jestu v React aplikaci s TypeScriptem obvykle začíná pracovní postup zajištěním instalace Node.js a npm (nebo yarn) a základního React projektu (např. vytvořeného pomocí Create React App nebo Vite, adaptovaného pro TS).

V existujícím projektu je běžnou praxí instalovat během vývoje následující: Jest, @testing-library/react, @testing-library/jest-dom a typy Jest pro TypeScript . Po instalaci můžete vytvořit konfigurační soubor, například jest.config.js nebo jest.config.cjs, kde definujete prostředí, transformátor TypeScript a příslušné cesty.

V souboru package.json obvykle přidáte alespoň tyto skripty: "test": "jest --watch" pro spouštění testů v režimu pozorovatele během vývoje a "test:coverage": "jest --coverage" pro generování reportů o pokrytí a zobrazení částí kódu, kterých se s testy nedotýkáte, a pro jejich integraci do CI/CD pipelines můžete postupovat podle návodu k nastavení toku CI/CD s akcemi GitHubu.

Jest lze ve výchozím nastavení nakonfigurovat tak, aby vyhledával soubory, jejichž název končí na .test.tsx nebo .spec.tsx (v případě Reactu s TypeScriptem), což značně zjednodušuje organizaci: testy umístíte vedle komponent nebo do konkrétní složky tests a Jest se postará o jejich nalezení.

Ruční integrace Jestu do Angular projektů

Historicky se testování v Angularu spoléhalo na Jasmine a Karmu , které mnozí považují za pomalé a nepříliš uživatelsky přívětivé pro integrace CI/CD. Zatímco experimentální možnosti použití Jestu byly zavedeny s Angularem 16, manuální přístup zůstává nejspolehlivějším z hlediska stability.

V nedávném projektu Angular (například vytvořeném pomocí Angular CLI 17) typický proces přechodu na Jest obvykle probíhá takto:

  • Vytvořte projekt s ng new project-test-jest a konfiguraci, kterou potřebujete.
  • Odinstalujte Karmu a Jasmínu s npm, odstraňování balíčků jako karma, jasmine-core a další související oddělení.
  • Odebrat z angular.json Sekce konfigurace testů založených na Karmě, protože ji nebudete používat.
  • Nainstalujte Jest a jest-preset-angular s npm install jest jest-preset-angular @types/jest --save-dev.
  • Aktualizujte skripty v souboru package.json takže „test“ spouští Jest místo ng testa přidejte skript „pokrytí“, který se spustí jest --coverage.
  • Upravit soubor tsconfig.spec.json takže se typy mění z Jasmine na Jest, což naznačuje "types":

Dále je třeba vytvořit soubor jest.config.js v kořenovém adresáři projektu, obvykle s využitím jest-preset-angular jako vodítka . Tam definujete věci jako testovací kořenový adresář, cestu k instalačnímu souboru, aliasy modulů (moduleNameMapper) a které soubory se započítávají do pokrytí.

Nakonec přidáte soubor src/setup-jest.ts , který importuje 'jest-preset-angular/setup-jest' a připraví prostředí Angularu pro správné fungování v Jestu, včetně JSDOM a dalších funkcí.

Příklady testování v Angularu s Jestem: komponenty a služby

V Angularu se testy komponent obvykle spoléhají na TestBed pro připojení komponenty v rámci testovacího modulu, vkládání služeb a zpracování cyklu detekce změn.

Například si představte Domovská stránkaKomponenta který má vlastnosti jako například title, count, isVisible y dataa že v jeho ngOnInit požaduje data z SampleService. předKaždou Obvykle bych nakonfiguroval TestBed s potřebným modulem nebo importy, zaregistroval službu a vytvořil komponentní fixture.

Poměrně základní první test by jednoduše vypadal jako `expect(component).toBeTruthy()` , aby se zajistilo, že komponenta bude vytvořena bez chyb. I když se to může zdát triviální, pomáhá detekovat problémy s konfigurací nebo nefunkční závislosti.

Pak můžete otestovat interakce uživatele s tlačítky, která zvyšují hodnotu čítače nebo přepínají booleovskou hodnotu viditelnosti. S fixture.debugElement.query(By.css('.class')) Najdete tlačítka, spouštíte události pomocí triggerEventHandler('click', null) a ověříte, že se vlastnosti komponenty po volání změnily podle očekávání fixture.detectChanges().

Pro služby Angularu, které volají skutečná API, je nezbytný pár HttpClientTestingModule a HttpTestingController . Je konfigurován v metodě `beforeEach`, vkládá se služba a kontroler a po každém testu se volá ` httpMock.verify()` , aby se zajistilo, že nezůstanou žádné čekající požadavky.

Typický test HTTP služby by se mohl přihlásit k odběru service.getPokemon('pikachu'), zkontrolujte to Kontroler testování protokolu Http přijmout požadavek GET na správnou URL a odpovědět req.flush(mockPokemon)V assercích je ověřeno, že data vrácená předplatiteli odpovídají simulované verzi.

Testování momentek a zakázkové transformátory

Jest vám také umožňuje dělat testování snímkůTo je u komponent React velmi běžné. Myšlenka je jednoduchá: vykreslíte komponentu (například pomocí react-test-renderer), uložíte jeho výstup do souboru snímku a v budoucích spuštěních porovnáte vykreslený výsledek s tímto souborem.

Když se součástka záměrně změní, můžete aktualizovat snímek s příkazem jako jest -uPokud byl rozdíl neočekávaný, test selže a budete muset zkontrolovat, co přesně se ve vykresleném výstupu změnilo.

Excel s Pythonem
Související článek:
Excel s Pythonem: Integrace skriptů a automatizace analýzy

V Reactu 16+ a knihovnách jako Enzyme se při simulaci určitých komponent můžete setkat s varováními v konzoli kvůli způsobu, jakým React ověřuje typy prvků. Mezi některá řešení patří vykreslování jako prostý text, použití vlastních prvků (popisky s pomlčkami a malými písmeny), spoléhání se na react-test-renderer nebo v extrémních případech zakázání určitých varování v konfiguraci Jestu.

Pokud váš projekt vyžaduje pokročilejší transformaci kódu, můžete také definovat vlastní transformátory v žertu. Místo pouhého použití babel-jest, můžete se uchýlit k @babel/core y babel-preset-jestkonfigurace klíče Jest „transform“ pro zpracování souborů s vlastními pravidly.

Nejlepší postupy při psaní jednotkových testů s Jestem

Abyste zajistili, že vaše testy budou skutečně užitečné a nebudou zátěží, je vhodné dodržovat několik jednoduchých pokynů, které se časem stanou téměř instinktivními:

  • Každý test se zaměřte na jednu věc.Specifické chování, jasný scénář. Díky tomu jsou snáze pochopitelné a udržovatelné.
  • Používejte expresivní popisy testůMěly by vysvětlovat, co daná funkcionalita dělá, ne jen opakovat název metody. Když test selže, zpráva by měla dávat smysl vám a vašemu týmu.
  • Provádějte testy nezávisle na sobě.Neměly by záviset na pořadí provedení ani na stavu, který zanechaly ostatní. Každý test by měl být možné spustit izolovaně.
  • Využijte beforeEach a afterEach znovu použít běžné konfigurace a po každém testu vyčistit zdroje nebo simulace.
  • Spoléhejte se na falešné a špiony izolovat externí závislosti (API, globální služby) a zaměřit se na logiku, kterou skutečně chcete ověřit.
  • Nezapomeňte na okrajové případy a chybyNetestujte pouze cestu k úspěchu; zahrňte i vzácné vstupy, nesprávné typy, chyby serveru a prázdné stavy.

Jakmile spustíte Jest s coverem (například pomocí pokrytí běhu npm), získáte adresář krytí s vysoce vizuálně zpracovanou HTML zprávou, která ukazuje, které soubory a řádky byly v testech provedeny. Otevírání coverage/lcov-report/index.html Můžete procházet soubor po souboru, což je ideální pro detekci tmavé oblasti vaší aplikace které by měly být pokryty.

Celý tento ekosystém Jestu, knihovny pro testování Reactu, jest-preset-angular, linterů a nástrojů pro coverage má v konečném důsledku poměrně jasný cíl: umožnit vám s jistotou měnit frontend, bez neustálého strachu z narušení uživatelského prostředí . Pokud jsou vaše testy dobře zaměřené, odrážejí, jak se aplikace skutečně používá, a nejsou vázány na interní detaily, stanou se záchranným lanem pro vaše projekty a pevným základem, na kterém můžete klidně vyvíjet svůj kód, a to i ve velkých týmech s častým nasazením.


Přidat jako preferovaný zdroj v Googlu