W tym tygodniu zakumplowałem się z mega inspirującym gościem - Kent'em C. Dodds'em. Wszystko za sprawą jego dwóch szkoleń, które przez tydzień były dostępne za free na FrontendMasters. Dzięki nim poznałem kilka nowych wzorców związanych z tworzeniem komponentów w React.js oraz utwierdziłem się w swoim przekonaniu dotyczącym pisania testów :) Ale to nie wszystko...w tygodniu wpadło jeszcze kilka mniejszych wskazówek, które na pewno wykorzystam. Zapraszam na Learning Log #3.

npm commands

Gdy zaczynałem swoją przygodę z programowaniem na topie był Grunt.js. Nieco później pojawił się Gulp.js. Ale koniec, końców wydaje mi się, że wygrały skrypty npm. Skrypty, które definiujemy w package.json. Ale nie o nich dzisiaj będzie mowa.

Wiedzieliście, że by default założone są skróty do podstawowych skryptów? Np. npm it jest równoważne npm install test. Co więcej - gdybyście popełnili literówkę w npm tst to odpali się...to o czym myśleliście npm test :)

Możecie też dodać gwiazdkę wybranemu pakietowi poprzez npm star react :)

Potrzebujecie dokumentację do pakietu ? Nie ma sprawy - odpalcie npm docs react a w przeglądarce otworzy Wam się strona https://reactjs.org/

Mała rzecz a jak mocno wpływa na nasz programistyczny warsztat - bezcenne.

Jeśli chcecie poznać więcej komend/skryptów odpalcie po prostu npm.

Usage: npm <command>

where <command> is one of:
    access, adduser, audit, bin, bugs, c, cache, ci, cit,
    completion, config, create, ddp, dedupe, deprecate,
    dist-tag, docs, doctor, edit, explore, get, help,
    help-search, hook, i, init, install, install-test, it, link,
    list, ln, login, logout, ls, outdated, owner, pack, ping,
    prefix, profile, prune, publish, rb, rebuild, repo, restart,
    root, run, run-script, s, se, search, set, shrinkwrap, star,
    stars, start, stop, t, team, test, token, tst, un,
    uninstall, unpublish, unstar, up, update, v, version, view,
    whoami

npm audit

Tydzień temu pisałem o podbiciu wersji node.js. Tym razem podbiłem wersję npm'a i przy odpaleniu npm install dostałem podsumowanie audytu:

[!] 195 vulnerabilities found [10019 packages audited]
    Severity: 193 Low | 1 High | 1 Critical
    Run `npm audit` for more detail

Myślę sobie WOW :) ... co więcej, po odpaleniu npm audit dostajemy listę pakietów, które zawierają potencjalne zagrożenia:

=== npm audit security report ===                        
                                                                                
# Run  npm install babel-core@6.26.3  to resolve 14 vulnerabilities
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ babel-core                                                   │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ babel-core > babel-generator > babel-types > lodash          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/577                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ babel-core                                                   │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ babel-core > babel-helpers > babel-template > babel-traverse │
│               │ > babel-types > lodash                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/577                       │
└───────────────┴──────────────────────────────────────────────────────────────┘

Jak widzicie dostajemy też wskazówki jak rozwiązać te problemy. W tym przypadku zainstalowanie babel-core@6.26.3 rozwiąże nam 14 problemów.

npm audit --fix

W tym tygodniu wyszła nowa wersja npm'a, która dodaje przełącznik --fix. Dzięki niemu możemy z automatu naprawić zależności jeśli spełniają warunki naszych sem-versji. MEGA :)

webpack web-assembly

DEMO: https://github.com/xtuc/c-webpack-demo

Myślę sobie HOW COOL IS THAT!!?? :)

form.elements

Jeśli dodawaliście attrybut ref do waszych elementów formularza, tylko po to, żeby później zawołać this.inputEl.value to jest na to lepszy sposób :) ... Ale najpierw old-approach:

import React, { Component } from "react";

class MyForm extends Component {

  onSubmit = (e) => {
    e.preventDefault();
    const username = this.usernameEl.value;
    const password = this.passwordEl.value;
    
    this.props.onSubmit({ username, password })
  }

  redner() {
    return (
      <form onSubmit={ this.onSubmit } >
         <input ref={ el => this.usernameEl = el } />
         <input ref={ el => this.passwordEl = el } />
         ...
      </form>
    );
  }
}

