Автотесты Netzke в браузере

Создание начальной оболочки для тестирования формы входа. Написана с высоты двухнедельного изучения ruby и Netzke. Сдалано топорно.

По мотивам

Весь код примера доступен на GitHub

Создаем новый проект

$ rails new netzke-test-1
    create  
    create  README
    create  Rakefile
    create  config.ru
    create  .gitignore
    ...
$ cd netzke-test-1

Добавляем gems в файл Gemfile:

source 'http://rubygems.org'

gem 'rails', '3.0.3'

gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'netzke-core', :git => "git://github.com/skozlov/netzke-core.git"
gem 'netzke-basepack', :git => "git://github.com/skozlov/netzke-basepack.git"
gem 'will_paginate'

group :development, :test do
  gem "cucumber-rails"
  gem "rspec-rails"
end

group :test do
  gem "capybara"
  gem "launchy"
  gem "database_cleaner"
  gem "selenium-webdriver"
end

… и устанавливаем их:

$ bundle install
Updating git://github.com/skozlov/netzke-core.git
Updating git://github.com/skozlov/netzke-basepack.git
Fetching source index for http://rubygems.org/
Using rake (0.8.7) 
Using abstract (1.0.0) 
Using activesupport (3.0.3) 
Using builder (2.1.2) 
...

Делаем линки на скаченные библиотеки ExtJS и иконки:

$ ln -s ~/Library/mylibs/ext-3.3.1 public/extjs
$ ln -s ~/Library/mylibs/famfamfam_silk_icons_v013/icons public/images/

Добавляем в /app/views/layout/application.rb

<head>
  <title>NetzkeTest1</title>
  <%= netzke_init %>
  <%= csrf_meta_tag %>
</head>

Генерим оболочку:

$ rails g rspec:install
$ rails g cucumber:install --rspec --capybara

Делаем чтобы тесты выполнялись красиво:

$ echo '--colour --format documentation' > .rspec
$ sed -i~ 's/progress/pretty/g' config/cucumber.yml

Прописываем драйвер в тесты, для этого вписываем в features/support/env.rb следующие строки:

Capybara.register_driver :selenium do |app|
  Capybara::Driver::Selenium.new app, :browser => :chrome
end

Пишем фичу в файле features/login.feature

 1 Feature: Check login window
 2 In order to value
 3 As a role
 4 I want feature
 5 
 6 @javascript
 7 Scenario: Check window properties (and button Enter should be disabled by default)
 8   Given I am on the login page
 9   Then I should see "Login window"
10   And I should see "User"
11   And I should see "Password"
12   Then button "Enter" should be disabled
13   When I fill in "username" with "some"
14   And I fill in "password" with "somepass"
15   And I sleep 1 seconds
16   Then button "Enter" should be enabled
17 
18 @javascript
19 Scenario: Check login
20   Given I have a user named "user1" with password "pass1"
21   And I am on the login page
22   When I fill in "username" with "wrong_user"
23   And I fill in "password" with "wrong_password"
24   And I press "Enter"
25   When I wait for the response from the server
26   And I sleep 1 seconds
27   Then I should see "Wrong!"
28   When I fill in "username" with "user1"
29   And I fill in "password" with "pass1"
30   And I press "Enter"
31   When I wait for the response from the server
32   And I sleep 1 seconds
33   Then I should see "Hello, user1!"

Что мы делаем:
В первом сценарии мы проверяем окно, которое должно появится, два поля и отключенная кнопка “Enter”, которая должна включится только если в первом и во втором поле что-либо есть.
И второй сценарий – при верных параметрах мы попадаем на страницу приветствия пользователя, а при неверных – сообщение об ошибке.
PS: Тест написано криво и его надо причесать, но для примера пойдет.
PPS: Понаставил пауз потому как не знаю как же дожидаться выполнения работы JS.

Запускаем тест cucumber features и видим кучу ошибок. Самая первая из них:

Can't find mapping from "the login page" to a path.

Генерируем контроллер и добавляем action index

$ rails g controller login index
    create  app/controllers/login_controller.rb
    invoke  erb
    create    app/views/login
    ...

Добавляем default route к нашей странице в файле config/routes.rb

netzke
match "login" => "login#index"

Запускаем наш тест и видим, что он запнулся на том, что не видит окно.

Then I should see "Login window"

Это нормально, потому что мы его еще не написали.
Теперь рисуем наше окно для входа в файле app/views/login/index.html.erb

<%= netzke :login %>        

