2012-04-17

SafariDriverの使い方

先日、Seleniumのバージョン2.21がリリースされ、SafariDriverという新たなドライバが加わりました。名前から分かる通り、Apple製のブラウザであるSafariを動かすためのドライバです。

これまで、IE、FirefoxGoogle ChromeOperaAndroidiPhone(iOS版 Safari)用のドライバはありましたが、デスクトップ版Safari用のドライバはありませんでした。Selenium RCを使えばSafariでもテストを動かすことは可能でしたが、JavaScriptのサンドボックスによる制限を回避できなかったり、新しいWebDriver APIが使えないなどの欠点がありました。

今回新しく追加されたSafariDriverは、サーバ部分がSafariの機能拡張として実装されており、前述した問題を解決するものになっています。

準備

SafariDriverを使うためには、機能拡張のビルドからインストールまでを自分で行う必要があります(2012年4月17日現在)。今回はその方法について解説したいと思います。

なお、SafariDriverを使うためにはバージョン5.0以上のSafariが必要になりますので、注意してください。

Safari Developer Programへの登録

Safariに独自の機能拡張をインストールする場合、デベロッパ証明書が必要になります。証明書を取得するために、まずはSafari Developer Programの登録を行います。

Safari Developer Program – Apple Developer

上記のURLにアクセスし、「今すぐ参加する」から登録を開始します。

新規登録か、既にAppleデベロッパとして登録済みかどうかを聞かれますので、自身の状況に適切な選択肢を選んで下さい。

私の場合は新規登録で、かつApple IDを持っていたので、「Safariデベロッパプログラムに登録するにあたり現在持っているApple IDを使用します。」を選択しました。

ここから先の画面は選んだ選択肢によって変わってきますが、大きくは変わらないと思うので、私が選んだ選択肢を基準に説明していきます。

次は、個人で登録するか会社で登録するかを聞かれます。私は個人を選択しました。

Apple IDを入力します。

確認画面が表示されるので、問題が無ければ「Continue」をクリック。

使用許諾契約。

登録完了です。「Get Started」をクリックしてメンバーセンターへ。

証明書の取得

登録が完了したので、次は証明書を取得します。メンバーセンターの画面中央あたりにある「Developer Certificate Utility」のアイコンをクリックします。

「Create Certificates」をクリック。

「Add Certificate」をクリック。

証明書の取得に必要な、証明書署名要求(CSR)というものを作成する手順が表示されます。

証明書署名要求を作成する手順はOSによって異なるようです。ここではMacでの作成手順を紹介していますが、Windowsを使用している方は@os0xさんの記事を参照してみてください。

Safari拡張の作り方 – 0xFF

Macで証明書署名要求を作成するには、キーチェーンアクセス.appを使用します。キーチェーンアクセスのメニューから、「証明書アシスタント」 >「 認証局に証明書を要求…」 を選択します。

以下のような画面が表示されるので、「メールアドレス」、「通称」を入力し、「ディスクに保存」を選択後、「続ける」をクリックして下さい。証明書署名要求を保存する場所を聞かれるので、適当な場所を選択して保存します。

これで証明書署名要求が作成できました。

ブラウザに戻って、証明書署名要求の作成手順が表示されている画面から「Continue」をクリックすると、証明書署名要求をアップロードする画面が表示されるので、先ほど作成したファイルを選択し、「Generate」をクリックします。

証明書の発行中…

発行完了!「Continue」で次へ。

発行された証明書をダウンロードします。「Download」ボタンから証明書を適当な場所へ保存します。

ダウンロードした証明書のファイルをダブルクリックすれば、自動的に証明書がインストールされます。これで機能拡張をインストールする準備は完了です。

機能拡張のビルド

次はSafariDriverの機能拡張をビルドして、インストール用のファイルを作成します。ビルド自体は簡単で、必要なファイルをSeleniumリポジトリからチェックアウトし、ビルド用のコマンドを叩くだけです。

$ svn checkout http://selenium.googlecode.com/svn/tags/selenium-2.21/ selenium-2.21
$ cd selenium-2.21
$ ./go safari

ビルドが完了するとbuild/javascript/safari-driverの下にSafariDriver.safariextensionが作られているはずです。これがSafari機能拡張のファイルです。

機能拡張のインストール

