Jest と React の組み合わせがあんまり便利じゃなかった
どっちも Facebook 製だし Jest は React のテストにも向いてるというから使ってみた
けどあんまり使いやすくなかった
Jest 自体に React のレンダリング機能はなし
別ライブラリが必要

○ React Renderer
○ Testing Library
○ Enzyme

など

React Renderer が公式
とりあえずこれを使ったけどそこまで便利というほどでもなかった
Testing Libraryとかのほうがいいかも

○ useState の更新は面倒
useState を mock 化して 返り値の setXXX を保持して それを呼び出し順から推測して取得して呼び出したり
もっと便利できる機能があるのを期待してたのに

○ shallow render が必要になる
普通に render すると子コンポーネントも render される
色々と処理がされすぎる
テスト用環境だと動かない部分の mock 化が面倒すぎる

shallow render だと子コンポーネントは render されない
関数ならコンポーネントの返り値 クラスコンポーネントなら redner メソッドの返り値を受け取れる
それなら直接関数呼び出しや インスタンス作って render 呼び出しでもいいような?
とも思ったけど それだと useMemo や useRef みたいなフックで問題出るかも

○ useEffect の実行
useEffect が実行されると 処理が複雑なコンポーネントでつらい
useEffect は無効にして useEffect の処理内で state が変わった結果の 仮想 DOM 構造のチェックだけしたい
かと言って useEffect で何もしないようにすると問題が起きる

useEffect の置き換えは全コンポーネントに影響するから 子コンポーネントでも useEffect が実行されない
ライブラリでは useEffect の処理で props.children を仮想 DOM に追加することがある
useEffect が実行されないと仮想 DOM 内は空で必要な要素が結果に含まれてない
特定モジュールからの require/import だけ mock できたらいいけどそれらしいのはなさそう

○ shallow renderer だと仮想 DOM 内の検索とかができない
取得できるものは JSX で作る部分の生のオブジェクト
querySelector 的な便利機能はついてない
子要素や N 番目という場所を固定で自力で取り出して確認することになる
固定の場所の props の onClick などを取り出して 関数呼び出しでボタン押された扱いにして……
ってちょっと不便すぎ
要素の追加や順番の置き換えだけで動かなくなる

○ そこまでしてのやる必要性
React のコンポーネントをテストしようとすると その他モジュールのテストに比べて mock しないといけないのが多い
ほとんどのコンポーネントってロジック的に複雑というわけでもなくテストしておきたい感はあんまりない
基本的に 機能は別モジュールに分けてるし コンポーネントのテストは React などのライブラリ使う前と同じくそこまでしなくてもいい感じがする

ロジック部分がモジュールに分かれていて そっちがテスト済みなら DOM 周りはもっとゆるいのでいい
特定文字が含むかどうかの確認だけとか
React でのテストをしないで 通常の DOM として jsdom か実際のブラウザで一通りの画面遷移ができてればそれでいいと思う
WinForms のフォーカスがよくわからない
こういう構造のフォームを用意する

Form
TextBox1
UserControl1
Button1
TextBox2

Form の ActiveControl プロパティに form.userControl1 をセットしてフォーカスを確認する

System.Diagnostics.Debug.WriteLine(this.userControl1.CanFocus);
// True
this.ActiveControl = this.userControl1;

System.Diagnostics.Debug.WriteLine(this.ActiveControl);
// WinFormsApp1.UserControl1
System.Diagnostics.Debug.WriteLine(this.userControl1.Focused);
// False
System.Diagnostics.Debug.WriteLine(this.userControl1.ContainsFocus);
// False
System.Diagnostics.Debug.WriteLine(this.userControl1.ActiveControl);
// null

userControl1.CanFocus が True なのでフォーカスできるはず

ActiveControl に代入後には ちゃんと中身が UserControl1 になってる
なのに userControl1 の Focused や ContainFocus は False
userControl1 の ActiveControl は null
フォーカスが行方不明
見た目上は初期位置の TextBox1 のまま

もしかして JavaScript であるようなイベントループに処理を返してから変わったり?
タイマーで 1 秒待ってから同じものを表示するようにしてみる
→全く同じ結果

ActiveControl とフォーカスは別?

だけど

this.ActiveControl = this.userControl1.button1;

にして 代入直後の時点でさっきと同じ内容を表示すると

WinFormsApp1.UserControl1
False
True
System.Windows.Forms.Button, Text: button1

ContainsFocus が True になっていて userControl1 の ActiveControl が button1 になってる
見た目上でもボタンにフォーカスがあたってる

this.ActiveControl = this.textBox2;

でもフォーカスが切り替わってカーソル位置も変わってる

UserControl だけ特殊みたい


Focus メソッドも使ってみる

this.userControl1.Focus()

WinFormsApp1.UserControl1
False
True
System.Windows.Forms.Button, Text: button1

「this.userControl1.button1」 を ActiveControl に設定したときと一緒で UserControl1 内の最初のコントロールにフォーカスがあたってる
UserControl 自体にはフォーカス当たらなそう

だけど UserControl1 の中身を空にしてから

this.userControl1.Focus()

すると

WinFormsApp1.UserControl1
True
True
(null)

フォーカスあたってるみたい
画面上ではどこにもフォーカスあたってるような見た目はなし
Python の unpack 仕様がやっぱりつらい
久々に Python に触れてやぱり unpack が辛いです
これはどっちもエラーです

(a, b, c) = [1, 2]
(a, b, c) = [1, 2, 3, 4]

足りないなら None でいいし 多いなら無視してくれていいのに これで例外が出ます
配列の要素数が不定の場合に一々チェックが必要になります
楽にするために

