yikegaya’s blog

仕事関連(Webエンジニア)と資産運用について書いてます

useEffect、useStateでhttpリクエストを飛ばしてrenderする時のテスト

useEffect、useStateでhttpリクエストを飛ばしてレスポンスの内容を元にテーブルの内容を描画する画面を書いていた。

で、レスポンスを元に表示した内容をテストしたかった。よくありそうな話だしすんなりいくだろう、、と思ったら思いの他苦戦したので作業内容メモ。

使っていたテストフレームワークはjestとenzyme。

まずenzymeでuseStateやHttpリクエストのmockを使ったやり方を探すがうまくいかず。

クラスコンポーネントであればsetStateして内容作ればそれでいいような気もしたけど、関数コンポーネントで同じようなやり方を探して試してもなかなかうまくいかず。

最終的に以下のスタックオーバフローを参考に書いた。

stackoverflow.com

大体こういう内容。

本体

const Index = () => {
  const [hoges, setHoges] = useState([]);

  useEffect(() => {
    async function fetchHoge() {
      const hoges = await axios.get<Hoge[]>(
        '/api/v1/hoge',
      );
      setHoge(hoges.data);
    }
    fetchHoges();
  }, []);
  return(
    <>
      <table>
        <thead>
          <tr>
            <th>hoge1</th>
            <th>hoge2</th>
            <th>hoge3</th>
          </tr>
        </thead>
        <tbody>
          {hoges.map((hoge, i) => (
            <tr key={i}>
              <td>{hoge.hoge_str1}</td>
              <td>{hoge.hoge_str1}</td>
              <td>{hoge.hoge_str1}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

テスト

  test('render table contents', async () => {
    const fake_params = [{hoge_str1: "hoge_str1",
                         hoge_str2_: "hoge_str2_",
                         hoge_str3: "hoge_str3"}]
    const axiosGetSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: fake_params });
    let component;
    await act(async () => {
      component = renderer.create(<Index ></Index>);
    });
    expect(axiosGetSpy).toBeCalledWith('/api/v1/hoge');
    expect(component.toJSON()).toMatchSnapshot();
    axiosGetSpy.mockRestore();
  });

jestのspyonmockResolvedValueOnceを使い。axiosのget関数をモックにする。これでuseEffectから呼ばれるget関数がモックになって、componentをrenderする時にテスト用paramの内容が表示される。

toMatchSnapshotで出力されたDOMの内容を見ても想定通りだったのでうまくいっていそう。

なんかReactのテストちゃんとやろうとするとハマるな。Railsのcapybara感覚でやってもすんなりいかないこともあるのでjestの公式ドキュメントくらいは目を通した方が良さそう。。

js側でPCとスマホ、タブレットの表示分ける

スマホタブレットで表示を変えるときにCSSで@media指定して制御するのはよくやるけど、要素の順番とか配置等ガッツリ見た目に変更足したい時があった。

CSSだとスマホの時に要素の並び替え変えるのはflex指定すればできたりするけどどうも綺麗にいかなかったのでJSで振り分けてみた。

CSSでよくやるやつ

@media screen and (mix-width: 768px) {
    // スマホ、タブレットのstyle指定
}

JS(Reactのrender内)

  if (window.matchMedia && window.matchMedia('(max-device-width: 768px)').matches) {
    // スマホ、タブレット表示
    return ()
  } else {
    // PC表示
    return ()
}

TypeScript+jest+enzymeでのテスト環境構築

Rails+webpacker+Reactのフロントにテストコードを導入した時のメモ。結構やることがあった。。

最近はReactのテスト環境の動向調べると、テストフレームワークjestにテストユーティリティツールのEnzymeの組み合わせがメジャーっぽいので素直に採用した。

入れたライブラリ

最初に実行したのが以下

yarn add --dev jest enzyme enzyme-adapter-react-16 jest-enzyme

それぞれ何かというと

ライブラリ名 内容
jest javascriptのテストフレームワーク。少し前はmochaが人気だったけど最近はこっちが主流らしい。ReactやGraphQLと同じFacebook
enzyme airbnbが作ったReactのテストユーティリティツール。
enzyme-adapter-react-16 enzymeをReactで使うために必要
jest-enzyme enzymeをjestで使うために必要

設定ファイル変更

ライブラリインストールしただけではダメでpackage.jsonの設定が必要らしいので設定していく。

まずjestのrootsを設定する。今回はRails内のapp/frontendにtsxファイルを置いていたのでテスト対象のパスと拡張子を設定。

package.json

  "devDependencies": {
   
  },
  "jest": {
    "roots": [
      "app/frontend"
    ],
    "moduleFileExtensions": [
      "js",
      "ts",
      "tsx",
      "jsx"
    ]
  },

あとyarn testでテストの実行できるようにscript追加。

  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }

TypeScript対応

ここテストコード書いてyarn testを実行してみる

内容はこんな感じ。テスト対象と同じパスに置いた。

app.test.tsx

import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import App from './app';

Enzyme.configure({ adapter: new Adapter() });

describe('view', () => {
  test('app component', () => {
    const wrapper = shallow(<App />);
    expect(wrapper).toMatchSnapshot();
  });
});

が、「syntax error: “interface is a reserved word in strict mode”」でテストが通らない。内容的に素のJavaScriptにはないinterfaceでエラーになっているのでjestがTypeScriptに対応していないっぽい。

https://jestjs.io/docs/ja/getting-started#typescript-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B

結局公式サイトにあるようにyarn add --dev babel-jest @babel/preset-typescriptしてbabel.config.jsのpresetsに追記することで解消した。

jestjs.io

presets: [
      "@babel/preset-typescript",

この状態で適当にtoMatchSnapshotマッチャでコードを書いて動かすと通った

VScodeの警告

これでyarn test が通るようにはなったけどなぜかVScodeが赤くなった。

Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.ts(2582)

警告通りにyarn add --dev @types/jestしてワークスペース追加しなおして解消。

これで他のマッチャでテスト書いても動く状態になった。

Rails+webpacker環境で「default is not a constructor」のエラーが出た時の対応

ビデオ通話機能を実装するためにskyway-js というライブラリをRails+webpacker+Reactのサービスにインストールしたときにエラーが出て軽くハマったのでメモ。

エラー内容

Rails+webpacker+Reactの環境でyarn add skyway-jsを実行。それをimportするところまではよかったが、公式ドキュメントに沿ってライブラリ内のPeerクラスをnewすると以下の画像のようにエラーになってハマった。

「default is not a constructor」とか言われてるけど実際node_modules以下にインストールされたコードを読むとちゃんとconstructor書いてあるぞ。。

TypeErrorなのでTypeScriptのconfigの問題かと思ったけどその方向で調べても分からず。

対応

原因特定するために手元で適当なReactアプリを作って同じようにyarn addすると問題なく動く →じゃRails特有(webpacker)の問題?と思い、rails/webpackerのgithub issueを漁る。で、以下のissueを見つける。

github.com

書いてある通りにbabel.config.jsにsourceType: 'unambiguous',を追記して解決した。

ライブラリがTypescriptで書かれていて、babelのコンパイルがうまくいっていなかったので、設定でチェックを緩くして解消できた。型チェックは緩くなってしまったけどこれしかしょうがなさそう。

babeljs.io

AWSソリューションアーキテクトアソシエイト合格できた

受かった。よかった。。

勉強方法

ハンズオンやったり本読んだりYoutubeAWS公式動画観たりもしたけど結局WEB問題集だけでも合格できたような気はする。

やったのはUdemyの講座2つを3周り、WEB問題集を2週。

Udemyの講座

これはセールの時なら1000円台で買える。2つ目の模擬試験は難易度は高いけどやっておいてよかった。

【SAA-C03版】これだけでOK! AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座 | Udemy

【SAA-C03版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問) | Udemy

WEB問題集

こっちは3880円払って60日間の有料プランに入った。他の合格体験記を読むとUdemyだけでも受かりそうな気はしたけど、試験代が15000円で落ちると痛いので保険として購入。問題が900問くらいあって勉強になった感があるので4000円の価値はあると思う。

Cloud License | AWS WEB問題集で学習しよう

その他教材


【AWS Black Belt Online Seminar】AWS Fargate

受けてみて

受験料と教材費でそこそこ出費もあったが(今フリーランスなので経費にはのせられるが会社の補助とかはない)勉強したおかげで以前は内容全くついていけなかったAWSの業務や話題にも大体キャッチアップできるようになった気がする。

ここからもっとAWS触ってクラウド案件も広く対応できる開発エンジニアになっていきたいな。。

AWSソリューションアーキテクトの模擬試験(非公式)買って解いてみた

別に業務で必要に迫られたわけではないんだけどなんとなくインフラの勉強がしたくなったのと久々に資格増やすのもありかと思い、AWSソリューションアーキテクトの勉強を再開してみた。

観察した範囲だともはや情報処理試験とかLPICとかに負けず認知率の高いIT資格になってる感があって勉強方法や合格体験記も溢れており、ググって諸々調べてみると今は書籍よりもUdemyの講座の方が良いらしい。

いつも通りセールで1000円代に下がるのを待って2つほど講座買ってみた。1つはハンズオン+模擬試験でもう1つは試験のマイナーな問題をまとめた試験。

www.udemy.com

www.udemy.com

やってみた感じ

ハンズオンは以前「手を動かしながら2週間で学ぶ AWS 基本から応用まで」という同じくUdemyの講座でやったことがあったので(こちらは2019/4/30に新規購入できなくなっていた)既視感があるところは流しつつハンズオンの講座を受けて、そのあとに問題を一通り解いてみる。

講座のくだりは他のクラウドサービスとの比較だったりと試験対策からはみ出した部分もあって勉強になった。

とりあえず1つ目の講座の模擬試験は初見6-7割くらいでもうちょい勉強すればなんかいけるんじゃ。くらいの感じだったけど2つ目講座の模擬試験は難易度高めの問題をまとめていることもあり4割程度しか解けず。

大体はEC2のインスタンスタイプとかS3のストレージクラスとか選べるオプション記憶してるか問われたり、システムと要件の例が出てきて AWSのどのサービスを使えばパフォーマンス、コストの面でそれぞれ最適なのかとか、ある程度細かいところ暗記して状況に適した使い方答えさせる問題が出てくる感じ。

後は割と知らなかったサービスもあってこんな便利なの。。って気になってくる(SnowbollとかAthenaとかS3セレクトとかAmazon WorkSpacesとか)

今後

この感じでWebで問題探して解いてれば合格できるんじゃないかって気がするけどなんとなく不健全な気もするのと問題解くだけだと飽きてくるのでコード書いてAPI叩いてみたりコンソール入っていじったりは必要そう。

youtubeみるとAWSの解説動画も結構あるしネットの記事も溢れてるのでしばらく本は買わずにネットだけで進める予定。

自粛期間中に終わればいいけど他にやりたいこともあるしほぼほぼ趣味なので気長にやってこうと思う。

言語処理100本ノック6、7章やった

しばらくReactを学び直していて離れていたが言語処理100本ノック再開して7章まで完了した。

この先は機械学習がテーマで重そうなので一旦ここを区切りとして振り返り。

6章: 英語テキストの処理

50、51は正規表現で文字列処理,52はステミングアルゴリズム(同じ意味の英単語だけど語系が変化するもの)で文字列を解析する。

ステミングについて

www.ibm.com

53以降はStanford Core NLPアルゴリズムを使って課題の文章を解析し、結果をXMLに吐き出してそのXMLを処理していく。XMLの処理は実務でもやったことがあるし問題ないんだけど、

が、未経験の領域でそこは学ぶ必要があった。あとはStanford Core NLPを使うのにJavaが必要だったりと環境構築が少し面倒。

Stanford Core NLPとは何か

スタンフォード大学が作成したオープンソース自然言語処理ライブラリ。

文章を単語ごとに分解してそれぞれの属性や単語間の関連を出力してくれる

  • 名詞、動詞、形容詞、副詞
  • 主語、述語、目的語、補語
  • 人名、地名、日付
  • 単語間の修飾関係

参考 stanfordnlp.github.io

それぞれの属性や関連付けの情報がXMLに吐かれるのでその属性を元に与えられた課題に沿った情報を出力するプログラムを書いていく。 Stanford Core NLPが日本語対応していないこともあるのか日本語情報少なく、データ構造把握するのが辛い。

7章: データベース

Key Value形式のNoSQLデータベースにアーティストの情報を登録してPythonインタラクティブシェルで検索する。MongoDB推奨なのでMongoDBに登録したけど他のDBでも良いらしい。

countとかsortがMongoだと関数として提供されていて便利だった。

最後にデータベースへの検索と結果の出力をするWebアプリケーションの課題があり、そこで初めてFlaskを触ってみた。

Rails以外のWebフレームワークほとんど触ってことなかったんだけどHTML内の変数の展開方法やルータの定義などRailsと同じ感覚でできる部分も多くRailsわかれば割と何とかなる感じ。

感想

XMLとkey-valueの扱いはRubyでのサーバサイドプログラミングと同じ感覚でできるが、自然言語処理ライブラリの使い方とか考え方で戸惑う部分が多かった。

一次情報だと辛くて結構先人の方々のコードやブログ記事を読ませていただき大変助かりました。