作成した機能拡張を、Safariにインストールします。まず、Safariのメニューから環境設定を開き、「詳細」をクリックしてから、「メニューバーに“開発”メニューを表示」を選択します。これでメニューバーに「開発」という項目が増えるので、そこから「機能拡張ビルダーを表示」を選択します。

機能拡張ビルダーのウィンドウの左下に「+」というボタンがあるので、そこから「機能拡張を追加」を選択し、そこで先ほど作成したSafariDriver.safariextensionを選択します。画面に機能拡張が追加されるので、「インストール」をクリックすれば、機能拡張のインストールは完了です。

動かしてみる

ここまででSafariDriverを使うための準備は整いました。実際にSafariDriverでSafariを動かしてみましょう。以下のようなクラスを作成し、実行してみてください。

import static org.openqa.selenium.support.ui.ExpectedConditions.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

public class SafariDriverTest {

    private WebDriver driver;

    @Before
    public void createDriver() {
        driver = new SafariDriver();
    }

    @After
    public void quitDriver() {
        driver.quit();
    }

    @Test
    public void shouldBeAbleToPerformAGoogleSearch() {
        driver.get("http://www.google.co.jp/");
        driver.findElement(By.name("q")).sendKeys("webdriver");
        driver.findElement(By.name("btnG")).click();
        new WebDriverWait(driver, 5).until(titleIs("webdriver - Google 検索"));
    }

}

Safariが起動し、Googleのページが開いたでしょうか?

SafariDriverで出来ないこと

SafariDriverは開発途上なので、以下の機能はまだ実装されていないようです。

  • executeScript()メソッドによるJavaScriptの実行
  • フレームの切り替え
  • ドラッグ&ドロップなどを実現するための、インタラクションAPI

この他にも既知のバグなどがあるようなので、実際に使う際は注意してください。

参考

2012-02-24

WebDriverで無限になめこを抜き続ける

f:id:hutyao:20120224032929p:plain

タイトルだけ見たら意味不明ですね。
元ネタはこちらのサイト。

以下が無限になめこを抜き続けるコードです。

import org.openqa.selenium.By;
import org.openqa.selenium.Mouse;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.MoveMouseAction;
import org.openqa.selenium.internal.Locatable;
import org.openqa.selenium.remote.RemoteWebDriver;

public class NamekoDrive {

    public static void main(String[] args) {
        System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver"); // path to chromedriver binary
        RemoteWebDriver driver = new ChromeDriver();

        try {
            driver.get("http://s6.ql.bz/~iqp/nameko/nameko.html");
            Mouse mouse = driver.getMouse();
            String namekoId;
            WebElement namekoElement;

            while (true) {
                for (int i = 0; i < 6; i++) {
                    for (int j = 0; j < 6; j++) {
                        namekoId = "obj_" + j + "_" + i;
                        namekoElement = driver.findElement(By.id(namekoId));
                        new MoveMouseAction(mouse, (Locatable) namekoElement).perform();
                    }
                }
            }
        } catch (WebDriverException ignore) {
            System.out.println("Interrupted...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (driver != null) {
                driver.quit();
            }
        }
    }

}

なぜかFirefoxDriverだと最左段と最下段のなめこが抜けなかったので、ChromeDriverでやっています。ひたすら抜き続けますが、飽きたときは普通にブラウザを落としてください。

意外とスピードが出なかったのが残念。

2012-02-19

モダンなJSライブラリのディレクトリ構成まとめ

JavaScriptのプロジェクトを新しく作るにあたってディレクトリ構成をどうするか悩んだので、オープンソースのライブラリなどを参考にすることに。ということで、モダンなJavaScriptライブラリ・フレームワークのディレクトリ構成をまとめてみました。

モダンと言ってはいますが、全然モダンじゃないライブラリも混ざってるかもしれないです。

jQuery

jquery
├── build
│   └── lib
├── speed
├── src
│   ├── ajax
│   └── sizzle
└── test
    ├── data
    │   ├── offset
    │   ├── selector
    │   └── support
    ├── qunit
    └── unit

jQuery Mobile

