{"id":231588,"date":"2023-01-10T15:30:00","date_gmt":"2023-01-10T12:30:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=231588"},"modified":"2022-12-25T18:54:39","modified_gmt":"2022-12-25T15:54:39","slug":"proste-testy-jednostkowe-javascript-w-wordpressie-z-jest","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/proste-testy-jednostkowe-javascript-w-wordpressie-z-jest\/","title":{"rendered":"Proste testy jednostkowe JavaScript w WordPressie z Jest"},"content":{"rendered":"\n<p>WordPress ma d\u0142ug\u0105 histori\u0119 test\u00f3w jednostkowych swojego kodu PHP. Jednak pisanie test\u00f3w jednostkowych JavaScript i test\u00f3w integracyjnych dla kodu w motywach i wtyczkach nie ma takiego samego statusu. Zobaczmy, jak przetestowa\u0107 JavaScript w naszych wtyczkach i motywach WordPress za pomoc\u0105 Jest.<\/p>\n<p>Oto tre\u015b\u0107, kt\u00f3r\u0105 om\u00f3wimy w tym artykule:<\/p>\n<h2>Testy jednostkowe JavaScript w WordPress<\/h2>\n<p>Po co wi\u0119c pisa\u0107 testy jednostkowe i testy integracyjne? \u015awietnie zapewniaj\u0105, \u017ce funkcja, metoda klasy, a nawet komponent React robi\u0105 to, co powinny. Pomaga wykrywa\u0107 b\u0142\u0119dy w kodzie, a tak\u017ce pomaga zachowa\u0107 integralno\u015b\u0107, gdy zmiany zostan\u0105 p\u00f3\u017aniej wprowadzone w kodzie, sprawdzaj\u0105c, czy po aktualizacji nadal dzia\u0142a zgodnie z przeznaczeniem.<\/p>\n<p><a href=\"https:\/\/startfunction.com\/category\/wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Wtyczki i motywy WordPress<\/a> s\u0105 w wi\u0119kszo\u015bci napisane w PHP i mog\u0105 u\u017cywa\u0107 pakietu PHPUnit do przeprowadzania test\u00f3w, tworzenia asercji, tworzenia funkcji i nie tylko. Podr\u0119cznik zawiera nawet sekcj\u0119 wyja\u015bniaj\u0105c\u0105, jak szybko <a href=\"https:\/\/make.wordpress.org\/cli\/handbook\/plugin-unit-tests\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">skonfigurowa\u0107 testy jednostkowe za pomoc\u0105 WP-CLI<\/a>.<\/p>\n<p>Je\u015bli chodzi o JavaScript, w Podr\u0119czniku znajduje si\u0119 strona o <a href=\"https:\/\/make.wordpress.org\/core\/handbook\/testing\/automated-testing\/qunit\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">uruchamianiu test\u00f3w QUnit<\/a>, chocia\u017c bardziej chodzi o testowanie kodu JavaScript w rdzeniu WordPressa.<\/p>\n<p>Chocia\u017c \u017cadna z tych rzeczy nie jest ustandaryzowana dla JavaScript w WordPress, mo\u017cemy pisa\u0107 \u015bwietne testy jednostkowe za pomoc\u0105 zestawu testowego Jest. W tym artykule dowiemy si\u0119, jak pisa\u0107 testy jednostkowe JavaScript dla przyk\u0142adowej wtyczki, kt\u00f3ra \u0142aduje 5 post\u00f3w przez WP REST API za pomoc\u0105 <code>fetch<\/code>funkcji z JavaScript i renderuje je w okre\u015blonym elemencie DOM na stronie.<\/p>\n<h2>Korzy\u015bci z u\u017cywania Jest do test\u00f3w jednostkowych JavaScript w WordPress<\/h2>\n<p>W przesz\u0142o\u015bci pisanie test\u00f3w jednostkowych JavaScript wi\u0105za\u0142o si\u0119 z konfiguracj\u0105 Mocha do uruchamiania test\u00f3w, Chai do tworzenia asercji, a Sinon do symulowania funkcji i ich szpiegowania. Chocia\u017c oferuj\u0105 du\u017c\u0105 elastyczno\u015b\u0107, praca z trzema pakietami jest znacznie bardziej skomplikowana ni\u017c z jednym. <a href=\"https:\/\/jestjs.io\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Jest<\/a> to wszystko w jednym pakiecie:<\/p>\n<ul>\n<li>mo\u017cesz uruchamia\u0107 testy deklaruj\u0105c je za pomoc\u0105 <code>describe<\/code>i <code>it<\/code>lub<code>test<\/code><\/li>\n<li>mo\u017cesz dokonywa\u0107 asercji za pomoc\u0105 <code>expect<\/code>i <code>toBe<\/code>i <code>toHaveLength<\/code>wielu innych<\/li>\n<li>mo\u017cesz kpi\u0107 z funkcji i je szpiegowa\u0107, a jest na to wiele sposob\u00f3w<\/li>\n<\/ul>\n<h3>Przed przej\u015bciem dalej<\/h3>\n<p>Aby ten artyku\u0142 koncentrowa\u0142 si\u0119 na testowaniu za pomoc\u0105 Jest, istnieje dodatkowa konfiguracja zewn\u0119trzna w stosunku do procesu testowania, taka jak Babel lub Webpack, kt\u00f3ra nie zostanie tutaj om\u00f3wiona. Wszystko to mo\u017cna znale\u017a\u0107 w <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">repozytorium WP Jest Tests<\/a>, kt\u00f3re towarzyszy temu artyku\u0142owi. Aby zachowa\u0107 kontekst, ka\u017cda sekcja b\u0119dzie zawiera\u0107 link do jednego z odpowiednich plik\u00f3w, kt\u00f3re napiszemy.<\/p>\n<h2>Przegl\u0105d strony PHP<\/h2>\n<p>Przyk\u0142adowa <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/wp-jest-tests.php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">wtyczka PHP<\/a>, kt\u00f3rej u\u017cyjemy do nauki pisania test\u00f3w jednostkowych JavaScript, jest do\u015b\u0107 standardowa. Jedyne interesuj\u0105ce wiersze to te, w kt\u00f3rych umieszczamy w kolejce nasz plik JavaScript i dodajemy skrypt inline, kt\u00f3ry przekazuje do niego zmienne:<\/p>\n<pre><code>$initial_state = rawurlencode( wp_json_encode( array(\n    'restUrl' =&gt; esc_url_raw( rest_url() ),\n    'posts'   =&gt; 5,)) );\nwp_enqueue_script( \n    'wp-jest-tests',\n    plugins_url( 'front.js', __FILE__ ),\n    array(),\n    $plugin_version,\n    true\n);\nwp_add_inline_script(\n    'wp-jest-tests',\n    'window.wpJestTests = JSON.parse(decodeURIComponent(\"'. $initial_state. '\"));',\n    'before'\n);<\/code><\/pre>\n<p>Po zaszyfrowaniu naszego pliku JavaScript dodajemy zmienn\u0105 globaln\u0105 <code>wpJestTests<\/code>z <code>wp_add_inline_script()<\/code>. Ta zmienna jest szczeg\u00f3lnie interesuj\u0105ca i trudna w obs\u0142udze, poniewa\u017c jest zewn\u0119trzna w stosunku do naszego pliku JavaScript i b\u0119dziemy musieli j\u0105 wy\u015bmiewa\u0107 w naszych testach.<\/p>\n<h2>Skonfiguruj testy Jest<\/h2>\n<p>Najpierw musimy zainicjowa\u0107 <code>npm<\/code>nasz projekt wtyczki, aby m\u00f3c z nim zainstalowa\u0107 Jest. Przejd\u017a w wierszu polece\u0144 do folderu wtyczek i uruchom:<\/p>\n<p><code>npm init<\/code>i przejd\u017a przez seri\u0119 podpowiedzi tutaj<\/p>\n<p>Edytuj utworzony plik <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/package.json\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">package.json<\/a> i dodaj nowy wpis, aby uruchomi\u0107 nasze testy w <code>scripts<\/code>sekcji:<\/p>\n<p><code>\"test\": \"jest\"<\/code><\/p>\n<p>B\u0119dzie to polecenie, kt\u00f3rego u\u017cyjemy, aby powiedzie\u0107 Jest, aby uruchomi\u0142 nasze testy jednostkowe JavaScript. Jest to jednorazowe uruchomienie, ale Jest r\u00f3wnie\u017c obs\u0142uguje ogl\u0105danie plik\u00f3w, wi\u0119c mo\u017cesz wprowadzi\u0107 dodatkowy:<\/p>\n<p><code>\"test-watch\": \"jest --watch\"<\/code><\/p>\n<p>Teraz zainstaluj Jest jako zale\u017cno\u015b\u0107 programistyczn\u0105, uruchamiaj\u0105c<\/p>\n<p><code>npm install -D jest<\/code><\/p>\n<p>Podczas instalacji utw\u00f3rz plik o nazwie <code>jest.config.js<\/code>. To utrzyma ca\u0142\u0105 niezb\u0119dn\u0105 konfiguracj\u0119. Dodaj nast\u0119puj\u0105ce informacje:<\/p>\n<pre><code>module.exports = {\n    verbose: true,\n    setupFiles: [\n        '\/__mocks__\/globals.js'\n    ],\n    moduleNameMapper: {\n        '.(css|less|sass|scss)$': '\/__mocks__\/styleMock.js'\n   }\n};<\/code><\/pre>\n<p>Przyjrzyjmy si\u0119 ka\u017cdemu z nich:<\/p>\n<ul>\n<li><code>verbose<\/code>: wskazuje, czy ka\u017cdy indywidualny test powinien by\u0107 raportowany podczas przebiegu. Po wykonaniu wszystkie b\u0142\u0119dy b\u0119d\u0105 nadal wy\u015bwietlane na dole. Zauwa\u017c, \u017ce je\u015bli uruchomiony jest tylko jeden plik testowy, domy\u015blnie jest to <code>true<\/code>.<\/li>\n<li><code>setupFiles<\/code>: lista \u015bcie\u017cek do modu\u0142\u00f3w, kt\u00f3re uruchamiaj\u0105 kod w celu skonfigurowania lub skonfigurowania \u015brodowiska testowego. Ka\u017cdy plik setupFile zostanie uruchomiony raz na plik testowy. Poniewa\u017c ka\u017cdy test dzia\u0142a we w\u0142asnym \u015brodowisku, skrypty te zostan\u0105 wykonane w \u015brodowisku testowym bezpo\u015brednio przed wykonaniem samego kodu testowego. U\u017cyjemy tego do deklarowania zmiennych globalnych renderowanych przez PHP i WordPress za pomoc\u0105 polece\u0144 takich jak <code>wp_add_inline_script<\/code>lub <code>wp_localize_script<\/code>.<\/li>\n<li><code>moduleNameMapper<\/code>: jest to mapa od wyra\u017ce\u0144 regularnych do nazw modu\u0142\u00f3w (lub tablic nazw modu\u0142\u00f3w), kt\u00f3ra pozwala na zablokowanie zasob\u00f3w statycznych, takich jak obrazy lub style za pomoc\u0105 pojedynczego modu\u0142u.<\/li>\n<\/ul>\n<p>Na pewno zauwa\u017cy\u0142e\u015b odniesienie: jest to specjalny token, kt\u00f3ry jest zast\u0119powany przez Jest z korzeniem twojego projektu, kt\u00f3rym zwykle jest lokalizacja twojego <code>package.json<\/code>.<\/p>\n<p>Om\u00f3wimy szczeg\u00f3\u0142owo kolejne dwie sekcje, ale najpierw utw\u00f3rz folder i te dwa pliki, o kt\u00f3rych mowa powy\u017cej:<\/p>\n<ul>\n<li>utw\u00f3rz folder o nazwie<code>__mocks__<\/code><\/li>\n<li>wewn\u0105trz folderu utw\u00f3rz pliki <code>styleMock.js<\/code>i<code>globals.js<\/code><\/li>\n<\/ul>\n<h2>Import mock\u00f3w do test\u00f3w Jest<\/h2>\n<p>Je\u015bli, tak jak ta wtyczka, u\u017cywasz Webpacka do kompilacji wszystkiego, w tym styl\u00f3w, i importujesz <code>.scss<\/code>plik w <code>.js<\/code>pliku:<\/p>\n<pre><code>import '.\/main.scss';<\/code><\/pre>\n<p>musisz u\u017cy\u0107 <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/__mocks__\/styleMock.js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">styleMock.js<\/a>, aby mockowa\u0107 pliki SASS podczas importowania ich do naszego pliku JavaScript, w przeciwnym razie Jest zawieszony, poniewa\u017c nie b\u0119dzie w stanie rozwi\u0105za\u0107 modu\u0142u. Nie potrzebujesz wiele do tego pliku, po prostu dodaj<\/p>\n<p>Jest u\u017cyje tej makiety za ka\u017cdym razem, gdy znajdzie <code>.scss<\/code>import i zmapuje je do makiety, co pozwoli ci przej\u015b\u0107 do przodu z testami bez zwracania uwagi na style.<\/p>\n<h2>Skonfiguruj globalne dla Jest<\/h2>\n<p>Popracujmy teraz nad plikiem <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/__mocks__\/globals.js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">globals.js<\/a>. Jedn\u0105 z zalet u\u017cywania Jest jest to, \u017ce jest ju\u017c dostarczany z ju\u017c skonfigurowan\u0105 <code>jsdom<\/code>, implementacj\u0105 standard\u00f3w sieciowych w czystym j\u0119zyku JavaScript, kt\u00f3ra symuluje \u015brodowisko DOM tak, jakby\u015b by\u0142 w przegl\u0105darce, i u\u017cyjemy jej do symulowania element\u00f3w DOM do naszych test\u00f3w.<\/p>\n<p>Utw\u00f3rz folder <code>__mocks__<\/code>i <code>globals.js<\/code>plik w nim. Dodaj to do pliku:<\/p>\n<pre><code>import { JSDOM } from 'jsdom';\nconst dom = new JSDOM();\nglobal.document = dom.window.document;\nglobal.window = dom.window;\nglobal.window.wpJestTests = undefined;<\/code><\/pre>\n<p>Spowoduje to deklaracj\u0119 i mock niekt\u00f3rych obiekt\u00f3w i metod, kt\u00f3rych b\u0119dziesz p\u00f3\u017aniej u\u017cywa\u0107 w swoich testach. Szczeg\u00f3lnie interesuj\u0105ca jest ta ostatnia<\/p>\n<pre><code>global.window.wpJestTests = undefined;<\/code><\/pre>\n<p>Jest to zmienna globalna, kt\u00f3r\u0105 napisali\u015bmy za pomoc\u0105 <code>wp_add_inline_script<\/code>. Musisz zakpi\u0107 j\u0105 jako zmienn\u0105 globaln\u0105, aby m\u00f3c u\u017cywa\u0107 jej w swoich testach.<\/p>\n<h2>Przegl\u0105d pliku JavaScript<\/h2>\n<p>Wtyczka WordPress zawiera pojedynczy plik JavaScript <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/src\/main.js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">main.js<\/a> w <code>\/src<\/code>folderze. Jest to p\u00f3\u017aniej transpilowane i wyprowadzane do <code>\/js\/front.js<\/code>pliku, kt\u00f3ry zostanie za\u0142adowany przez PHP. JavaScript \u0142aduje pi\u0119\u0107 post\u00f3w WordPress za <code>fetch<\/code>pomoc\u0105 standardowej funkcji JavaScript, za po\u015brednictwem interfejsu API WP REST i wstawia tytu\u0142 wraz z linkiem do posta do <code>div.entry-content<\/code>.<\/p>\n<p>Zamierzasz wyeksportowa\u0107 funkcj\u0119, kt\u00f3ra wykonuje ca\u0142\u0105 prac\u0119:<\/p>\n<pre><code>export const wpJestTestsInit =() =&gt; {<\/code><\/pre>\n<p>wi\u0119c mo\u017cesz go u\u017cywa\u0107 w swoich testach w Jest.<\/p>\n<h2>Nareszcie pisanie test\u00f3w jednostkowych JavaScript za pomoc\u0105 Jest!<\/h2>\n<p>Teraz mo\u017cesz zacz\u0105\u0107 pisa\u0107 testy! Testy mo\u017cna znale\u017a\u0107 na wiele sposob\u00f3w:<\/p>\n<ul>\n<li>je\u015bli nazwa pliku to<code>test.js<\/code><\/li>\n<li>lub jest poprzedzony nazw\u0105 pliku, kt\u00f3ry testuje, na przyk\u0142ad<code>main.test.js<\/code><\/li>\n<li>je\u015bli s\u0105 to <code>.js<\/code>pliki znajduj\u0105ce si\u0119 w folderze o nazwie<code>__tests__<\/code><\/li>\n<\/ul>\n<p>Utw\u00f3rz <code>__tests__<\/code>folder, a wewn\u0105trz niego <code>front.test.js<\/code>. Mo\u017cesz zobaczy\u0107 <a href=\"https:\/\/github.com\/eliorivero\/wp-jest-tests\/blob\/master\/__tests__\/front.test.js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">gotowy plik JavaScript dla test\u00f3w Jest<\/a> w repozytorium towarzysz\u0105cym. Przejd\u017amy przez to blokami. Pierwsza linia importuje plik JS, kt\u00f3ry chcemy przetestowa\u0107:<\/p>\n<pre><code>import { wpJestTestsInit } from '..\/src\/main';<\/code><\/pre>\n<p>Nast\u0119pnie czy\u015bcimy wszystkie mocki, wi\u0119c nigdy nie uruchamiamy brudnych mock\u00f3w nios\u0105cych warto\u015bci z poprzednich test\u00f3w. Mo\u017ce to prowadzi\u0107 do b\u0142\u0119d\u00f3w, poniewa\u017c na przyk\u0142ad, je\u015bli \u015bledzimy, ile razy zosta\u0142a wywo\u0142ana funkcja, mo\u017cemy uzyska\u0107 niepoprawny odczyt, je\u015bli nie wyczy\u015bcimy makiety mi\u0119dzy testem a testem:<\/p>\n<pre><code>afterEach(() =&gt; {\n    jest.clearAllMocks();\n} );<\/code><\/pre>\n<p>Pierwszy test, kt\u00f3ry napiszemy, b\u0119dzie zawiera\u0142 podstawowe stwierdzenia, gdy pewne rzeczy zawiod\u0105. Na przyk\u0142ad, je\u015bli <code>wpJestTests<\/code>zmienna globalna, kt\u00f3r\u0105 pisali\u015bmy, <code>wp_add_inline_script<\/code>nie zosta\u0142a zapisana z jakiegokolwiek powodu:<\/p>\n<pre><code>describe( 'Initialization', () =&gt; {\n    test( 'if wpJestTests is undefined, nothing happens', () =&gt; {\n        expect( wpJestTestsInit() ).toBe( false );\n    } );\n\n    test( 'if .entry-content is missing, nothing happens', () =&gt; {\n        wpJestTests = { posts: 5 };\n        const mockQuerySelector = jest.spyOn( document, 'querySelector') .mockImplementation( () =&gt; undefined );\n        expect( wpJestTestsInit() ).toBe( false );\n        expect( mockQuerySelector ).toHaveBeenCalledTimes( 1 );\n    } );\n} );<\/code><\/pre>\n<p>W tym kodzie<\/p>\n<ul>\n<li><code>describe<\/code>tworzy grup\u0119 z\u0142o\u017con\u0105 z kilku powi\u0105zanych ze sob\u0105 test\u00f3w<\/li>\n<li><code>test<\/code>jest tym, co faktycznie wykonuje test<\/li>\n<li><code>expect<\/code>otacza nasz obiekt testowy, zapewniaj\u0105c dost\u0119p do wielu \u201edopasowa\u0144&quot;, kt\u00f3re pozwalaj\u0105 na wysuwanie r\u00f3\u017cnych twierdze\u0144 na temat jego zawarto\u015bci<\/li>\n<li><code>toBe<\/code>jest jednym z tych dopasowa\u0144. Jest zawiera wiele element\u00f3w <a href=\"https:\/\/jestjs.io\/docs\/en\/expect\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">dopasowuj\u0105cych<\/a>, a nawet inne mo\u017cna doda\u0107 za <a href=\"https:\/\/github.com\/jest-community\/jest-extended#jest-extended\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pomoc\u0105 pakietu innej<\/a> firmy .<\/li>\n<\/ul>\n<p>Pierwszy test niczego nie definiuje, <code>wpJestTests<\/code>wi\u0119c jego warto\u015b\u0107 b\u0119dzie taka, jak zdefiniowa\u0142e\u015b w <code>globals.js<\/code>. Poniewa\u017c jest to <code>undefined<\/code>, nie mo\u017cemy pracowa\u0107, wi\u0119c chcemy potwierdzi\u0107, \u017ce funkcja powraca bez robienia czegokolwiek.<\/p>\n<p>Drugi test definiuje <code>wpJestTests<\/code>i na\u015bladuje <code>document.querySelector<\/code>metod\u0119, kt\u00f3ra ma zosta\u0107 zwr\u00f3cona <code>undefined<\/code>, czyli to, co zwr\u00f3ci\u0142aby, gdyby nie mog\u0142a znale\u017a\u0107 elementu w DOM. W takim przypadku chcemy potwierdzi\u0107, \u017ce wracamy bez robienia czegokolwiek i \u017ce nasza funkcja mocking <code>document.querySelector<\/code>zosta\u0142a wywo\u0142ana raz.<\/p>\n<h2>Pr\u00f3bne pobieranie w testach Jest<\/h2>\n<p>Kolejny zestaw test\u00f3w zaczyna si\u0119 od<\/p>\n<pre><code>describe( 'Fetch posts', () =&gt; {<\/code><\/pre>\n<p>a wewn\u0105trz mamy kolejn\u0105 funkcj\u0119 burzenia:<\/p>\n<pre><code>afterAll( () =&gt; {\n    global.fetch.mockClear();\n    delete global.fetch;\n});<\/code><\/pre>\n<p>w przeciwie\u0144stwie do <code>afterEach<\/code>tego zostanie uruchomione po wykonaniu wszystkich test\u00f3w w tym <code>describe<\/code>bloku. Poniewa\u017c nasz plik JavaScript u\u017cywa <code>fetch<\/code>do \u0142adowania post\u00f3w, musimy sprawdzi\u0107, czy zosta\u0142 wywo\u0142any i zwr\u00f3ci\u0142 to, o co prosili\u015bmy, wi\u0119c zamierzamy zakpi\u0107 <code>fetch<\/code>funkcj\u0119:<\/p>\n<pre><code>global.fetch = jest.fn().mockImplementation(\n    () =&gt; Promise.resolve({\n        ok: true,\n        status: 200,\n        json: () =&gt; Promise.resolve( [\n            {\n                link: 'test-1',\n                title: { rendered: 'Post 1' }\n            },\n            {\n                link: 'test-2',\n                title: { rendered: 'Post 2' }\n            },\n            {\n                link: 'test-3',\n                title: { rendered: 'Post 3' }\n            },\n            {\n                link: 'test-4',\n                title: { rendered: 'Post 4' }\n            },\n            {\n                link: 'test-5',\n                title: { rendered: 'Post 5' }\n            },\n        ] ),\n    })\n);<\/code><\/pre>\n<p>Wy\u015bmiewamy pierwsz\u0105 obietnic\u0119, kt\u00f3ra dotyczy odpowiedzi, a drug\u0105 reprezentacj\u0119 danych w formacie JSON. Te dane s\u0105 podobne do tych, kt\u00f3re otrzymujemy z API WP REST. Bior\u0105c pod uwag\u0119, \u017ce nasz kod potrzebuje tylko tytu\u0142u i linku, kpimy z tego.<\/p>\n<h2>Test integracji JavaScript z Jest w asynchronicznym kodzie, kt\u00f3ry u\u017cywa fetch<\/h2>\n<p>Mo\u017cemy teraz napisa\u0107 test za pomoc\u0105 mocked <code>fetch<\/code>. Istnieje zasadnicza r\u00f3\u017cnica mi\u0119dzy tym testem a innymi testami jednostkowymi JavaScript: jest to test integracyjny. Poprzednie testy, kt\u00f3re tutaj om\u00f3wiono, po prostu zapewni\u0142y, \u017ce komponent dzia\u0142a dobrze. Sprawdzili\u015bmy, czy je\u015bli zmienna globalna stanu pocz\u0105tkowego nie zosta\u0142a zdefiniowana, nasz komponent nie b\u0119dzie renderowa\u0142 si\u0119. Jest to inne, poniewa\u017c zamierzamy przetestowa\u0107 dzia\u0142anie ca\u0142ego systemu, gdy zdefiniowana jest zmienna stanu pocz\u0105tkowego, uruchamiaj\u0105c w ten spos\u00f3b transakcj\u0119 danych, a na koniec wstawiaj\u0105c tytu\u0142y post\u00f3w wraz z linkami do dokumentu.<\/p>\n<p>Od samego pocz\u0105tku jest inaczej: funkcja anonimowa przekazana do <code>test<\/code>otrzymuje <code>done<\/code>parametr. W rzeczywisto\u015bci jest to funkcja, kt\u00f3ra zostanie wywo\u0142ana po zako\u0144czeniu testu. Jest czeka <code>done<\/code>na wywo\u0142anie przed zako\u0144czeniem testu. Je\u015bli <code>done<\/code>nigdy nie zostanie wywo\u0142any, test zako\u0144czy si\u0119 niepowodzeniem z b\u0142\u0119dem przekroczenia limitu czasu. Jest to dla nas interesuj\u0105ce, poniewa\u017c testujemy kod z udzia\u0142em <code>fetch<\/code>funkcji asynchronicznej.<\/p>\n<pre><code>test( 'if posts are fetch, inserts them', done =&gt; {\n    wpJestTests = { posts: 5 };\n    const mockClassListAdd = jest.fn();\n    const divElem = {\n        tagName: 'DIV',\n        classList: { add: mockClassListAdd },\n        innerHTML: ''\n    };\n    const mockQuerySelector = jest.spyOn( document, 'querySelector') .mockImplementation( () =&gt; divElem );\n\n    expect( wpJestTestsInit() ).toBe( true );\n\n    process.nextTick(() =&gt; {\n        expect( mockQuerySelector ).toHaveBeenCalledTimes( 1 );\n        expect( global.fetch ).toHaveBeenCalledTimes( 1 );\n        expect( mockClassListAdd ).toHaveBeenCalledTimes( 1 );\n        expect( divElem.innerHTML.match( \/test-[1-5]\/g ).length ).toBe( 5 );\n\n        done();\n    });\n} );<\/code><\/pre>\n<p>Globalny <code>wpJestTests<\/code>jest zdefiniowany, a nasz mocked <code>document.querySelector<\/code>teraz zwraca co\u015b, co przypomina element HTML, z parzyst\u0105 <code>classList<\/code>i jego <code>add<\/code>metod\u0105 potomn\u0105.<\/p>\n<p>Wzywamy <code>wpJestTestsInit<\/code>i oczekujemy, \u017ce zako\u0144czy si\u0119 to poprawnie. Teraz, poniewa\u017c jest <code>fetch<\/code>asynchroniczny, u\u017cyjemy <a href=\"https:\/\/nodejs.org\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Node.js<\/a>. In Node.js to kolejka, kt\u00f3ra zostanie uruchomiona po zako\u0144czeniu wszystkich zdarze\u0144 w bie\u017c\u0105cej p\u0119tli zdarze\u0144. To \u015bwietnie, poniewa\u017c wszystkie nasze obietnice zosta\u0142yby wtedy rozwi\u0105zane, co jest dok\u0142adnie tym, czego potrzebujemy do testowania tego kodu, kt\u00f3ry obejmuje .<code>process.nextTick<\/code><a href=\"https:\/\/nodejs.org\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external\"><\/a><code>nextTick``fetch<\/code><\/p>\n<p>Reszta to wi\u0119cej asercji, aby upewni\u0107 si\u0119, \u017ce <code>querySelector<\/code>znaleziono co\u015b do pracy, co <code>fetch<\/code>rzeczywi\u015bcie zosta\u0142o wywo\u0142ane, \u017ce klasa zosta\u0142a dodana do listy, a tytu\u0142y i linki naszych post\u00f3w zosta\u0142y wstawione w odpowiednim elemencie HTML. Gdy wszystko jest zrobione, wywo\u0142ujemy <code>done<\/code>i ko\u0144czymy nasz test asynchroniczny.<\/p>\n<h2>Uruchom testy Jest<\/h2>\n<p>Teraz mo\u017cesz pisa\u0107<\/p>\n<p><code>npm run test<\/code><\/p>\n<p>a Jest uruchomi testy jednostkowe JavaScript dla Twojej wtyczki WordPress<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157897-61e6c3c169e87.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-157897-61e6c3c169e87.png\" alt=\"Proste testy jednostkowe JavaScript w WordPressie z Jest\" ><\/a><\/p>\n<h2>Wniosek<\/h2>\n<p>So Jest to \u015bwietne i proste rozwi\u0105zanie do pisania test\u00f3w, kt\u00f3re obejmuj\u0105 kod JavaScript naszych wtyczek lub motyw\u00f3w WordPress. Ale jest wi\u0119cej. Je\u015bli piszemy aplikacj\u0119 React dla naszej wtyczki, by\u0107 mo\u017ce zechcemy dokona\u0107 asercji na jej temat. Jest te\u017c do pewnego stopnia pom\u00f3c, a je\u015bli potrzebujemy wi\u0119cej, mo\u017cemy doda\u0107 Enzyme do naszych narz\u0119dzi i zacz\u0105\u0107 pisa\u0107 z nim testy integracyjne.<\/p>\n<p>Prosz\u0119 podaruj!<\/p>\n<p>Je\u015bli uzna\u0142e\u015b to za przydatne, kup mi kaw\u0119 <img decoding=\"async\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Proste testy jednostkowe JavaScript w WordPressie z Jest\" \/>, abym m\u00f3g\u0142 nie zasn\u0105\u0107 i stworzy\u0107 dla Ciebie wi\u0119cej przydatnych samouczk\u00f3w!<\/p>\n<p>3,00 z\u0142<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/startfunction.com\" class=\"external external_icon\">startfunction.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Zapewnij stabilno\u015b\u0107 kodu JavaScript we wtyczce WordPress, pisz\u0105c testy jednostkowe JavaScript za pomoc\u0105 Jest.<\/p>\n","protected":false},"author":1,"featured_media":157898,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[721,732,897,752,1020,845,866],"tags":[1169],"class_list":["post-231588","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-javascript-7","category-kod","category-otwarte-zrodlo","category-przydatne-strony","category-samouczki","category-wordpress-7","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/231588","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=231588"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/231588\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/157898"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=231588"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=231588"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=231588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}