И сам компонент. Для этого создаем католог app/components и файл app/components/login.rb:

 1 # coding: utf-8
 2 class Login < Netzke::Base
 3 
 4   js_base_class 'Ext.Window'
 5 
 6   def configuration
 7     super.merge(
 8       :title => 'Login window',
 9       :hidden => false,
10       :width => 350, :autoHeight => true,
11       :closable => false, :resizable => false,
12       :items => [{
13         :buttons => [ :login.action ],
14         :xtype => :form,
15         :frame => true,
16         :defaultType => :textfield,
17         :monitorValid => true,
18         :defaults => { :anchor => '100%', :allowBlank => false },
19         :items => [{
20           :name => 'username',
21           :fieldLabel => 'User'
22         },{
23           :name => 'password',
24           :fieldLabel => 'Password',
25           :inputType => :password
26         }]
27       }]
28     )
29   end
30 
31   action :login, :text => 'Enter', :icon => :accept, :formBind => true
32   
33   js_method :on_login, <<-JS.l
34     function(){
35       var form = this.items.first().getForm();
36       if (form.isValid()){
37         this.login(form.getFieldValues());
38       }
39     }
40   JS
41 
42   endpoint :login do |para|
43     user = User.find(:first, :conditions => {
44       :login => para['username'],
45       :password => para['password']
46     })
47     session[:user_id] = user.id unless user.nil?
48     { :get_answer => !user.nil?  }
49   end
50 
51   js_method :get_answer, <<-JS.l
52     function (ret){
53       if (ret == false) {
54         Ext.Msg.alert('Wrong!','Wrong username or password');
55       }else{
56         window.location = '/users';
57       }
58     }
59   JS
60   end

Строки 6-29: Описание окна.
Строка 31: Добавление action типа “кнопка” и привязывание к форме
Строки 33-40: Отправка формы на сервер
Строки 42-50: Проверка пароля на строне сервера (так делать нельзя – это только пример)
Строки 52-60: Приемка ответа от сервера и решения что же дальше

Теперь cucumber ругается на непонятный ему шаг:

Undefined step: "button "Enter" should be disabled" (Cucumber::Undefined)

Отлично! Так давайте его и напишем в файле features/step_definitions/my_netzke_steps.rb:

Then /^button "([^"]*)" should be enabled$/ do |arg1|
  page.driver.browser.execute_script(<<-JS).should == true
    var btn = Ext.ComponentMgr.all.filter('text', '#{arg1}').filter('type','button').first();
  return typeof(btn)!='undefined' ? !btn.disabled : false
  JS
end

Then /^button "([^"]*)" should be disabled$/ do |arg1|
  page.driver.browser.execute_script(<<-JS).should == true
    var btn = Ext.ComponentMgr.all.filter('text', '#{arg1}').filter('type','button').first();
    return typeof(btn)!='undefined' ? btn.disabled : false
  JS
end

У нас готов первый полностью пройденный сценарий, на котором мы проверям окно входа и неактивную кнопку. Идем дальше.

Undefined step: "I have a user named "user1" with password "pass1""

Система не знает как сделать пользователя – так подскажем как это делается. Добавляем описание этого шага в features/step_definitions/my_netzke_steps.rb

Given /^I have a user named "([^"]*)" with password "([^"]*)"$/ do |arg1, arg2|
  User.create!( :login => arg1, :password => arg2 )
end

OMG! У нас нет модели! Cucumber говорит что uninitialized constant User (NameError). Создадим:

$ rails g model User login:string password:string
    invoke  active_record
    create    db/migrate/20110214075142_create_users.rb
    create    app/models/user.rb
    invoke    rspec
    create      spec/models/user_spec.rb
$ rake db:migrate
$ rake db:test:prepare
...

Осталось два последних шага, которых не понимает cucumber: When I wait for the response from the server и I sleep (\d+) seconds. Напишем их в features/step_definitions/my_netzke_steps.rb

When /^I wait for the response from the server$/ do
  page.wait_until{ page.driver.browser.execute_script("return !Ext.Ajax.isLoading();") }
end

When /I sleep (\d+) seconds?/ do |arg1|
  sleep arg1.to_i
end

И наконец-то cucumber наткнулся Then I should see “Hello, user1!” на нашу последнюю недописанную часть – то, что должно появится после входа в систему. Для этого создадим котроллер users, в котором приветствуем пользователя:

$ rails g controller users index

И default route config/routes.rb

match "users" => "users#index"

И напишем в app/views/users/index.html.erb:

Hello, <%= User.find(session[:user_id]).login %>!

Всё. Тесты пройдены – вход работет.

blog comments powered by Disqus

Sidebar