jquery-mobile
├── build
├── css
│   ├── structure
│   └── themes
│       ├── default
│       │   └── images
│       └── valencia
│           └── images
├── docs
│   ├── _assets
│   │   ├── css
│   │   ├── images
│   │   └── js
│   ├── about
│   ├── api
│   ├── buttons
│   ├── config
│   ├── content
│   ├── forms
│   │   ├── checkboxes
│   │   ├── radiobuttons
│   │   ├── search
│   │   ├── selects
│   │   ├── slider
│   │   ├── switch
│   │   └── textinputs
│   ├── lists
│   │   └── images
│   ├── pages
│   │   ├── docs-links-urltest
│   │   ├── dynamic-samples
│   │   └── pages-themes
│   └── toolbars
│       ├── glyphish-icons
│       └── images
├── experiments
│   └── scrollview
├── external
│   ├── r.js
│   │   └── dist
│   └── requirejs
├── js
├── tests
│   ├── functional
│   └── unit
│       ├── button
│       ├── buttonMarkup
│       ├── checkboxradio
│       ├── collapsible
│       ├── controlgroup
│       ├── core
│       ├── degradeInputs
│       ├── dialog
│       ├── event
│       ├── fieldContain
│       ├── fixedToolbar
│       ├── init
│       ├── listview
│       │   └── cache-tests
│       ├── media
│       ├── navbar
│       ├── navigation
│       │   ├── base-tests
│       │   │   ├── app-base
│       │   │   └── content
│       │   ├── data-url-tests
│       │   ├── dialog-param-test
│       │   ├── form-tests
│       │   └── path-tests
│       │       ├── parent
│       │       └── sub-dir
│       ├── page
│       ├── page-sections
│       ├── select
│       ├── slider
│       ├── support
│       ├── textinput
│       ├── widget
│       └── zoom
└── tools

Prototype

prototype
├── dist
├── doc_assets
│   └── images
├── ext
│   └── update_helper
├── src
│   └── prototype
│       ├── ajax
│       ├── dom
│       └── lang
├── test
│   ├── functional
│   └── unit
│       ├── caja_whitelists
│       ├── fixtures
│       └── templates
└── vendor
    ├── caja_builder
    ├── legacy_selector
    │   └── repository
    ├── nwmatcher
    │   └── repository
    ├── pdoc
    ├── sizzle
    │   └── repository
    ├── slick
    │   └── repository
    ├── sprockets
    └── unittest_js

MooTools

mootools-core
├── Docs
│   ├── Browser
│   ├── Class
│   ├── Core
│   ├── Element
│   ├── Fx
│   ├── Request
│   ├── Slick
│   ├── Types
│   └── Utilities
├── Packager
├── Source
│   ├── Browser
│   ├── Class
│   ├── Core
│   ├── Element
│   ├── Fx
│   ├── Request
│   ├── Slick
│   ├── Types
│   └── Utilities
└── Specs
    ├── 1.2
    │   ├── Class
    │   ├── Core
    │   ├── Element
    │   ├── Native
    │   └── Utilities
    ├── 1.3base
    │   ├── Class
    │   ├── Core
    │   ├── Fx
    │   └── Types
    ├── 1.3client
    │   ├── Browser
    │   ├── Class
    │   ├── Core
    │   ├── Element
    │   ├── Fx
    │   ├── Request
    │   ├── Types
    │   └── Utilities
    ├── 1.4base
    │   └── Types
    ├── 1.4client
    │   ├── Element
    │   └── Fx
    ├── 2.0base
    │   ├── Core
    │   └── Types
    ├── 2.0client
    │   └── Browser
    └── Runner

Sizzle

sizzle
├── speed
│   ├── frameworks
│   └── system
└── test
    ├── data
    └── unit

Underscore.js

underscore
├── docs
│   └── images
└── test
    └── vendor

Backbone.js

backbone
├── docs
│   └── images
├── examples
│   └── todos
└── test
    └── vendor

Modernizr

Modernizr
├── feature-detects
├── media
└── test
    ├── caniuse_files
    ├── js
    │   └── lib
    └── qunit

Raphaël

raphael
├── plugins
└── test
    ├── image
    └── vendor

UglifyJS

UglifyJS
├── bin
├── lib
├── test
│   └── unit
│       └── compress
│           ├── expected
│           └── test
└── tmp

psd.js

psd.js
├── deps
├── docs
├── lib
├── src
└── test

pdf.js

