LoginSignup
22
18

More than 5 years have passed since last update.

Selenium IDE(2018/12/06現行版)からselenium-webdriverのjsコードに変換する

Last updated at Posted at 2018-12-05

DMM.com Advent Calendar 2018 6日目の記事です。

おはようございます、アドテクノロジー部の津久井(@kkkdev )と申します。
前職は MotecoBeautyというスマホアプリやアドフリくんという国産SSP等の開発に携わっており、
昨年12月にDMMに参画いたしました。

アドテクと自動テストによるQA(品質保証)の関連性

クロスブラウザ・モバイルOS....

ブラウザ / モバイル実機による検証・および自動化は、webサービスやモバイルアプリ開発者のみならず
アドネットワークやSSP等のアドテク界隈でも重要視されています。

参考: QA(品質保証)チームによる実機端末をつかった自動/手動テストの裏側(アドテクセンター通信)

自動化のミドルウェアはいくつか知られていますが、今回はその中から、古くから
ブラウザの自動テストに用いられているSeleniumと、ブラウザ操作の記録ツール
「Selenium IDE」にまつわる子ネタ(表題)を1点ピックアップして紹介いたします。

Selenium IDEの歴史

Selenium IDE自体は2004年(!)よりThoughtWorks社によって開発が始まった自動化フレームワークです。
おそらくエンジニアの方なら公私のどちらかで1度は触れてみたことがあるのではないでしょうか。

スタンドアロンのSeleniumが潰れた!

まず最初に、表題の機能は現行のSelenium IDEには搭載されておりません。

詳しい説明は [2018年時点] Selenium IDE についてまとめてみた にまとめられていますが、Firefox 55から
(旧)Selenium IDEが使えなくなりました。

現在全てを刷新した現行Selenium IDEがブラウザ拡張機能(Chrome,Firefox)で提供されていますが、旧版
に比べ、 さながらLight版程度の機能になっています。(動作を記録して、独自のファイルに保存するのみ)

潰れた結果、コードへの変換が出来なくなった!

前述の刷新でスタンドアロン版で実装されているSelenium IDE -> selenium-webdriverへのコード変換の
機能も消えてしまい、独自の.sideファイル(Selenium IDEのベースとなるSideeXに起因する)での保存のみとなりました。

Selenium IDEで出力した.sideを「Selianize」でコード変換

(本投稿は結局このnpmライブラリを紹介するだけの中身なのですが)
あまり(というかほとんど)言及されているのを見たことがありませんが、実はSelenium IDEのリポジトリには
Selianizeという selenium-webdriver 用のコード変換用のライブラリが同梱されています。
(単独のnpmライブラリとしても利用可)

今回はこのSelianizeで実際前述の.sideファイルをにselenium-webdriver用のコードに
変換&出力する手順を、以下に記載していきます。

手順

Googleで「まなびストレート」を検索&該当のwikiページから林原めぐみ氏のページに飛ぶ操作を記録します。
(中身自体に意味はありません)

※Selenium IDE自体の記述は最小限操作程度です

事前準備. ChromeにSelenium IDEの拡張

Selenium IDE(Chrome拡張)をインストールしておく

※Firefoxの場合は https://addons.mozilla.org/ja/firefox/addon/selenium-ide

1. Selenium IDEで操作を記録する

割愛 (参考 : https://qiita.com/gluelan2013/items/0513c5331b6a67086308)

※各Commandのリファレンス的なものは、ベースになっているSideeXのページが参考になるかも

操作の自動記録以外に 直接Selenium IDEを操作して手順を追加することも可能です。
sleep / run script の Command などは のこの手段でIDE上から実装を行えます。
1点補足すると、Command によってはSideeXのリファレンス(兼 公式)通り
Targetの引数に 値を入れることもあります。どうも直感的ではないですが......

[たとえば、pauseコマンドに設定するミリ秒はTargetに書く]
スクリーンショット 2018-12-03 16.35.39.png

2. Selenium IDEから.sideファイル(操作手順を記録したファイル)をローカルに保存

記録した手順を、IDEの右上から「Save Project」でから.sideファイルに保存します。

3. 「Selianize」モジュールを読み込み、selenium-webdriverコードに変換するnode.jsの実装を行う

.sideを読み、WebDriverIOコードに変換するnode.jsコード

"use strict"

const selianize = require('selianize').default;
const fs = require('fs');


(async () => { 
    //.sideの読み込み & JSONをパース
    const project = JSON.parse(
        fs.readFileSync('sample.side')
    );
    const selianized = await selianize(project);
    //変換後のプロジェクトを表示
    console.log(selianized);
})()

上記の実行結果は以下です。

{ globalConfig: 'global.Key = require(\'selenium-webdriver\').Key;global.URL = require(\'url\').URL;global.BASE_URL = configuration.baseUrl || \'https://www.google.co.jp\';let vars = {};',
  suites: 
   [ { name: 'Default Suite',
       persistSession: false,
       code: 'jest.setTimeout(300000);describe("Default Suite", () => {it("AAA", async () => {await tests["AAA"](driver, vars);await driver.getTitle().then(title => {expect(title).toBeDefined();});});});',
       tests: undefined,
       snapshot: undefined } ],
  tests: 
   [ { id: '51404450-7b46-4f36-b443-b56386b206ee',
       name: 'AAA',
       code: 'tests["AAA"] = async (driver, vars, opts) => {await driver.get((new URL("/", BASE_URL)).href);await driver.manage().window().setSize(...(`1306x847`.split("x").map((s) => parseInt(s))));await driver.wait(until.elementLocated(By.name(`q`)), configuration.timeout);await driver.findElement(By.name(`q`)).then(element => {element.clear().then(() => {element.sendKeys(`まなびすと`);});});await driver.wait(until.elementLocated(By.css(`div.sbl1 > span`)), configuration.timeout);await driver.findElement(By.css(`div.sbl1 > span`)).then(element => {element.click();});await driver.wait(until.elementLocated(By.css(`h3.LC20lb`)), configuration.timeout);await driver.findElement(By.css(`h3.LC20lb`)).then(element => {element.click();});await driver.wait(until.elementLocated(By.css(`dd > dl > dd > a`)), configuration.timeout);await driver.findElement(By.css(`dd > dl > dd > a`)).then(element => {element.click();});}',
       snapshot: undefined } ] }

各要素ごとに、selenium-webdriverのjsコードが文字列として返却されているのがわかります。

globalConfig (初期設定)
global.Key = require('selenium-webdriver').Key;
global.URL = require('url').URL;
global.BASE_URL = configuration.baseUrl || 'https://www.google.co.jp';
let vars = {};
suites[].code (jestのテストコードの雛形)
jest.setTimeout(300000);
describe("Default Suite", () => {
    it("AAA", async () => {
        await tests["AAA"](driver, vars);
        await driver.getTitle().then(title => {
            expect(title).toBeDefined();
        });
    });
});
tests[].code (実際の動作のコード)
async (driver, vars, opts) => {
    await driver.get((new URL("/", BASE_URL)).href);
    await driver.manage().window().setSize(...(`1306x847`.split("x").map((s) => parseInt(s))));
    await driver.wait(until.elementLocated(By.name(`q`)), configuration.timeout);
    await driver.findElement(By.name(`q`)).then(element => {
        element.clear().then(() => {
            element.sendKeys(`まなびストレート`);
        });
    });
    await driver.wait(until.elementLocated(By.css(`div.sbl1 > span`)), configuration.timeout);
    await driver.findElement(By.css(`div.sbl1 > span`)).then(element => {
        element.click();
    });
    await driver.wait(until.elementLocated(By.css(`h3.LC20lb`)), configuration.timeout);
    await driver.findElement(By.css(`h3.LC20lb`)).then(element => {
        element.click();
    });
    await driver.wait(until.elementLocated(By.css(`dd > dl > dd > a`)), configuration.timeout);
    await driver.findElement(By.css(`dd > dl > dd > a`)).then(element => {
        element.click();
    });
}

globalConfig は 定型文かなー、と思いきや、開始地点のURLもここで定義されていますね....

4. あとはよしなに

上記のコードを保存なりevalなり

Selenium IDE自体の使い所(現行版)

コミュニケーションツールとして

Selenium IDE(現行版)には 例えばselenium-webdriverでよく使われるスクリーンショット等の
機能は無く、記録したものをそのまま使うには機能不足感は否めません。なので、

・非エンジニアのメンバーに記録してもらう
・操作を再現した.sideファイルを渡す事により、実現したい内容に対するメンバー間の齟齬を無くす
(長ったらしい仕様書を書いた上、それが間違っているという悲劇を防ぐ)

上記のようなコミュニケーションにおける補助的なツールになれば御の字かな....と思います。

javascriptに変換できるのはSelianizeだけ!(知る限り)

実はSelenium IDEと同様の操作記録ツールには 強化版とも言えるKatalon Recorderという
Chrome拡張が存在し、こちらは既にコード出力機能が実装済です。

ただnode.jsによるjavascriptコードの出力は未対応になっており (現在 C# / JAVA / Python / Ruby 対応)、
node.jsのselenium-webdriverによる実装を行いたい場合には Selenium IDE + Selianize を使うのが
ベストかな....と考えています。

その他

現行のSelenium IDE自体もまだまだこれから + Appiumなどのアプリ向け自動化フレームワークは
機械学習を取り入れ始め、なかなか面白い動きを見せているというところもあり、今後の
IDEアップデートに期待しつつ、自動化界隈のアクションをマクロな視点で注視したいところです。

最後に

アドテクノロジー部は今年4年に発足したばかりの組織ですが、松本新CTOの元(明日は松本さんの記事です!)、

2019年は本格的に活動の幅を広げ、飛躍と貢献の流れに繋げられればと思っております!(します)

22
18
2

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
22
18