8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

書籍「実践SeleniumWebDriver」のPageObjectパターンをRSpecでテストコードにしてみた。

Last updated at Posted at 2015-01-02

前回の投稿(http://sakaimo.hatenablog.com/entries/2014/12/29) では、JAVAで書かれていたコードをRubyでやってみました。この段階では「操作」の自動化だったので、今回はRSpecで「テスト」の自動化にチャレンジしてみました。

まだまだリファクタの余地はありそうなのですが、スキル不足によりひとまずここまで。。。

こゆソースコードはGitHubとかで公開したほうがいいのだろうけど、GitHubの使い方がわかんないので後回し><

  • 私の環境
    • macOS 10.10.1
    • ruby 2.0.0p481
    • rspec 3.1.7
    • FireFox 34.0.5

試すときはWordPressのアカウトを取って、spec_helper.rb の中身を変えてください。


ディレクトリ構造

ディレクトリ構造
E2ETest
  pages
    add_new_post_page.rb
    admin_login_page.rb
    all_posts_page.rb
    base_page.rb
    delete_post_page.rb
    edit_post_page.rb
  spec
    spec_helper.rb
    test_spec.rb

pagesの中身

add_new_post_page.rb
require File.expand_path(File.dirname(__FILE__) + '/base_page')

class AddNewPostPage < BasePage
  def initialize(driver)
    @driver = driver
    @url = "#{BASE_URL}/wp-admin/post-new.php"
  end

  # ページの機能
  # 記事の新規投稿をする
  def add_new_post(titlestr, description)
    @driver.switch_to.frame("content_ifr") #WYSIWYGではframeの切り替えが必要
    body.send_keys(description)

    @driver.switch_to.default_content
    title.send_keys(titlestr)

    publish_btn.click
  end

  # ページの要素
  private
  def body
    return @driver.find_element(:id, "tinymce")
  end

  def title
    return @driver.find_element(:id, "title")
  end

  def publish_btn
    return @driver.find_element(:id, "publish")
  end
end
admin_login_page.rb
require File.expand_path(File.dirname(__FILE__) + '/base_page')

class AdminLoginPage < BasePage
  def initialize(driver)
    super(driver)
    @url = "#{BASE_URL}/wp-admin/"
  end

  # ページの機能
  # 一気にログイン処理しちゃう
  def login
    email.clear
    email.send_keys(LOGIN_ID)
    pwd.clear
    pwd.send_keys(LOGIN_PW)
    login_button.click

    # ログイン後にはAllPostPageに遷移する
    return AllPostsPage.new(@driver)
  end

  # ページの要素
  private

  def email
    return @driver.find_element(:id, "user_login")
  end

  def pwd
    return @driver.find_element(:id, "user_pass")
  end

  def login_button
    return @driver.find_element(:id, "wp-submit")
  end
end
all_posts_page.rb
require File.expand_path(File.dirname(__FILE__) + '/base_page')

class AllPostsPage < BasePage
  def initialize(driver)
    super(driver)
    @url = "#{BASE_URL}/wp-admin/edit.php"
  end

  # ページの機能
  # 記事の作成
  def create_new_post(title, description)
    # 新規作成画面に遷移
    add_new_post.click

    # 作成画面のPageObjectを作成+投稿
    new_post = AddNewPostPage.new(@driver)
    new_post.add_new_post(title, description)
  end

  # 投稿の編集
  def edit_post(present_title, new_title, description)
    # 指定されたタイトルの詳細画面に行く
    go_to_paticular_post_page(present_title)
    edit_post_page = EditPostPage.new(@driver)
    edit_post_page.editPost(new_title, description)
  end

  # 投稿の削除
  def delete_post(title)
    # 指定されたタイトルの詳細画面に行く
    go_to_paticular_post_page(title)
    delete_post_page = DeletePostPage.new(@driver)
    delete_post_page.delete_post
  end

  # 一覧画面での投稿のフィルタリング
  def filter_posts_by_category(category)
    # 本にも載ってないので割愛。あとで書いてみるかもしれない。
  end

  # 投稿の検索
  def search_in_posts(search_text)
    # 本にも載ってないので割愛。あとで書いてみるかもしれない。
  end

  # 投稿数の取得
  def get_all_posts_count
    return posts_container.find_elements(:tag_name, "tr").size
  end

  # 指定した文字列のタイトルが存在するかを返す(もっとうまいやり方ありそう)
  def title_present?(title)
    all_posts = posts_container.find_elements(:class_name, "row-title")
    result = false

    all_posts.each do |ele|
      if ele.text == title
        result = true
        break result
      end
    end
    return result
  end

  # ページの要素
  private

  def add_new_post
    return @driver.find_element(:link_text, "新規追加")
  end

  # 各記事タイトルの要素(という言い方でいいのかな)をすべて取得
  def posts_container
    return @driver.find_element(:id, "the-list")
  end

  # 指定した投稿の編集ページに遷移するメソッド
  def go_to_paticular_post_page(title)
    all_posts = posts_container.find_elements(:class_name, "row-title")
    all_posts.each do |ele|
      if ele.text == title
        ele.click
        break
      end
    end
  end
end
base_page.rb
class BasePage

  def initialize(driver)
    @driver = driver
    @url    = ""
  end

  # ページを開く
  def open
    @driver.get(@url) unless @driver.current_url == @url
  end
end
delete_post_page.rb
require File.expand_path(File.dirname(__FILE__) + '/base_page')

class DeletePostPage < BasePage

  def initialize(driver)
    @driver = driver
  end

  def delete_post
    move_to_trush.click
  end

  private

  def move_to_trush
    return @driver.find_element(:link_text, "ゴミ箱へ移動")
  end
end
edit_post_page.rb
require File.expand_path(File.dirname(__FILE__) + '/base_page')

class EditPostPage < BasePage

  def initialize(driver)
    @driver = driver
  end

  def editPost(str_title, str_description)
    @driver.switch_to.frame(content_frame) #frameの切り替えが必要
    body.clear
    body.send_keys(str_description)

    @driver.switch_to.default_content
    title.clear
    title.send_keys(str_title)

    publish_btn.click
  end


  private

  # WYSIWYGのiframe
  def content_frame
    return @driver.find_element(:id, "content_ifr")
  end

  # 本文入力欄
  def body
    return @driver.find_element(:id, "tinymce")
  end

  # タイトル入力欄
  def title
    return @driver.find_element(:id, "title")
  end

  # 更新ボタン
  def publish_btn
    return @driver.find_element(:id, "publish")
  end
end

specの中身

spec_helper.rb
require 'selenium-webdriver'
require 'pry'

Dir[File.expand_path("../../pages/", __FILE__) << '/*.rb'].each do | file |
  require file
end

# 定数
BASE_URL = "https://xxx.wordpress.com"
LOGIN_ID = "イーメール"
LOGIN_PW = "パスワード"
test_spec.rb
describe "ログインして書いて編集して削除するシナリオ" do

  before :all do
    @driver = Selenium::WebDriver.for :firefox
  end

  after :all  do
    @driver.quit
  end

  it "正しいID/PWでログインできること" do
    login_page = AdminLoginPage.new(@driver)

    # ログインページを開く
    login_page.open

    # ログインする
    login_page.login

    # 今回はtitleに「ダッシュボード」という文字列が含まれているかで比較
    expect(@driver.title).to include "ダッシュボード"
  end

  it "記事の投稿ができること" do
    all_posts_page = AllPostsPage.new(@driver)
    all_posts_page.open

    # 記事の投稿
    all_posts_page.create_new_post("タイトル1", "本文1")

    # 記事一覧画面に行って、登録したタイトルが表示されているか、で判定(もっといい方法あるかも)
    all_posts_page.open
    result = all_posts_page.title_present?("タイトル1")
    expect(result).to be_truthy
  end

  it "記事の編集ができること" do
    # 記事の編集
    all_posts_page = AllPostsPage.new(@driver)
    all_posts_page.open

    # 記事の編集
    all_posts_page.edit_post("タイトル1", "タイトル2", "本文2")

    # 記事一覧画面に行って、編集したタイトルが表示されているか、で判定(もっといい方法がありそう)
    all_posts_page.open
    result = all_posts_page.title_present?("タイトル2")
    expect(result).to be_truthy
  end

  it "記事数の取得" do
    all_posts_page = AllPostsPage.new(@driver)
    all_posts_page.open
    result = all_posts_page.get_all_posts_count
    expect(result).to eq 1 # テスト開始時に投稿数がゼロとした
  end

  it "記事の削除ができること" do
    # 記事の削除
    all_posts_page = AllPostsPage.new(@driver)
    all_posts_page.open
    all_posts_page.delete_post("タイトル2")

    # タイトル2へのリンクが無いことをもって判断
    all_posts_page.open
    result = all_posts_page.title_present?("タイトル2")
    expect(result).to be_falsey
  end
end

実行する

E2Etestディレクトリにいる状態で実行
前提として、既存の投稿数はゼロにしておく

E2Etest sakaimo$ rspec -fd spec/test_spec.rb 

ログインして書いて編集して削除するシナリオ
  正しいID/PWでログインできること
  記事の投稿ができること
  記事の編集ができること
  記事数の取得
  記事の削除ができること

Finished in 49.57 seconds (files took 0.32554 seconds to load)
5 examples, 0 failures

  • 絶対もっと良い書き方があるはず。。。
8
10
0

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
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?