pdf.js
├── examples
│   ├── acroforms
│   └── helloworld
├── extensions
│   ├── chrome
│   └── firefox
│       └── components
├── external
│   ├── jasmine
│   ├── jasmineAdapter
│   ├── jpgjs
│   └── jsTestDriver
├── src
│   └── utils
├── test
│   ├── pdfs
│   ├── resources
│   │   ├── browser_manifests
│   │   └── firefox
│   │       └── extensions
│   │           └── special-powers@mozilla.org
│   │               ├── chrome
│   │               │   └── specialpowers
│   │               │       └── content
│   │               └── components
│   └── unit
│       └── test_reports
└── web
    └── images

three.js

three.js
├── build
│   └── custom
├── doc
│   └── api
│       ├── cameras
│       ├── core
│       ├── extras
│       │   └── core
│       └── lights
├── examples
│   ├── ctm
│   │   └── camaro
│   ├── fonts
│   │   └── droid
│   ├── js
│   │   ├── ctm
│   │   │   └── license
│   │   └── postprocessing
│   ├── models
│   │   └── animated
│   │       └── monster
│   ├── obj
│   │   ├── blenderscene
│   │   ├── buffalo
│   │   ├── camaro
│   │   ├── cubecolors
│   │   ├── f50
│   │   ├── female02
│   │   ├── gallardo
│   │   │   └── parts
│   │   ├── leeperrysmith
│   │   ├── lucy
│   │   ├── male02
│   │   ├── ninja
│   │   ├── suzanne
│   │   ├── veyron
│   │   │   └── parts
│   │   └── walt
│   ├── scenes
│   ├── sounds
│   ├── textures
│   │   ├── cube
│   │   │   ├── Bridge2
│   │   │   ├── Escher
│   │   │   ├── Park2
│   │   │   ├── Park3Med
│   │   │   ├── SwedishRoyalCastle
│   │   │   ├── pisa
│   │   │   └── skybox
│   │   ├── lava
│   │   ├── lensflare
│   │   ├── minecraft
│   │   ├── normal
│   │   │   └── ninja
│   │   ├── patterns
│   │   ├── planets
│   │   ├── sprites
│   │   └── terrain
│   └── utf8
├── gui
│   ├── files
│   └── js
│       └── libs
├── src
│   ├── cameras
│   ├── core
│   ├── extras
│   │   ├── animation
│   │   ├── cameras
│   │   ├── controls
│   │   ├── core
│   │   ├── geometries
│   │   ├── helpers
│   │   ├── loaders
│   │   ├── modifiers
│   │   ├── objects
│   │   ├── plugins
│   │   ├── renderers
│   │   └── shaders
│   ├── lights
│   ├── materials
│   ├── objects
│   ├── renderers
│   │   └── renderables
│   ├── scenes
│   └── textures
└── utils
    ├── compiler
    └── exporters
        ├── blender
        │   └── 2.60
        │       └── scripts
        │           └── addons
        │               └── io_mesh_threejs
        ├── ctm
        ├── fbx
        │   └── modules
        │       └── win
        │           └── Python26_x86
        ├── max
        ├── obj
        └── utf8

Knockout.js

knockout
├── build
│   ├── fragments
│   ├── output
│   └── tools
├── spec
│   └── lib
│       └── qunit
└── src
    ├── binding
    │   └── editDetection
    ├── subscribables
    └── templating
        ├── jquery.tmpl
        └── native

RequireJS

requirejs
├── dist
│   └── fonts
│       └── PT-Sans
├── docs
│   └── design
└── tests
    ├── anon
    │   └── sub
    ├── browsertests
    │   ├── appendbeforeload
    │   ├── async
    │   ├── docwritenested
    │   ├── noload
    │   ├── onerror
    │   ├── scriptload
    │   ├── scriptloadinteractive
    │   ├── scriptloadinteractiveattach
    │   └── vardefine
    ├── circular
    │   └── complexPlugin
    ├── commonjs
    │   └── tests
    │       └── modules
    │           └── 1.0
    │               ├── absolute
    │               │   └── submodule
    │               ├── cyclic
    │               ├── determinism
    │               │   └── submodule
    │               ├── exactExports
    │               ├── hasOwnProperty
    │               ├── method
    │               ├── missing
    │               ├── monkeys
    │               ├── nested
    │               │   └── a
    │               │       └── b
    │               │           └── c
    │               ├── relative
    │               │   └── submodule
    │               └── transitive
    ├── defineError
    ├── doh
    │   └── _sounds
    ├── domReady
    ├── exports
    ├── i18n
    │   └── nls
    │       ├── en-us-surfer
    │       └── fr
    ├── jquery
    │   └── scripts
    ├── jsonp
    ├── layers
    ├── nestedDefine
    ├── order
    ├── packages
    │   ├── bar
    │   │   └── 0.4
    │   │       └── scripts
    │   ├── baz
    │   │   └── lib
    │   ├── dojox
    │   │   └── window
    │   ├── foo
    │   │   └── lib
    │   ├── funky
    │   │   └── lib
    │   ├── optimizing
    │   │   └── packages
    │   │       ├── engine
    │   │       ├── fuel
    │   │       └── tires
    │   └── pkgs
    │       ├── alpha
    │       ├── beta
    │       │   └── 0.2
    │       │       └── scripts
    │       └── dojox
    │           ├── chair
    │           └── table
    ├── paths
    │   ├── first.js
    │   └── impl
    ├── plugins
    │   ├── fromText
    │   ├── prime
    │   └── textDepend
    ├── priority
    │   └── priorityWithDeps
    │       ├── script
    │       │   ├── lib
    │       │   └── req
    │       │       └── utils
    │       └── style
    ├── relative
    │   ├── foo
    │   │   └── bar
    │   ├── greek
    │   └── outsideBaseUrl
    │       ├── a
    │       └── b
    ├── remoteUrls
    ├── text
    │   └── resources
    ├── uniques
    ├── universal
    ├── urlfetch
    ├── version1
    └── version2

HeadJS

headjs
├── dist
├── src
└── tests
    ├── manual-tests
    └── qunit

LABjs

LABjs
└── tests

EaselJS

EaselJS
├── build
│   ├── template
│   │   └── assets
│   └── tools
│       ├── google-closure
│       └── yuidoc
│           ├── bin
│           ├── ext
│           └── template
│               └── assets
├── docs
├── examples
│   ├── game
│   ├── img
│   ├── modernizr
│   └── styles
├── lib
└── src
    └── easeljs
        ├── display
        ├── events
        ├── filters
        ├── geom
        ├── ui
        └── utils

History.js

history.js
├── demo
├── scripts
│   ├── bundled
│   │   ├── html4+html5
│   │   └── html5
│   ├── compressed
│   └── uncompressed
├── tests
├── tests.src
└── vendor
    └── qunit
        ├── qunit
        └── test

enchant.js

enchant.js
├── dev
│   └── plugins
├── doc
│   ├── en
│   │   ├── javascript
│   │   └── symbols
│   ├── ja
│   │   ├── css
│   │   │   └── fonts
│   │   ├── javascript
│   │   └── symbols
│   ├── javascript
│   └── template
│       ├── css
│       │   └── fonts
│       ├── javascript
│       └── subtemplates
├── examples
│   ├── action
│   ├── gl
│   │   ├── bounding
│   │   ├── camera
│   │   ├── collada
│   │   ├── enchantjs
│   │   ├── quaternion
│   │   └── shape
│   ├── rpg
│   ├── shooting
│   └── util
├── images
├── ja
│   └── plugins
├── plugins
│   └── libs
└── tests

Paper.js

paper.js
├── build
│   └── jsdoc-toolkit
├── dist
│   └── docs
│       ├── classes
│       └── resources
│           ├── css
│           │   └── assets
│           └── js
├── examples
│   ├── Animated
│   ├── Games
│   ├── Node.js
│   ├── Rasters
│   ├── Scripts
│   ├── Tools
│   └── css
├── lib
├── node.js
├── src
│   ├── basic
│   ├── browser
│   ├── color
│   ├── core
│   ├── docs
│   ├── item
│   ├── path
│   ├── project
│   ├── style
│   ├── text
│   ├── tool
│   ├── ui
│   └── util
└── test
    ├── lib
    │   └── qunit
    └── tests

Zepto.js

zepto
├── examples
│   ├── iphone
│   └── snow
├── spec
│   └── javascripts
│       ├── helpers
│       └── support
├── src
├── test
│   └── fixtures
└── vendor
    ├── google-compiler
    └── yuicompressor

SeaJS

seajs
├── build
├── docs
│   ├── assets
│   ├── demo
│   │   ├── calculator
│   │   │   └── online
│   │   ├── coffee-and-less
│   │   ├── hello-seajs
│   │   ├── spinning-icons
│   │   └── todos
│   └── zh-cn
├── lib
├── src
│   └── plugins
├── support
└── test
    ├── bootstrap
    ├── issues
    │   ├── anonymous
    │   ├── anywhere
    │   ├── combo-use
    │   ├── config-base
    │   │   └── js
    │   │       ├── biz
    │   │       │   └── sub
    │   │       └── xxlib
    │   │           └── 1.0.0
    │   ├── config-conflict
    │   ├── data-main
    │   ├── debug
    │   ├── duplicate-load
    │   ├── ie-cache
    │   ├── inline-module
    │   ├── jsonp
    │   ├── load-css
    │   ├── load-deps
    │   ├── local-files
    │   ├── map
    │   │   ├── build
    │   │   └── libs
    │   │       └── build
    │   ├── module-extend
    │   ├── multi-map
    │   ├── multi-use
    │   ├── multi-versions
    │   ├── no-conflict
    │   ├── onload
    │   ├── parse-deps
    │   ├── plugin-coffee
    │   ├── plugin-json
    │   ├── plugin-less
    │   ├── plugin-map
    │   ├── plugin-text
    │   ├── preload
    │   ├── preload-ie
    │   ├── remove-comments
    │   ├── require-extend
    │   ├── seajs-map
    │   │   └── sub
    │   ├── timestamp
    │   └── un-correspondence
    ├── modules
    │   ├── alias
    │   │   └── submodule
    │   │       └── sub
    │   ├── checkPotentialErrors
    │   ├── configMap
    │   │   └── sub
    │   ├── cyclic
    │   ├── define
    │   ├── determinism
    │   │   └── submodule
    │   ├── exactExports
    │   ├── exports
    │   ├── extend
    │   ├── hasOwnProperty
    │   ├── load
    │   ├── math
    │   ├── metadata
    │   ├── method
    │   ├── missing
    │   ├── monkeys
    │   ├── nested
    │   │   └── a
    │   │       └── b
    │   │           └── c
    │   ├── preload
    │   ├── relative
    │   │   └── submodule
    │   ├── simplest
    │   ├── transitive
    │   └── version
    ├── packages
    │   ├── base
    │   └── math
    ├── research
    │   ├── load-js-css
    │   ├── onload-order
    │   │   └── result
    │   ├── reliability
    │   │   └── result
    │   └── style-order
    └── unit

CamanJS

CamanJS
├── adapters
├── dist
├── docs
├── examples
│   ├── browser
│   ├── images
│   └── node
├── proxies
├── src
│   ├── core
│   ├── lib
│   └── plugins
└── test
    ├── benchmark
    │   └── flot
    └── qunit

CasperJS

casperjs
├── bin
├── docs
├── modules
│   └── vendors
├── samples
└── tests
    ├── site
    │   └── images
    └── suites
        └── casper

Spine

spine
├── lib
├── src
└── test
    ├── lib
    └── specs

JavaScriptMVC

javascriptmvc
├── documentjs
├── funcit
├── funcunit
├── jmvc
│   ├── docs
│   ├── fonts
│   ├── images
│   │   ├── backgrounds
│   │   │   └── download
│   │   └── team
│   ├── pages
│   ├── scripts
│   ├── site
│   │   ├── scripts
│   │   └── views
│   └── stylesheets
├── jquery
├── mxui
├── scripts
├── steal
├── test
│   └── scripts
└── tutorials
    ├── ajaxy
    │   └── fixtures
    ├── examples
    │   └── contacts
    ├── getstarted
    ├── images
    ├── mvc
    └── rapidstart

AngularJS

angular.js
├── css
├── docs
│   ├── content
│   │   ├── api
│   │   ├── cookbook
│   │   ├── guide
│   │   └── misc
│   ├── examples
│   │   └── ng-include
│   ├── img
│   │   ├── guide
│   │   └── tutorial
│   ├── spec
│   └── src
│       └── templates
│           └── syntaxhighlighter
├── example
│   ├── buzz
│   ├── personalLog
│   │   ├── scenario
│   │   └── test
│   └── tweeter
├── i18n
│   ├── closure
│   ├── e2e
│   ├── locale
│   ├── spec
│   └── src
├── images
│   ├── css
│   ├── docs
│   │   ├── guide
│   │   │   ├── about_view.graffle
│   │   │   │   └── QuickLook
│   │   │   └── simple_scope.graffle
│   │   │       └── QuickLook
│   │   └── tutorial
│   │       ├── simple_scope.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_02.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_03.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_04-06.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_04.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_07.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_08-09.graffle
│   │       │   └── QuickLook
│   │       ├── tutorial_10-11.graffle
│   │       │   └── QuickLook
│   │       └── tutorial_proto.graffle
│   │           └── QuickLook
│   └── logo
│       └── Angular.graffle
│           └── QuickLook
├── lib
│   ├── closure-compiler
│   ├── htmlparser
│   ├── jasmine
│   ├── jasmine-jstd-adapter
│   ├── jquery
│   ├── jsl
│   ├── jstestdriver
│   ├── nodeserver
│   └── showdown
├── logs
├── perf
│   └── data
├── regression
├── src
│   ├── jstd-scenario-adapter
│   ├── scenario
│   │   └── output
│   ├── service
│   │   └── filter
│   └── widget
├── test
│   ├── jstd-scenario-adapter
│   ├── scenario
│   │   ├── e2e
│   │   └── output
│   ├── service
│   │   └── filter
│   └── widget
└── tmp

Benchmark.js

benchmark.js
├── doc
├── example
│   └── jsperf
├── plugin
├── test
│   └── benchmark.air
│       ├── bin-debug
│       └── src
└── vendor
    ├── docdown
    ├── platform.js
    ├── qunit
    ├── qunit-clib
    └── requirejs

Qwery

qwery
├── config
├── integration
├── mobile
│   └── src
├── pseudos
│   └── src
├── src
├── tests
└── vendor

Augment.js

augment.js
├── lib
└── test
    └── env

html2canvas

html2canvas
├── build
├── external
├── src
│   └── plugins
└── tests

Davis.js

davis.js
├── docs
├── examples
├── lib
│   ├── extensions
│   └── plugins
├── src
│   ├── extensions
│   └── plugins
└── tests
    ├── javascripts
    └── stylesheets

Moment.js

moment
├── lang
├── min
│   └── lang
└── test
    ├── lang
    └── non-lang

tween.js

tween.js
├── build
├── examples
│   ├── css
│   ├── js
│   └── video
├── src
└── utils

URI.js

URI.js
├── prettify
├── src
└── test
    └── qunit
2011-12-09

FirefoxDriver Tips

FirefoxDriverの使い方に関する少量のメモです。

Firefoxの設定を変更する

Firefoxでは、ブラウザの設定やアドオンのデータなどは全てプロファイルに紐付けられています。プロファイルのデータは特定のディレクトリに置かれており、Firefoxの起動時に読み込まれます。

