UWSCでIEを自動操作し,回帰テスト/JavaScript実行/ファイル保存 などができるライブラリ
※これより新しいバージョンがリリースされています。
http://language-and-engineering.hatenablog.jp/entry/20090826/p1
下記の「IEを自動操作するライブラリ」の改良版ができた。
UWSCで,IEを自動操作するためのライブラリ (ファイルアップロードも自動化できる)
http://language-and-engineering.hatenablog.jp/entry/20090729/p1
IEで
- ファイルのアップロード・ダウンロード (←selenium等の他ツールでは不可能)
- 簡易な回帰テスト
- 表示中のWebページに対するJavaScript実行
を含むようなオートメーションが可能。
まず,新ライブラリを利用したコードを掲載する。
次に,ライブラリそのものを掲載する。
こんなコードが書ける
use_google.uws
call .\IEManipulation.uws // IEを起動 _ie = IE.new() IE.show( _ie ) // Googleを開く IE.jump( _ie, "http://www.google.co.jp/" ) // 検索 IE.type( _ie, "q", "ゴッゴル" ) IE.click( _ie, "all" ) IE.click_and_wait( _ie, "btnG" ) // 関連キーワードを取得 first_result_link = _ie.document.getElementById( "res" ).getElementsByTagName("a").Item(0) msgbox( first_result_link.innerText ) IE.click_and_wait( _ie, first_result_link )
click_and_waitなどの関数の引数には
- "btnG"のようにDOM IDの文字列を渡す事もできるし,
- first_result_link のように,要素オブジェクトをそのまま渡す事もできる。
※ポリモーフィズム/オーバーロードに近い事をやろうとしている。
コーディングの際に考える事は少なくて済む。両方とも同一のメソッドでよい。
2サンプル目,JavaScriptを利用するケース:
use_js.uws
call .\IEManipulation.uws // IEを起動 _ie = IE.new() IE.show( _ie ) // Googleを開く IE.jump_with_js( _ie, "http://www.google.co.jp/" ) // JSコードをブラウザ側で実行 IE.export_js( _ie, "alert('hoge')" ) // JSコードの実行結果をUWSC側で取得 elem = IE.import_js( _ie, "document.body" ) msgbox( elem.innerHTML ) // 値をテストしてみる IE.type( _ie, "q", "hoge" ) IE.assert_value( _ie, "q", "hoge" ) //IE.assert_value( _ie, "q", "hogee" ) // これはfailedとして実行停止になる // 要素が存在するかテスト IE.wait_for_element_present( _ie, "q", 5 ) IE.wait_for_element_present( _ie, "aaaaaa", 5 )
jumpのかわりにjump_with_jsでURLを開くと,そのページにはJavaScriptを注入できる。
- export_jsで,ブラウザ側へJSコードを輸出してもよいし,
- import_jsで,UWSC側へJSコードの実行結果を輸入することもできる。
UWSCを使って,Webアプリケーションのかんたんな回帰テストを行なう事も可能。
- assert_valueで要素のvalueを検査
- assert_textで要素のinnerTextを検査
成功したらそのまま動作が進む。こけたらそこでエラーメッセージを出し,実行を止める。
wait_for_element_presentは,いまどきのWebサイトを表示する際には必須。
- setTimeoutとかで遅延して要素が読み込まれる場合とか
- Ajaxで非同期にページの一部が書き換わる場合とか
などで,ある要素が現れるまでポーズしてくれる。ポーズの秒数を具体的に指定しなくて済む。(タイムアウト秒数は指定するが。)
3サンプル目,ファイルのダウンロード:
use_dl.uws
call .\IEManipulation.uws _ie = IE.new() IE.show( _ie ) IE.jump( _ie, "http://cakeforge.org/frs/download.php/730/cake_1.3-dev.zip/donation=false" ) // ファイルへのリンク IE.click( _ie, _ie.document.getElementsByTagName("a").Item(2) ) // ダウンロードダイアログを処理 IE.save_downloaded_file( _ie ) msgbox("ダウンロード完了")
保存のダイアログに自動でEnterキーが押される。
デフォルトのダウンロードフォルダ(デスクトップとか)にファイルが保存される。
ライブラリ本体
ライブラリはclass化されている。
UWSCでのクラスはインスタンス化できないので,staticメソッドだけを持つようなclassだが,それでも
_ie = IE.new()
みたいな記法が可能になって,その分ついて行きやすい。
IEManipulation.uws
// // IEを自動操作するためのライブラリ ver 1.1 // class IE // -------------------- 制御 -------------------- // 新規IEオブジェクトを作成して返す function new() result = createOLEobj("InternetExplorer.Application") fend // 起動中のIEを見えるように procedure show( browser ) browser.visible = True wid = hndtoid( browser.hwnd ) acw( wid ) pause( browser ) fend // IEがビジー状態の間待ちます procedure wait( browser ) repeat sleep( 0.1 ) until ( ! browser.busy ) and ( browser.readystate = 4 ) pause( browser ) fend // URLにジャンプ procedure jump( browser, url ) browser.navigate( url ) wait( browser ) fend // ポーズ procedure pause( browser ) sleep( 0.2 ) fend // 要素が出現するまで待ちます procedure wait_for_element_present( browser, dom_id, timeout_sec ) interval_sec = 0.2 total_wait_sec = 0 loop_flag = True while loop_flag // 要素は現れたか ifb browser.document.getElementById( dom_id ) = Nothing then // 出現していないのでスリープ sleep( interval_sec ) total_wait_sec = total_wait_sec + interval_sec else // 出現したのでループ終了 loop_flag = false endif // タイムアウトか ifb total_wait_sec > timeout_sec then msgbox( "element '" + dom_id + "' did not appear." ) exitexit endif wend fend // -------------------- DOM操作 -------------------- // IDが渡された場合はDOM要素にして返します function to_elem( browser, locator ) ifb VarType( locator ) = 8 then // 変数の型が文字列の場合はDOM IDとみなす result = gid( browser, locator ) else // それ以外の場合はスルー result = locator endif // VarTypeのヘルプ:http://msdn.microsoft.com/ja-jp/library/cc392346.aspx fend // $ function gid( browser, dom_id ) result = browser.document.getElementById( dom_id ) fend // 入力 procedure type( browser, locator, str ) elem = to_elem( browser, locator ) elem.value = str pause( browser ) fend // クリック procedure click( browser, locator ) elem = to_elem( browser, locator ) elem.click pause( browser ) fend // クリックして待機 procedure click_and_wait( browser, locator ) click( browser, locator ) wait( browser ) fend // 文言ベースでセレクトボックスを選択 procedure select_by_label( browser, locator, label ) elem = to_elem( browser, locator ) for i = 0 to elem.options.length - 1 // 文言が一致するか ifb elem.options[ i ].innerText = label then elem.options[ i ].selected = True endif next pause( browser ) fend // 値ベースでセレクトボックスを選択 procedure select_by_value( browser, locator, val ) elem = to_elem( browser, locator ) for i = 0 to elem.options.length - 1 // 値が一致するか ifb elem.options[ i ].Value = val then elem.options[ i ].selected = True endif next pause( browser ) fend // indexベースでセレクトボックスを選択 procedure select_by_index( browser, locator, index ) elem = to_elem( browser, locator ) elem.options[ index ].selected = True pause( browser ) fend // ファイルアップロード // DOM IDではなくnameで要素を指定するので注意 procedure file_upload( browser, post_name, file_path ) IESetData( browser, file_path, post_name ) pause( browser ) fend // -------------------- JavaScriptの制御 -------------------- // URLにジャンプし,WebページにJSコードを注入する procedure jump_with_js( browser, url ) IE.jump( browser, url ) IE.create_js_proxy( browser ) fend // Webページ中にJS経由用のオブジェクトを生成して返す procedure create_js_proxy( browser ) doc = browser.document TextBlock js_proxy_code // UWSCからコード注入するためのオブジェクト document._uwsc_proxy = { global : this, _window : window, eval_code : function( str ){ try{ return eval( str ); }catch(e){ return null; } } }; endTextBlock // 生成 elem_s = doc.createElement("script") elem_s.text = js_proxy_code; elem_s.type = "text/javascript"; // 注入 doc.getElementsByTagName("head").Item(0).appendChild( elem_s ); fend // 文字列をJSコードとしてブラウザ側で評価 procedure export_js( browser, str_jscode ) browser.document._uwsc_proxy.eval_code( str_jscode ) fend // 文字列をJSコードとして評価した結果をUWSC側へ読み込み function import_js( browser, str_jscode ) // いったん文字列をブラウザ側にexportし,その結果をUWSC側にimport result = browser.document._uwsc_proxy.eval_code( str_jscode ) fend // -------------------- ファイルダウンロード用 -------------------- // ダイアログが現れるまで待機 procedure wait_for_dialog( dialog_title, timeout_sec ) interval_sec = 0.2 total_wait_sec = 0 loop_flag = True while loop_flag // ダイアログは現れたか ifb getid( dialog_title, "#32770", -1 ) > -1 then loop_flag = false else sleep( interval_sec ) total_wait_sec = total_wait_sec + interval_sec endif // タイムアウトか ifb total_wait_sec > timeout_sec then msgbox( "dialog '" + dialog_title + "' did not appear." ) exitexit endif wend fend // ダイアログにキーを送信 procedure send_dialog( dialog_title, key_code ) // 出現を待つ wait_for_dialog( dialog_title, 10 ) sleep(1) // キー押下 id = getid( dialog_title, "#32770", -1 ) sckey( id, key_code ) fend // ファイルのダウンロードダイアログが出たときに,ダウンロード+保存を実行 procedure save_downloaded_file( browser ) sleep(2) IE.send_dialog( "ファイルのダウンロード", vk_s ) IE.send_dialog( "名前を付けて保存", vk_return ) fend // -------------------- テスト実行用 -------------------- // 要素の値を検証 procedure assert_value( browser, locator, val_expected ) elem = to_elem( browser, locator ) val_real = elem.value assert( val_expected, val_real ) fend // 要素内の文字列を検証 procedure assert_text( browser, locator, val_expected ) elem = to_elem( browser, locator ) val_real = elem.innerText assert( val_expected, val_real ) fend // 文字列同士を比較 procedure assert( val_expected, val_real ) ifb val_expected = val_real then // OK else msgbox( "actual value '" + val_real + "' did not match '" + val_expected + "'" ) // スクリプトを強制終了 exitexit endif fend endclass
補足
自動テストならまずはSeleniumだが,ファイルのアップロード/ダウンロードはできない。
Selenium IDEだとFirefox限定になってしまう。
UWSCなら,IEで自動化できる。
そういう経緯で,回帰テストのために採用。
関連する記事:
UWSCのマクロで,IEを起動して自動操作するサンプルコード
http://language-and-engineering.hatenablog.jp/entry/20140204/controlIeBrowser...
JScript / VBScript (WSH)で,IEを自動操作しよう
http://language-and-engineering.hatenablog.jp/entry/20090713/p1
IE AutoTester で,UIの回帰テストを完全自動化
http://language-and-engineering.hatenablog.jp/entry/20090922/p1