BizRobo! DAで処理が空振ってしまう原因と対策（コンポーネント編）

## はじめに

以前書いた記事の続編で、より発生しがちな具体的なケースについて記載します。

https://qiita.com/macrisis/items/6eacd98207b4b963403c

## アプリケーションとコンポーネントの関係

以前の記事が `アプリケーション` 、今回の記事が `コンポーネント` についてですが、DAが扱うターゲットの概念としてはさらにもう一つ外側に `デバイス` という対象があり関係性は下図の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/ebb11225-3371-5d9c-7cd5-5b3f3694192e.png)

一般のRPA製品ではロボット＝デバイス（端末）なのでロボットが指定するのは特定端末の `アプリケーション` とそこに配置されるボタンやテキストを指す `コンポーネント` のみです。一方でBizRobo!はRoboServerでロボットが起動され、必要に応じて指定した端末をDAが操作する形式であるため、`デバイス` > `アプリケーション` > `コンポーネント` の関係を指定してロボットが操作する対象を選ぶことになります。

:::note info
実際にどの程度使われているかは別として、上記の仕組み上BizRobo!においては一つのロボットが複数の端末を切り替えて操作することも可能です。
例えば、一つのロボットが複数の端末に対して順番に処理を行っていくようなことや、ロボットの稼働端末として複数デバイスを予めセットしておいて、端末に異常があった場合には切り替えて処理を続行するといった物理的な冗長性を持たせるなども、やって見る価値はあるかもしれません。
:::

## コンポーネントが空振りになってしまう仕組み

前回のアプリケーション編では稀に起こるフォーカスの消失でDAの操作が空振ってしまうことを紹介しましたが、コンポーネントの場合は主にその受付状態[^1]によって空振りが生じます。

例えば以下のような画面。
ラジオボタンで「有効」が選択されている場合には下のテキストボックスは入力を `受付可能` な状態であり文字の入力が可能ですが、その隣りにある「無効」や「読み取り専用」が選択されている場合は入力が `受付不可` な状態であり、いくらキーボードを叩いても何も入力されません。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="vYZzVGq" data-user="macrisis" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/macrisis/pen/vYZzVGq">
  </a> by JO (<a href="https://codepen.io/macrisis">@macrisis</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

DAでコンポーネントを設定する場合、ユーザーが選択した時点での画面状態を基にCSSセレクター表記でファインダーを特定するため、上の場合で言えばテキストボックスのタグ（INPUT）やその種類（type="text"）といった `静的` な情報はDAにより自動的に割り当てられますが、`動的` に変わる「状態」については自動で設定されず設定時と実行時で不一致が発生する場合に問題が起こります。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/744a9f27-f8bd-46de-3468-1562101dae4f.png)

## 空振りが発生するケース

通常は余り発生しませんが、自動化対象のアプリケーション特性やシステムの負荷状況により稀に起こる事があり、その場合には大体以下の３パターンに集約できると思います。（経験の範囲）

- 新規画面表示直後の画面操作時
- 項目選択や絞り込みのように、画面の描画を更新する操作の直後
- データの更新や登録などデータの変更をコミットする操作の直後

### 新規画面表示直後

アプリケーション処理の一つとして初期化処理というものがあります。例えばWebの場合、URLを指定してHTMLを読み込むことでINPUTやBUTTONなどの要素が表示され、その後に初期化イベントが発生しBUTTONの有効化やセレクトボックス内のアイテム生成など様々なことが行われます。

要は、実際にコンポーネントが表示されてから受付状態が「可」になるまでにワンテンポ隙間の時間が生じるのですが、仕組みの説明で書いたようにデフォルトのコンポーネント設定で判断できるのはコンポーネントの存在確認だけなので、仮に端末やアプリの動作が重くて通常より初期化処理に時間がかかった場合にDAがフライングして操作が空振る結果になります。

### 画面描画の更新

「新規画面表示直後」のケースと類似しており、画面描画の更新に時間がかかってしまう場合、更新前のコンポーネントを先にDA側が掴んでしまい、その後画面描画によりコンポーネントが書き換えられても事前に掴んだコンポーネントを切掛にフライングしており操作が空振ります。


### データの変更処理実行時

データを登録したり更新したり、プリンター出力したりといったアクションを実行する際、誤ってダブルクリックにより二重登録してしまうことを避けるために実行ボタンを一瞬無効化（受付不能に）することがあります。

「新規画面表示直後」の初期化処理と同様に受付状態の変化を感知せずコンポーネントの存在確認のみをし、無効化されているボタンをDAがクリックして処理が空振ります。


## コンポーネントを確実に捕捉する方法

上記のような現象に気づかず `DAの動きが不安定` と思われる際には、コンポーネントの受付状態を加味した設定をすることで不安定な動作を解消できます。

