0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ブラウザ自動化で「文字は入ったのに送信できない」を直す — value代入がReactに届かない問題の対処3種

0
Posted at

3行で

  • 自動操作で value に代入しても、React などの状態を持つUIでは「ページ内部の値」は空のまま
  • 代入した直後にキー入力を1回だけ足すと、ページ側が値を読み直して認識してくれる
  • 入力できたかの確認は、スクリーンショットではなく送信ボタンの活性文字数カウンタで行う

どんなときに刺さるか

ブラウザ自動化(Playwright / Puppeteer / CDP 経由のエージェントなど)でテキスト入力欄を扱っていて、次のどれかに心当たりがある場合です。

症状 よくある勘違い
長い日本語を送ったのに1文字しか入らない 文字コードやIMEの問題だと思って回り道する
画面に文字は出ているのに送信ボタンが有効にならない 入力は成功していると思い込み、ボタン側を疑う
入力後に文字数カウンタやサジェストが動かない ページが重いだけだと思って待ち時間を伸ばす

いずれも原因は同じ1点に集約されます。

なぜ起きるか

状態管理を持つUIでは、入力欄に表示されている文字は state を描画した結果でしかありません。アプリケーションにとっての「値」は state のほうにあり、DOM の value プロパティを外から書き換えても state は更新されません。

つまりこうなります。

DOM の value  →  書き換えた(画面には出る)
React の state →  空のまま(送信ボタンは disabled のまま)

これが「見た目は成功、実体は失敗」を生みます。デバッグ時にスクリーンショットで確認していると、この食い違いに気づけません。

一方「1文字ずつキー入力を送る」方式は state を正しく更新できますが、1文字ごとに再レンダリングが走るため、長文だと再描画と後続のキーイベントが競合して文字が欠落します。日本語はIMEの composition イベントも挟まるので、さらに取りこぼしやすくなります。

解決策1: 代入 → キー入力1回(推奨)

実運用でいちばん安定したのがこの組み合わせでした。

  1. JavaScript で value に長文を一括代入する
  2. その直後に、自動操作のキー入力APIで1文字だけ打つ

手順2のキーイベントが「入力が発生した」というトリガーになり、アプリ側が入力欄の現在値を読み直します。このとき手順1で入れた長文がまとめて state に取り込まれます。自分のケースでは、この直後に aria-label="送信" のボタンが DOM に現れました。

順番を逆にしないでください。先にキー入力してから代入すると、代入内容が state に伝わらないまま終わります。

長文を1文字ずつ打つ方式に比べて速度も段違いです。代入は一瞬なので、実質キー入力1回分のコストで済みます。

解決策2: イベントを明示的に dispatch する

キー入力を挟めない環境では、イベントを直接発火させます。

const el = document.querySelector('#target');
el.value = longText;
el.dispatchEvent(new Event('input',  { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));

bubbles: true は必須です。React はルート要素に委譲したリスナーでイベントを受けるため、バブリングしないイベントは届きません。

ただしこの方法は万能ではありません。独自の入力コンポーネントを使っているページでは、素の input イベントを購読していないことがあります。相手の実装への依存度が低い解決策1を第一候補にして、使えない環境でのみこちらに落とすのが安全です。

解決策3: クリップボード経由で貼り付ける

クリップボードにテキストを載せてから Ctrl+V / Cmd+V を送る方法もあります。

  • 長文でも取りこぼしがない
  • IMEの変換処理を経由しない
  • 1文字ずつ打つより高速

弱点は、クリップボードという共有資源を使うため他の処理と競合しうる点と、onpaste を潰しているページ(メールアドレス確認欄など)では機能しない点です。

検証は「見た目」でやらない

対処と同じくらい重要なのがここです。入力後の検証をスクリーンショットや DOM のテキスト取得で済ませると、上記の食い違いをそのまま見逃します。

検証には、アプリが値を認識したときにだけ変化するものを使ってください。

  • 送信ボタンの disabled が外れたか
  • 文字数カウンタの数字が増えたか
  • オートコンプリートのサジェストが出たか

これらが変化していなければ、画面に何が表示されていようと入力は失敗しています。

おまけ: レスポンス領域が空で返ってくる

送信自体は成功したのに、応答を表示する要素の textContent が空、というケースにも遭遇しました。要素は存在するのに中身の長さが 0 という状態です。

これは入力とは別レイヤーの問題で、描画完了前に読みに行っているか、レンダリング自体が取りこぼされています。同じURLを再読み込みしたら中身が入っていたので、データはサーバー側に保存済みで、画面反映だけが落ちていたことになります。空文字が返ったら1回リロードして読み直すをリトライ手順に組み込んでおくと安全です。

まとめ

症状 原因 対処
長文が1文字しか入らない 1文字ごとの再レンダリングとキーイベントの競合 一括代入 + キー入力1回
文字は見えるが送信できない DOM の value だけ更新され state が空 同上 / inputchange を dispatch
入力成否が判断できない 見た目は成功に見える ボタンの活性・カウンタで検証する
レスポンスが空で返る 描画の取りこぼし 再読み込みしてから取得

自動化でいちばん時間を溶かすのは「完全に失敗」ではなく「半分成功」です。画面に文字が見えていると成功と判断してしまい、数工程先で詰まってから原因を探しに戻ることになります。入力後は必ずアプリ側の反応で検証しましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?