Teraz bez ref:

import React, { Component } from "react";

class MyForm extends Component {

  onSubmit = (e) => {
    e.preventDefault();
    const { username, password } = e.target.elements;
    
    this.props.onSubmit({ 
      username: username.value, 
      password: password.value 
    })
  }

  redner() {
    return (
      <form onSubmit={ this.onSubmit } >
         <input name="username" />
         <input name="password" />
         ...
      </form>
    );
  }
}

Delete all unnecessary refs ! :D

Advanced React Component Patterns

Tak jak wspomniałem we wstępie - w tym tygodniu na FrontendMasters dostępne były dwa kursy Kent'a C. Dodds'a. Jednym z nich jest Advanced React Component Patterns. Jest to nowsza wersja kursu dostępnego na egghead.io. Czym się różnią ? Nowy React.Context API + pytania z publiczności. Na egghead dostajecie wiedzę w pigułce ze starym context.API. Na FrontendMasters nagranie ze szkolenia z prawdziwymi ludźmi, którzy zadawali ciekawe pytania.

Kurs omawia takie wzorce jak:

  • Compound Components
  • Render prop pattern
  • Props collection
  • Props getters
  • State initializer
  • State controll props
  • HOC
  • Rendux

Wielka, wielka merytoryczna wartość. O niektórych patternach słyszałem, niektóre już wykorzystywałem świadomie a inne nieświadomie :D Teraz przynajmniej wiem jaką mają nazwę ;)

Jeśli nie zdążyliście na darmowy tydzień to na youtube znajdziecie szkolenie na ten sam temat poprowadzone w PayPal'u -- TUTAJ --

React-testing-library

O tym narzędziu głośno zrobiło się jakiś czas temu. Przynajmniej mój twitter o tym huczał ;) Podaczas drugiego kursu, który miałem okazję zobaczyć - dowiedziałem się dlaczego Kent zrezygnował z enzyme, na rzecz react-testing-library. Poznałem, też odpowiedź na pytanie dlaczego shallow rendering (tak mocno forsowany przez enzyme) jest zły! Nie powinniśmy mockować wszystkich sub-componentów, renderowanych przez nasz komponent. Ba...sprawdzanie czy przekazaliśmy odpowiednie propsy to nie wszystko. Co sprawia, że nasz komponent działa? Integracja! To, że wszystkie sub-komponenty działają wspólnie. Dlatego najlepiej renderować zawsze całość, zamiast korzystać z shallow renderingu. Jeżeli chcecie zamockować component, który wyczynia jakieś hocki-klocki z DOM'em to użyjcie jest.mock. Nie wiecie czym jest jest.mock? Zapraszam do następnego rozdziału :)

Jeśli nie udało wam się skorzystać z darmowego tygodnia na FrontendMasters to na youtube znajdziecie warsztat prowadzony w PayPal'u ;) -- TUTAJ --

jest.mock

Załóżmy, że chcemy przetestować czy nasz komponent prawidłowo woła metodę z api. Tyle, że tego api nie przekazujemy w propsach a importujemy z innego modułu:

import React, { Component } from "react";
import api from "utils/api";

class MyCmp extends Component {

  onClick = () => api.sendData();

  render() {
    return (
      <div onClick={ this.onClick } />
    );
  }
}

Ok...i jak to teraz przetestować ? Z pomocą przychodzi jest.mock:

import api from "utils/api";

jest.mock("utils/api", () => ({
   sendData: jest.fn()
});

test("calls api.sendData", () => {
    // Here render your component using enzyme/ReactDOM/react-testing-lib
    
    expect(api.sendData).toHaveBeenCalledTimes(1); // WTF !? How it works !?
});

No właśnie jak to działa ? Otóż działa to w ten sposób, że babel-jest wykonuje hoist'ing wszystkich wywołań jest.mock, więc nawet jeśli w teście wołamy import to nie importujemy docelowego modułu tylko zadeklarowany mock. HOW COOL IS THAT !? :D

Po dokładniejsze info odsyłam (a jakże) do repo Kent'a https://github.com/kentcdodds/how-jest-mocking-works/

Tak samo możecie zamockować sobie jakiś component:

jest.mock("components/awesome", () => (props) => <div>FAKE-AWESOME</div>");

To tyle w tym tygodniu :) Polecam profil Kent'a na: