概要
GitHub 上で、Swagger の yaml | yml | json を Swagger-UI に変換できる Chrome 拡張機能を作った。
その紹介。
「Swagger とは?」という話は、下記等を参照のこと。
Demo
インストール
Chrome Web Store からインストールできる。
swagger-viewer - Chrome ウェブストア
特徴
簡単
- 1クリックで変換できる
依存なし
- この拡張機能のみで動作する
- Web の Swagger Editor を開いたり、ドキュメント生成サーバーを起動する必要なし
セキュア(たぶん)
- 外部ネットワークへの送受信はないため、業務でも使用できる
- ※自己責任でお願いします
- たぶん
- Chrome の Network タブを眺めたが、通信する様子はなかった
- Swagger の描画のために使用しているライブラリ「swagger-ui」のコードも軽く読んだが、ネットワーク送受信に関するコードはなかった(自信なし)
- やべーやつだったらご連絡いただけると幸いです
開発裏話(?)
動けばいいんだよ2割、美しく書きたい8割、くらいの気持ちで作った
趣味のコードは盆栽
名言だと思った
「趣味で書くソースコードは綺麗汚い問わない」との意見が散見されますが、僕は趣味で綺麗なソースコードを追求する人間です。盆栽に近い。
— ミノ駆動 (@MinoDriven) 2019年4月25日
src
https://github.com/arx-8/swagger-viewer
技術要素
似た技術スタックで Chrome 拡張機能を作りたい人の一助になれば(と盆栽自慢に)少し書く
- WebExtension Toolbox (Chrome 拡張機能ジェネレーター)
- TypeScript
- Jest
- jsdom
- React
- ESLint
- Clean Architecture
以下盆栽ポイント
- 最新フロントエンド技術 (TypeScript, Jest, typescript-eslint, prettier, etc.) を導入した
- 壊れやすいDOM操作に対してUnitTestを書いた
- 生DOMは、Jest + jsdom
- Reactは、Jest Snapshot test + react-test-renderer
- WebExtension Toolbox で作った雛形には、TypeScriptはもちろんESLintもテストも入ってないので、自分で追加が必要
- Clean Architecture
- (ゆるく)パッケージ構成をこれでやるとだいたいうまく整理できる気がする
- Clean Architecture * React のベストプラクティスがほしい・・・
TypeScript導入
下記issueを参考に、
https://github.com/webextension-toolbox/generator-web-extension/issues/11
ts-loaderで導入
https://github.com/arx-8/swagger-viewer/commit/fcf385363729f6fb0a7e39018a5fff2ec5881145
後に、Jest導入時にうまく動作しなかったため、babelに変更
https://github.com/arx-8/swagger-viewer/commit/a5dbbe19054189cb03cc88d825ee9c21d2671987
幸いwebextension-toolboxがbuildに使ってるbabelが7系だっため、TypeScriptのトランスパイルができた
https://github.com/arx-8/swagger-viewer/blob/master/swagger-viewer/package-lock.json#L9871
Jest導入
前述の通り、ts-loaderではうまく動かず、babelに変えた
https://github.com/arx-8/swagger-viewer/pull/9/files#diff-47c7df0a0b4c5f24af1531f28d7a4d57
Reactでの css import がエラーになったため、これをやった
https://jestjs.io/docs/ja/webpack#静的アセットの管理
ESLint (+ Prettier)
https://github.com/arx-8/swagger-viewer/pull/11/files#diff-514b7220e7bfcb11a68634cba4db8961
- .eslintrcのextendsが激盛り・・・
- 個人的には、ガチガチのairbnbをプロジェクトに応じて緩めるのが好き
no-restricted-globals, no-restricted-properties で禁止機能を定義している
- Map は嫌い
- innerText -> textContent
- DOM の textContent と innerText について - Please Sleep
- 「innerHtmlがあるからinnerTextやろ」とやると死ぬ
- document -> getDocument()
- 理由は後述
ESLint + TypeScript + VSCode
VSCode拡張機能のESLintはちゃんとtsファイルにも対応していた
しばらく気付かず悶々としていたが、やはりMSは神
https://github.com/Microsoft/vscode-eslint/issues/609#issuecomment-460554105
- ただデフォルト有効にはならなそうな雰囲気なので、自分で設定が必要
実際の設定はこんな感じ
- https://github.com/arx-8/swagger-viewer/blob/aaae948cf150848f44e7a110d3487ce9de328b23/swagger-viewer/.vscode/settings.json
- https://github.com/arx-8/swagger-viewer/blob/aaae948cf150848f44e7a110d3487ce9de328b23/swagger-viewer/.eslintrc.js#L15-L22
今のところ特にバグにもハマってないので、typescript-eslint は十分プロダクトに投入できるレベルなのでは
Jest + jsdom
だいたいこんな手順で、documentオブジェクトに任意の値を展開してテストしている
-
- getDocument関数をJestでMock化
-
- ページ丸ごと文字列としてテストデータとし、それをjsdomに与えてdocumentオブジェクトを生成
-
- getDocumentの返値を「2.」にする
-
- 任意のdocumentオブジェクトに対して、操作が期待通りの状態を作れるかテストする
テスト結果を手で定義するのが面倒なものは、toMatchSnapshotで雑にassert
no-restricted-globals で document -> getDocument() としてる理由はこれ
- JestでMockできるのは、外部ファイルからimportしたリソースのみらしい
- なので、documentオブジェクトにアクセスする場合は、必ずgetDocument(モック化できるfunction)を経由させている
Jest + react-test-renderer
enzyme より react-test-renderer の方がいいぞ、という記事を読んだのでそうした
コード例
- https://github.com/arx-8/swagger-viewer/blob/280caa8e155a4e45d68b74c83b532650d531b56b/swagger-viewer/app-src/contentscript/presentation/App/index.test.tsx
- 出力内容を1行ずつ見てはいられないが、「これで間違いはない」という状態で一発Snapshot取っておく
- UI系のライブラリも丸ごとSnapshot取っておくと、バージョンアップの時に動作の保証だけでなく、「どこが変更されたか」がdiffでわかって便利
DOM丸ごと生成したりライブラリのrender結果を丸ごとSnapshot取ったり力技なUTだが、「規模が小さいし実行してほっときゃ終わるだろ」ということで富豪チックに書いた
これでGitHubのhtmlが変更されたとしても、UT回して検知・修正ができるであろうと期待
未解決の課題
ReactTestUtils.Simulate.click ができない
やり方を知ってる方いたら、ご教授願いたい・・・
公式には記述があるのだが、ver違いなのかReactTestUtils.Simulateがundefinedだった
https://reactjs.org/docs/test-utils.html#simulate
「Reactコンポーネントが、ある箇所をクリックされた結果どうなってるか」のSnapshot testができていないのが心残り
まとめ
- Chrome拡張機能、型・テストともガッチガチに作れて楽しかったのでオススメ!!