例えば上で例示した [CodePenのページ](https://codepen.io/macrisis/full/vYZzVGq)をChromiumで読み込んだ場合を例に記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/7ffa8756-84de-8dba-117a-656fdc061ab9.png)


```html:有効な場合に展開されるコンポーネントのタグ情報
<INPUT id="txt" placeholder="入力できるかな？" type="text" value=""
 der_rendered="y" der_isOffscreen="true" der_value="「有効」なので入力可"
 der_x="18" der_y="168" der_width="234" der_height="29"/>
```
<details><summary>画面イメージ</summary><div>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/858e979d-d53f-cc24-59ba-2c69117a35b5.png)
</div></details>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/744a9f27-f8bd-46de-3468-1562101dae4f.png)
この例では特に追加する動的な情報はなく、追加する属性は有りません。


```html:無効な場合に展開されるコンポーネントのタグ情報
<INPUT disabled="" id="txt" placeholder="入力できるかな？" type="text" value=""
 der_rendered="y" der_isOffscreen="true" der_value="「無効」なので入力不可"
 der_x="18" der_y="168" der_width="234" der_height="29"/>
```
<details><summary>画面イメージ</summary><div>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/a353fc47-793d-6cc6-a38d-f5ac4c38e211.png)
</div></details>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/e26fb0db-defe-5e53-170f-3b8db6532ae9.png)
`[disabled=""]` 属性を追加することで「無効な状態のタグ」を特定します。ただし本来実行したい操作としては無効な状態の場合には操作しないということなので、「無効な状態でない場合に処理をする」ために、Guarded Choiceの指定条件も Location Found（ロケーションが見つかった場合）ではなく Location Not Found（ロケーションが見つからなかった場合）に切り替えます。


```html:読み取り専用の場合に展開されるコンポーネントのタグ情報
<INPUT id="txt" placeholder="入力できるかな？" readonly="" type="text" value=""
 der_rendered="y" der_isOffscreen="true" der_value="「読み取り専用」なので入力不可"
 der_x="18" der_y="168" der_width="234" der_height="29"/>
```
<details><summary>画面イメージ</summary><div>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/1e66479c-a588-00c5-207f-c9f324326b1e.png)
</div></details>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/0e5770d7-3cf1-e135-19ac-bac97cf85f85.png)
`[readonly=""]` 属性を追加することで「読み取り専用な状態のタグ」を特定します。ただし本来実行したい操作としては上記「無効な状態の場合」のときと同様で、「読取り専用な状態でない場合に処理をする」であるため、Guarded Choiceの指定条件も Location Found（ロケーションが見つかった場合）ではなく Location Not Found（ロケーションが見つからなかった場合）に切り替えます。

つまりこのケースの場合は総合するとテキストボックスが有効な場合を特定するために、「無効でもなく」「読み取り専用でもない」場合に処理を継続するという２段階の確認が必要になります。（ややこしい）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/fae46a96-37aa-dde4-2eed-caa0027bfd76.png)
この対応によりコンポーネントの状態が正しくファインダーで捉えられるようになるため、アプリケーションの状態変化を自動的に判断しDAが安定して動くようになります。


:::note info
Windowsアプリではなく、WebサイトをIEやChromiumにて自動化する際には「ツリーの変更停止」を画面の描画前に配置することでブラウザ内の状態変化を自動的に感知してくれます。
:::
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/c6d4210b-3faf-dea2-ae30-7dfa66aae39e.png)

## 番外編

今回は Chromium でWebサイトを読み込んだ時を例にコンポーネントの状態確認を行いましたが、これがIEでWebサイトを操作した場合や通常のWindowsアプリケーションを操作する場合には Widget TreeとしてDA内に展開されるオブジェクトの構成や属性が変わってきますので、上記の考え方をベースとして実際にはそれぞれケースバイケースにて対応を行う必要があります。

###### Windows アプリの場合
下の例を見る限りでは、`isEnabled="true"` という属性のある場合に受付状態が有効と判断できそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/809ba840-2cc2-60ce-4450-a2b00c9d165e.png)


## まとめ

おそらく `DAの動作が安定しないため、固定WAIT（「秒が経過した時」）を入れてタイミングを合わせつつ運用しています。` という方はこれらの対応をせずに目隠しでリズムを取っているようなものなので、本件一考してみるのは非常に価値の高いものだと思います。

:::note alert
本件はあくまでもお使いのアプリケーションの特性によりDAが安定しない場合に対処する方法であり、無暗やたらとロボットに同様の処理を組み込むことは推奨していません。無駄な処理となってしまいます。
:::


[^1]: 例えば画面上にボタンが存在しそのボタンをクリックしたとしてもボタン自体が無効化されている場合にはクリック操作は受け付けられず、結果何も起こらない（空振ってしまう）ことになります。