Jest + enzymeでbuttonがdisabledかをテストする
Reactでフロントエンドを作っていて、テストを書いているときにボタンがdisabledになっているか(ボタンが押せないか)をテストしようとして調べた結果をまとめる。
結論
propsメソッドを使用して、オブジェクトが持っているアトリビュートを返してもらい、disabledがtrueかどうかをテストする。
const button = wrapper.find('button') expect(button.props().disabled).toBeTruthy()
参考
Template Methodパターンを使ったのでまとめる
Template Methodパターンとは
Template Methodパターンは、抽象クラスとその派生クラスを使うデザインパターン。
実装手順
Template Methodパターンの実装手順は以下のようになる。
- 基本クラスに汎用的なアルゴリズムを実装する
- 派生クラスで実装してほしいメソッドを抽象メソッドとして定義する
- 派生クラスで基本クラスの抽象メソッドを実装する
実装例
Template Methodパターンの実装例を考えた。 具体的な実装というよりは、こんな感じで実装できそうだという感じ。
複数媒体をスクレイピングするケースを考える。 媒体に関わらずやりたいことは、「URLにアクセスし、記事のタイトルを取得して何らかの処理をしたい」というユースケースで考えた。 抽象クラスはこのようにしてみた。
※コメントアウトの部分は、こういう処理が本当なら実装されるというものを表している。 処理の説明などではない。
abstract class Scraping { constructor(private baseURL: string) {} execute() { /** * 共通のスクレイピング処理を実装する * URLにアクセスするところなど */ const urls = this.getArticleURLs(this.baseURL) const titles = urls.map((url, _) => this.extractTitle(url)) /** * titlesを使った処理 * 記事のタイトルを出力したりするなど */ } abstract getArticleURLs(baseURL: string): string[] abstract extractTitle(articleURL: string): string } export default Scraping
解説
Scrapingクラス
という抽象クラスをTemplateMethodパターンのクラスとして定義する。
executeメソッド
は実行するための処理を表している。
どの媒体をスクレイピングするにしても、変わらない処理を実装している。
具体的には、以下のような流れで処理を行う想定。
- URLを元にサイトを見に行く
- サイトにある記事ごとのURLを取得する
- 記事ごとのURLにアクセスし、タイトルを取得する
- 3で取得したタイトルを使って何らかの処理をする
次に、抽象メソッドとしてgetArticleURLsメソッド
とextractTitleメソッド
を定義している。
getArticleURLsメソッドは記事ごとのURLを取得するためのメソッド。
媒体ごとに記事のURLの取得方法は違うはずなので、Scrapingクラス
を継承したサブクラスで実装することにする。
求人サイトをスクレイピングすると仮定するとWantedlyScrapingやGreenScrapingというサブクラスでWantedlyやGreenの求人のURLを取得する方法は異なるので、それぞれに実装する。
extractTitleメソッドは、記事からタイトルを取得するメソッド。 タイトルも媒体ごとに取得方法がことなるので、サブクラスで実装する。
このように実装することで、共通する処理は抽象クラスに実装し、詳細がことなるメソッドはサブクラスで実装することができるようになる。
注意点
Template Methodパターンには、「派生クラスでは基本クラスに宣言されている抽象メソッドだけを使って実装する」というルールがある。 そのため、サブクラスにしかないパブリックなメソッドを実装してはいけない。
参照
「継続的にアウトプットする技術――エンジニアのための「続けられる」科学」を読んだ
アウトプットを始める理由
インプットとアウトプットの黄金比は3:7なのだそう。 多く見積もってもインプット:アウトプット = 8:2だった自分としては衝撃的だった。 3:7なのでインプットの倍以上をアウトプットするのが理想なのだが、 とりあえずは1:1の割合でインプットとアウトプットをしていこうと考えた。
読んだ
とりあえずアウトプットに関する本を読もうと思い、こちらの本を読んだ。 booth.pm
アウトプットを組み込む
自分の中でのインプットの流れはある程度固まっているので、その中にアウトプットを組み込むことを考えた。
自分は普段の作業にポモドーロを導入しているので、 インプットのポモドーロのあとにアウトプットのポモドーロをしようと思う。 要するに、インプットとアウトプットを交互に行ってみる。
アウトプットの流れ
アウトプットはブログに行う。 アウトプットのポモドーロでは、以下の流れで進めてみる。
- 学んだ内容のアウトラインを箇条書きにする
- アウトラインを肉付けする
- 公開する
アウトプット初心者なので、あまり時間をかけすぎずにとりあえず公開するということを続けてみたい。
JestでSCSSをimportしているところのテストでエラーが起きるのを解決
概要
JestでReactのテストを書いているときに、SCSSをインポートしている箇所のテストでエラーが起きていました。 それに対しての解決方法です。
環境
開発の環境は以下です。 - TypeScript - React - Redux - Jest - Enzyme - Webpack
原因
テスト環境では、インポートされたSCSSファイルを扱うことができないのが原因でした。 (tsやtsxのファイルはjest.config.jsのtransformオプションでts-jestを使って変換するというふうに設定しているので扱えます。)
上記のような設定をSCSSに対して行っていないため、エラーが出ていました。
解決策
CSSモジュール(SCSSも同様)をモックすることで解決しました。 CSSモジュールはあくまで、コンポーネントに対してスタイルをあてるものなので、 正しいスタイルがあたっているかというテストをする必要がない限り、CSSモジュールごとモックしてしまって問題ありません。
identity-obj-proxy
というパッケージを導入して、moduleNameMapper
オプションにCSSモジュール(拡張子がcssやscssなどの場合)の場合は、
identity-obj-proxyを使ってモックする設定を追記することでテスト中のCSSモジュールはモックされるようになりました。
identity-obj-proxyのインストール
$ yarn add --dev identity-obj-proxy
moduleNameMapperにCSSモジュールをモックする設定
module.exports = { ... moduleNameMapper: { '^src/(.+)': '<rootDir>/src/$1', '\\.(css|scss|sass)$': 'identity-obj-proxy' }, ... }