エンジニアスタンプラリー～フロントエンド編＃10

## 企画主旨
[Frontend Developer Roadmap](https://roadmap.sh/frontend)をひたすら巡回する企画 
詳しくは[こちら](https://qiita.com/tonchan1216/items/8d5f072cf769dfe1bc4f)

## 今回の実施内容
テストの実施
テストコードやテストツールの利用

## Testing your Apps

#### Jest
コンポーネントの単体テストをJestで実施。
日本語対応している公式サイト[Getting Started Jest](https://jestjs.io/docs/ja/getting-started)の手順通り導入。
謎に導入に詰まった。webpackを通さなくてもES6を変換するようにするのがミソらしい・・・。
テスト内容は、ただコンポーネントのスナップショットをとるだけにとどまる。

```json:.babelrc
{
  "env": {
    "test": {
      "presets": ["@babel/preset-env", "@babel/preset-react"],
      "plugins": [
        "transform-es2015-modules-commonjs"
      ]
    }
  }
}
```

```javascript:jest.config.js
module.exports = {
  transform: {
    '^.+\\.js$': '<rootDir>/node_modules/babel-jest'
  },
  moduleFileExtensions: ['js'],
  moduleNameMapper: {
    '^@app/(.+)': '<rootDir>/src/js/$1'
  },
  transformIgnorePatterns: ['<rootDir>/node_modules/']
};
```
```javascript:Footer.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import Footer from '../src/js/components/Footer';

describe('フッターコンポーネント', () => {
  it('Footerレンダリング', () => {
    const component = renderer.create(<Footer />);

    const tree = component.toJSON();
    expect(tree).toMatchSnapshot();
  });
});

```

#### Enzyme
ReactのComponentテストが書きやすくなるフレームワーク。
[Introduction/Enzyme](https://airbnb.io/enzyme/)をもとに、導入及びJestで作ったテストコードを修正していく。
スナップショットテスト以外にも、クリックイベントとかのテストパターンが簡単に追加可能。
カバレッジテストを100%に近づける楽しみ（なったとは言ってない）。

```javascript:App.test.js
describe('SkillStore', () => {
  it('Change input text', () => {
    const store = new SkillStore();
    store.changeText('skill 1');
    expect(store.inputText).toBe('skill 1');
  });
  it('Update text', () => {
    const store = new SkillStore();
    store.updateNews('news 1');
    expect(store.news).toBe('news 1');
  });
  it('Add skills', () => {
    const store = new SkillStore();
    store.inputText = 'skill 2';
    store.page = 'front';
    store.addSkill();
    expect(store.skill.front[store.skill.front.length - 1]).toBe('skill 2');
  });
  it('Add skills - no input', () => {
    const store = new SkillStore();
    const slillNum = store.skill.front.length;
    store.inputText = '';
    store.page = 'front';
    store.addSkill();
    expect(store.skill.front).toHaveLength(slillNum);
  });
  it('Toggle page', () => {
    const store = new SkillStore();
    store.togglePage('back');
    expect(store.page).toBe('back');
  });
});

describe('App component', () => {
  it('App 子コンポーネント', () => {
    const store = new SkillStore();
    const wrapper = mount(
      <Provider store={store}>
        <App />
      </Provider>
    );

    expect(wrapper.find(Header)).toHaveLength(1);
    expect(wrapper.find(Content)).toHaveLength(1);
    expect(wrapper.find(Footer)).toHaveLength(1);
  });
});

```

#### Cypress
ユーザの操作ベースで簡単にテストできるツール
[Writing Your First Test](https://docs.cypress.io/guides/getting-started/writing-your-first-test.html#Special-commands)に従って、一連の操作をイメージしてテストコードを作成。
書き方もJestと似ているところもあって、よき。

```javascript:ui_spec.js
describe('My First Test', () => {
  it('Add New Skill', () => {
    cy.visit('http://localhost:8080/');
    cy.get('.top-bar')
      .contains('バックエンド')
      .click();

    cy.get('.add-skill__textbox')
      .type('GO lang')
      .should('have.value', 'GO lang');

    cy.get('.add-skill__button').click();

    cy.get('.skill').contains('GO lang');
  });
```

## 成果物
いろんな目線でテストができることを学んだ。
そもそもテストがしやすいコードを書く、というのも意識する必要があるのかも。
https://github.com/tonchan1216/WDR-frontend/tree/v10