(a, b, c) = [*list, *[None] * 3][:3]
(x, y) = [*list, *[None] * 2][:2]

としてもやっぱりイマイチ
関数にまとめれば多少は見やすくなるもののやっぱりスッキリはしません

def resize(list, size):
return [*list, *[None] * size][:size]

(x, y) = resize(list, 2)
埋め込む値がある場合のみ処理したい
something(`.... ... ${values.foo} .. ...`)
something(`.. ..... ${values.bar} ... ..`)

こんな感じの処理で values.foo などの埋め込む値が 存在する (null, undefined じゃない) ときのみ something を実行したいことがたまにある

if (values.foo) {
something(`.... ... ${values.foo} .. ...`)
}
if (values.bar) {
something(`.. ..... ${values.bar} ... ..`)
}

なんか面倒な感じで something 呼び出しが 10 近くも並ぶと どうにかしたくなってくる
`` の埋め込みはタグ関数を使って関数で処理できるので

const F = (fn, ...args) => (tpls, ...values) => {
if (values.every(v => v != null)) {
fn(String.raw(tpls, ...values), ...args)
}
}

F(something)`.... ... ${values.foo} .. ...`
F(something)`.. ..... ${values.bar} ... ..`

スッキリはしたけど用途が限定的すぎる気も

something(fn`... .. ${values.foo} .. ....`)

上の形式にして fn では埋め込む値に undefined があれば全体を undefined で返す
something では undefined を受け取ると何もしないとする方が良さそう?
ただ something が自作でないなら undefined 対策にラッパー関数が必要になるし ラッパー関数作るならそこで分岐埋め込みもやったほうがいいのではという気持ちにもなる

const somethingWrapper = (cond, str) => {
if (cond != null) something(str)
}

somethingWrapper(values.foo, `... .. ${values.foo} .. ..`)

シンプルだけど values.foo を 2 回書くのだけが不満
`` を使った埋め込みで 2 回書かないならタグ関数必須のはずだし 結局上のに戻る
正規表現パターンマッチング
文字列のパースで 無いかもしれないものがいくつかある場合 正規表現で「?」をつけて match させてから結果を if 文で色々処理するのってわかりづらいし let 多用になるのがいまいち
「?」つけずにそれぞれのパターンで match させてパターンごとに処理をさせたほうがわかりやすいかも

こういう関数を用意して

const match = (str, patterns) => {
for(const [cond, fn] of patterns) {
if (cond == null) return fn()
const matched = cond instanceof RegExp ? cond.exec(str) : str.match(cond)
if (matched) return fn(matched, ...matched)
}
}

こう使う

const tes = str => {
const result = match(str, [
[/^(\d+)$/, (_, __, d) => [+d, +d]],
[/^(\d+),$/, (_, __, d) => [+d, null]],
[/^,(\d+)$/, (_, __, d) => [null, +d]],
[/^(\d+),(\d+)$/, (_, __, d1, d2) => [+d1, +d2]],
[null, () => [null, null]],
])
console.log(result)
}

tes("10,20") // [10, 20]
tes("30,") // [30, null]
tes(",40") // [null, 40]
tes("50") // [50, 50]
tes("") // [null, null]

見やすさはイマイチかも
Node.js の GUI ライブラリ
Python だと GUI を作るライブラリで tkinter とか kivy とか聞くけど Node.js って NW.js や Electron くらいしか聞かない
ブラウザ組み込み系じゃなく GUI を作るライブラリってないのかなと調べてみた

● Node-Qt
http://documentup.com/arturadib/node-qt (Github)

C++ Qt bindings
この手のライブラリはラップしてるだけだと思うので C++ で Qt 使ったことある人には向いてるかも
2014 年から更新されてない
bindings だし安定してるのか放置されてるのか

● node-gtk
(Github)

GNOME Gtk+ bindings
こっちは最終更新は 2020 年末で最近
Windows だと使えなさそう

● NodeGui
https://docs.nodegui.org/ (Github)

一番人気そうな GUI ライブラリ
内部は Qt 使ってるらしい
React や Vue にも対応してるらしいけど そういうの使うなら Electron でいい気がする
React Native は Windows 版もあった気がするし

● Yue
https://libyue.com/ (Github)

リポジトリ内に C++, Lua, Node.js がまとめて入っていてドキュメントも同じサイトにまとまってる
Qt などの移植と違って元プロジェクト自体が 3 言語サポートしてるみたい
既存のライブラリに求めてるのがなかったから自作したらしい
内部的に何使ってるかまでわかってない
base フォルダを見るに一部 Chromium のコードを流用してる?
Windows 版は GDI+ で将来的に Direct2D に置き換え予定だとか
match と replace の検索するテキストに文字列型渡したときの違い
忘れた頃に引っかかるやつ

console.log("1.2".replace("1.2", "X")) // X
console.log("102".replace("1.2", "X")) // 102

console.log("1.2".replaceAll("1.2", "X")) // X
console.log("102".replaceAll("1.2", "X")) // 102

console.log("1.2".match("1.2")) // ["1.2", index: 0, input: "1.2", groups: undefined]
console.log("102".match("1.2")) // ["102", index: 0, input: "102", groups: undefined]

console.log("1.2".matchAll("1.2").next().value) // ["1.2", index: 0, input: "1.2", groups: undefined]
console.log("102".matchAll("1.2").next().value) // ["102", index: 0, input: "102", groups: undefined]

match は文字列型でも正規表現としてマッチングされる
replace の挙動に揃えてほしいけど互換性重視で実現されないだろうね

ただの match だと正規表現にしたくないなら indexOf や includes で良かったけど matchAll は indexOf 繰り返すの面倒だから文字列型として使いたいのに