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回(推奨)
実運用でいちばん安定したのがこの組み合わせでした。
- JavaScript で
valueに長文を一括代入する - その直後に、自動操作のキー入力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 が空 | 同上 / input・change を dispatch |
| 入力成否が判断できない | 見た目は成功に見える | ボタンの活性・カウンタで検証する |
| レスポンスが空で返る | 描画の取りこぼし | 再読み込みしてから取得 |
自動化でいちばん時間を溶かすのは「完全に失敗」ではなく「半分成功」です。画面に文字が見えていると成功と判断してしまい、数工程先で詰まってから原因を探しに戻ることになります。入力後は必ずアプリ側の反応で検証しましょう。