Intro to React Component Driver
Prezentacija Praktikantams

Table of Contents

1. React Component Driver

(╯°□°)╯︵ ┻━┻

2. Agenda

  • Istorija
  • Demo: Read Test Renderer
  • Demo: React Component Driver ir TDD
  • Ateities Vizija

3. Kas yra React Component Driver?

  • React Test Renderer apvalkalas.
  • Įrankių rinkinys leidžiantis analizuoti komponentų medį.
    • Konstravimas: render, renderComponent, …
    • Užklausos: filterBy, getTextNodes, …
  • Test Driver konvencija.
    • Paslepia komplikuotą konstravimą, manipuliavimą.
    • Pasakoja istoriją.

4. Panašūs įrankiai

5. Istorija

commit 93e02b2044d3f82ac7526449ec72ca7acd088840
Author: Donatas Petrauskas <donatasp@wix.com>
Date:   Mon Nov 21 16:17:19 2016 +0200

  Try to include custom built testkit.

6. Ko nedaro React Component Driver

  • Nevykdo native kodo. Tam skirtas Detox.
  • Nepalengvina testų rašymo.

7. Demo: React Test Renderer

  • Importavimas
  • Renderer objektas
  • Komponentų medis
  • Komponento evoliucija

8. Komponento Evoliucija

function Counter() {
  const [count, setCount] = React.useState(0);
  return (<button onClick={() => setCount(count + 1)}>Count is {count}</button>);
}

9. Demo: React Component Driver

  • Užklausos
  • ComponentDriver

10. Ateities Vizija

11. Dokumentacija

12. REPL

babel > const React = require('react')
undefined
babel > const {create} = require('react-test-renderer')
undefined
babel > const pp = (x) => console.log(JSON.stringify(x, null, 2))
undefined
babel > create(<div />).toJSON()
{ type: 'div', props: {}, children: null }
babel > create(<div id="app" />).toJSON()
{ type: 'div', props: { id: 'app' }, children: null }
babel > create(<div>Hello, World!</div>).toJSON()
{ type: 'div', props: {}, children: [ 'Hello, World!' ] }
babel > pp(create(<div><span>Hello, World!</span><button/></div>).toJSON())
{
  "type": "div",
  "props": {},
  "children": [
    {
      "type": "span",
      "props": {},
      "children": [
        "Hello, World!"
      ]
    },
    {
      "type": "button",
      "props": {},
      "children": null
    }
  ]
}
undefined
babel > const onClick = () => console.log('Hello!')
undefined
babel > const button = create(<button onClick={onClick}>Click Me!</button>).toJSON()
undefined
babel > button.props.onClick()
Hello!
undefined
babel > function Counter() {
  const [count, setCount] = React.useState(0);
  return (<button onClick={() => setCount(count + 1)}>Count is {count}</button>);
}
undefined
babel > const renderer = create(<Counter />)
undefined
babel > renderer.toJSON()
{
  type: 'button',
  props: { onClick: [Function: onClick] },
  children: [ 'Count is ', '0' ]
}
babel > renderer.toJSON().props.onClick()
undefined
babel > renderer.toJSON()
{
  type: 'button',
  props: { onClick: [Function: onClick] },
  children: [ 'Count is ', '1' ]
}
babel > const RCD = require('react-component-driver')
undefined
babel > RCD
{
  withContext: [Function: withContext],
  ComponentDriver: [Function: ComponentDriver],
  componentDriver: [Function: factory],
  render: [Function: render],
  renderComponent: [Function: renderComponent],
  toJSON: [Function: toJSON],
  filterBy: [Function: filterBy],
  filterByTestID: [Function: filterByTestID],
  filterByType: [Function: filterByType],
  getTextNodes: [Function: getTextNodes]
}
babel > const {filterByTestID, filterBy, getTextNodes, renderComponent, toJSON, ComponentDriver} = RCD
undefined
babel > renderComponent(Counter, {}).toJSON()
{
  type: 'button',
  props: { onClick: [Function: onClick] },
  children: [ 'Count is ', '0' ]
}
babel > toJSON(renderComponent(Counter, {}))
{
  type: 'button',
  props: { onClick: [Function] },
  children: [ 'Count is ', '0' ]
}
babel > function Counter() {
  const [count, setCount] = React.useState(0);
  return (
    <div>
      <div testID="COUNT">{count}</div>
      <button testID="COUNTER_BUTTON" onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}
undefined
babel > const r = renderComponent(Counter, {})
undefined
babel > const x = toJSON(r)
undefined
babel > pp(x)
{
  "type": "div",
  "props": {},
  "children": [
    "       ",
    {
      "type": "div",
      "props": {
        "testID": "COUNT"
      },
      "children": [
        "0"
      ]
    },
    "       ",
    {
      "type": "button",
      "props": {
        "testID": "COUNTER_BUTTON"
      },
      "children": [
        "+"
      ]
    },
    "     "
  ]
}
undefined
babel > filterByTestID('COUNT', x)
[ { type: 'div', props: { testID: 'COUNT' }, children: [ '0' ] } ]
babel > filterByTestID('X', x)
[]
babel > getTextNodes(filterByTestID('COUNT', x))
[ '0' ]
babel > filterByTestID('COUNTER_BUTTON', x)[0].props.onClick()
undefined
babel > pp(filterByTestID('COUNT', toJSON(r)))
[
  {
    "type": "div",
    "props": {
      "testID": "COUNT"
    },
    "children": [
      "1"
    ]
  }
]
undefined
babel > const CounterDriver = class extends ComponentDriver {
  constructor() {
    super(Counter);
  }

  clickPlusButton() {
    this.getByID('COUNTER_BUTTON').props.onClick();
    return this;
  }

  getCount() {
    return this.getByID('COUNT').children[0];
  }
}
undefined
babel > new CounterDriver().clickPlusButton().clickPlusButton().getCount()
'2'
babel >