ただし、FirefoxDriverを用いてFirefoxを起動した場合は既存のプロファイルは読み込まれません。常に新しいプロファイルが作成され、終了時に破棄されます。そのため、設定などはほとんど初期状態のままになります。起動時に独自の設定を反映させたい場合、Firefoxのプロファイルを扱うためのクラスが用意されているので、それを使います。

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("general.useragent.override", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
profile.setPreference("intl.accept_languages", "en-us, en");
WebDriver driver = new FirefoxDriver(profile);

FirefoxProfileというのが、プロファイルを扱うためのクラスです。
setPreference()メソッドは設定値を追加、変更します。一つ目の引数に設定名、二つ目の引数に設定値を指定します。設定値のタイプには、文字列、真偽値、整数値の三種類があるので、二つ目の引数にも、Stringintbooleanの三種類の型の値を渡すことができます。

上記の例では、general.useragent.overrideでユーザーエージェントを、intl.accept_languagesで言語設定を変更しています。

また、プロキシ設定の変更には専用のクラスが用意されているので、network.proxy.httpなどを直接弄るよりは、こちらを使ったほうが楽です。

Proxy proxy = new Proxy();
proxy.setHttpProxy("proxyhost:8080");
profile.setProxyPreferences(proxy);

アドオンをインストールする

FirefoxDriverを使ってFirefoxを起動する際に、任意のアドオンをインストールすることができます。インストールするには、あらかじめアドオンのファイルをダウンロードしておく必要があります。

FirefoxProfile profile = new FirefoxProfile();

// Firebugをインストール
File firebug = new File("firebug-1.8.4-fx.xpi");
profile.addExtension(firebug);
profile.setPreference("extensions.firebug.currentVersion", "1.8.4");

// FireMobileSimulatorをインストール
File firemobilesimulator = new File("firemobilesimulator-1.2.3-fx.xpi");
profile.addExtension(firemobilesimulator);
profile.setPreference("msim.current.carrier", "DC");
profile.setPreference("msim.current.id", "1");

WebDriver driver = new FirefoxDriver(profile);

ただし、この方法を用いると、アドオンのインストールや初期化処理によって、Firefoxの起動にかかる時間が増えてしまいます。一時的にアドオンを利用するだけならあまり問題はないのですが、恒久的にアドオンを使用するようなら、あらかじめアドオンをインストールしたプロファイルを用意しておき、それを次の方法で再利用するようにしたほうが効率的です。

既存のプロファイルを利用する

前に述べた通り、FirefoxDriverを用いてFirefoxを起動すると新たなプロファイルが作成されます。ただし、既存のプロファイルを指定して起動することも可能です。既存のプロファイルを用いるには、プロファイルのデータが含まれているディレクトリを以下のように指定します。

File profileDir = new File("myprofiledir");
FirefoxProfile profile = new FirefoxProfile(profileDir);
WebDriver driver = new FirefoxDriver(profile);

プロファイルディレクトリの場所でなく、プロファイル名を指定することもできます。
プロファイル名はプロファイルマネージャから確認できます。

ProfilesIni profilesIni = new ProfilesIni();
FirefoxProfile profile = profilesIni.getProfile("myprofile");
WebDriver driver = new FirefoxDriver(profile);

以下のような指定方法もあります。

System.setProperty("webdriver.firefox.profile", "myprofile");
WebDriver driver = new FirefoxDriver();

実行ファイルを指定する

Firefoxをデフォルトのインストール先と異なる位置にインストールしている場合、FirefoxDriverがFirefoxの実行ファイルを見つけられず、起動に失敗することがあります。こういった場合、自分自身で実行ファイルの位置を指定しなければなりません。

File binaryFile = new File("D:\\apps\\Mozilla Firefox\\firefox.exe");
FirefoxBinary binary = new FirefoxBinary(binaryFile);
WebDriver driver = new FirefoxDriver(binary, null);

FirefoxBinaryFirefoxの実行ファイルを扱うクラスです。実行ファイルを表すFileオブジェクトをコンストラクタの引数として受け取ります。

Macの場合の指定方法は以下のようになります。

File binaryFile = new File("/Applications/FirefoxBeta/Firefox.app/Contents/MacOS/firefox-bin");
FirefoxBinary binary = new FirefoxBinary(binaryFile);
WebDriver driver = new FirefoxDriver(binary, null);

以下の記述も同様です。

System.setProperty("webdriver.firefox.bin", "/Applications/FirefoxBeta/Firefox.app/Contents/MacOS/firefox-bin");
WebDriver driver = new FirefoxDriver();

一時ファイルを残す

あまり利用する場面はないと思いますが、WebDriverが作成する一時ファイルを削除しないようにすることができます。これにより、FirefoxDriverが作成した一時プロファイルを削除せずに残すことも可能です。

System.setProperty("webdriver.reap_profile", "false");
WebDriver driver = new FirefoxDriver();

ログをファイルに出力する

WebDriverが吐いたログをファイルに出力することができます。何かしら不審な挙動をしている際には、役に立つ情報になるかもしれません。

FirefoxProfile profile = new FirefoxProfile();
File logFile = new File("webdriver.log");
profile.setPreference("webdriver.log.file", logFile.getAbsolutePath());
WebDriver driver = new FirefoxDriver(profile);

新しい方法でのページの読み込み検出

Seleniumのバージョン2.9からの実験的な機能として、ページの読み込みが完全に完了するまで待機しない設定が可能になったらしいです。しかし、自分の環境ではうまく動きませんでした…。

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("webdriver.load.strategy", "fast");
driver = new FirefoxDriver(profile);