mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-29 04:06:11 +01:00
Merge branch 'master' of git://github.com/bsag/tracks
This commit is contained in:
commit
c58186451f
8 changed files with 332 additions and 39 deletions
25
spec/fixtures/contexts.yml
vendored
25
spec/fixtures/contexts.yml
vendored
|
|
@ -1,7 +1,22 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
|
||||
# one:
|
||||
# column: value
|
||||
#
|
||||
# two:
|
||||
# column: value
|
||||
agenda:
|
||||
id: 2
|
||||
name: agenda
|
||||
position: 2
|
||||
hide: false
|
||||
user: admin_user
|
||||
|
||||
call:
|
||||
id: 3
|
||||
name: call
|
||||
position: 3
|
||||
hide: true
|
||||
user: admin_user
|
||||
|
||||
email:
|
||||
id: 4
|
||||
name: email
|
||||
position: 4
|
||||
hide: false
|
||||
user: admin_user
|
||||
|
|
|
|||
34
spec/fixtures/preferences.yml
vendored
Normal file
34
spec/fixtures/preferences.yml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
admin_user_prefs:
|
||||
user: admin_user
|
||||
staleness_starts: 7
|
||||
date_format: "%d/%m/%Y"
|
||||
title_date_format: "%A, %d %B %Y"
|
||||
show_number_completed: 5
|
||||
show_completed_projects_in_sidebar: true
|
||||
show_hidden_contexts_in_sidebar: true
|
||||
show_hidden_projects_in_sidebar: true
|
||||
admin_email: butshesagirl@rousette.org.uk
|
||||
week_starts: 1
|
||||
due_style: 0
|
||||
refresh: 0
|
||||
time_zone: "London"
|
||||
verbose_action_descriptors: true
|
||||
show_project_on_todo_done: false
|
||||
|
||||
other_user_prefs:
|
||||
user: jane
|
||||
staleness_starts: 7
|
||||
date_format: "%d/%m/%Y"
|
||||
title_date_format: "%A, %d %B %Y"
|
||||
show_number_completed: 5
|
||||
show_completed_projects_in_sidebar: true
|
||||
show_hidden_contexts_in_sidebar: true
|
||||
show_hidden_projects_in_sidebar: true
|
||||
admin_email: butshesagirl@rousette.org.uk
|
||||
week_starts: 1
|
||||
due_style: 0
|
||||
refresh: 0
|
||||
time_zone: "London"
|
||||
verbose_action_descriptors: false
|
||||
show_project_on_todo_done: true
|
||||
57
spec/fixtures/todos.yml
vendored
Normal file
57
spec/fixtures/todos.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
<%
|
||||
|
||||
def today
|
||||
Time.zone.now.beginning_of_day.to_s(:db)
|
||||
end
|
||||
|
||||
def next_week
|
||||
1.week.from_now.beginning_of_day.to_s(:db)
|
||||
end
|
||||
|
||||
def last_week
|
||||
1.week.ago.beginning_of_day.to_s(:db)
|
||||
end
|
||||
|
||||
def two_weeks_ago
|
||||
2.weeks.ago.beginning_of_day.to_s(:db)
|
||||
end
|
||||
|
||||
def two_weeks_hence
|
||||
2.weeks.from_now.beginning_of_day.to_s(:db)
|
||||
end
|
||||
|
||||
%>
|
||||
|
||||
billgates:
|
||||
id: 2
|
||||
context_id: 2
|
||||
project_id: 2
|
||||
description: Call Bill Gates to find out how much he makes per day
|
||||
notes: ~
|
||||
state: active
|
||||
due: <%= two_weeks_hence %>
|
||||
completed_at: ~
|
||||
user: admin_user
|
||||
|
||||
dinoexterm:
|
||||
id: 3
|
||||
context_id: 2
|
||||
project_id: 3
|
||||
description: Call dinosaur exterminator
|
||||
notes: Ask him if I need to hire a skip for the corpses.
|
||||
state: active
|
||||
due: <%= two_weeks_hence %>
|
||||
completed_at: ~
|
||||
user: admin_user
|
||||
|
||||
buymilk:
|
||||
id: 4
|
||||
context_id: 2
|
||||
project_id: ~
|
||||
description: Buy milk
|
||||
notes: ~
|
||||
state: completed
|
||||
due: ~
|
||||
completed_at: <%= today %>
|
||||
user: admin_user
|
||||
27
spec/fixtures/users.yml
vendored
Normal file
27
spec/fixtures/users.yml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
admin_user:
|
||||
login: admin
|
||||
crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--abracadabra--") %>
|
||||
token: <%= Digest::SHA1.hexdigest("adminSat Feb 25 17:14:00 GMT 20060.236961325863376") %>
|
||||
is_admin: true
|
||||
first_name: Admin
|
||||
last_name: Schmadmin
|
||||
auth_type: database
|
||||
|
||||
other_user:
|
||||
login: jane
|
||||
crypted_password: <%= Digest::SHA1.hexdigest("#{Tracks::Config.salt}--sesame--") %>
|
||||
token: <%= Digest::SHA1.hexdigest("janeSun Feb 19 14:42:45 GMT 20060.408173979260027") %>
|
||||
is_admin: false
|
||||
first_name: Jane
|
||||
last_name: Doe
|
||||
auth_type: database
|
||||
|
||||
ldap_user:
|
||||
login: john
|
||||
crypted_password: test
|
||||
token: <%= Digest::SHA1.hexdigest("johnSun Feb 19 14:42:45 GMT 20060.408173979260027") %>
|
||||
is_admin: false
|
||||
first_name: John
|
||||
last_name: Deere
|
||||
auth_type: ldap
|
||||
|
|
@ -13,56 +13,139 @@ module ContextSpecHelper
|
|||
|
||||
end
|
||||
|
||||
describe Context do
|
||||
describe "Context validations" do
|
||||
include ContextSpecHelper
|
||||
|
||||
before(:each) do
|
||||
@context = Context.new
|
||||
end
|
||||
|
||||
it "should be valid" do
|
||||
@context.name = "FooBar"
|
||||
@context.should be_valid
|
||||
|
||||
before(:each) do
|
||||
@context = Context.new
|
||||
end
|
||||
|
||||
|
||||
it "should be valid" do
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.should be_valid
|
||||
@context.save
|
||||
Context.should have(4).records # 3 in fixtures 1 set up here
|
||||
end
|
||||
|
||||
it "should have two errors with a missing name" do
|
||||
@context.attributes = valid_context_attributes.except(:name)
|
||||
@context.should_not be_valid
|
||||
@context.should have(2).error_on(:name)
|
||||
@context.errors.on(:name)[0].should eql("context must have a name")
|
||||
@context.errors.on(:name)[1].should eql("context name must be less than 256 characters")
|
||||
end
|
||||
|
||||
it "should have one error with a name of more than 255 characters" do
|
||||
@context.name = "z" * 256
|
||||
@context.should_not be_valid
|
||||
@context.should have(1).error_on(:name)
|
||||
@context.errors.on(:name).should eql("context name must be less than 256 characters")
|
||||
end
|
||||
|
||||
|
||||
it "should have one error with name containing comma" do
|
||||
@context.name = "Foo,Bar"
|
||||
@context.should_not be_valid
|
||||
@context.should have(1).error_on(:name)
|
||||
@context.errors.on(:name).should eql("cannot contain the comma (',') character")
|
||||
end
|
||||
|
||||
it "should have one error if name already exists for user" do
|
||||
@existing_context = Context.new
|
||||
@existing_context.attributes = valid_context_attributes
|
||||
@existing_context.save
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.should_not be_valid
|
||||
@context.should have(1).error_on(:name)
|
||||
@context.errors.on(:name).should eql("already exists")
|
||||
end
|
||||
|
||||
it "should have one record in Context model class" do
|
||||
@context.name = "FooBar"
|
||||
@context.save
|
||||
Context.should have(1).record
|
||||
Context.should have(4).records # 3 in fixture, one set up here
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Context model" do
|
||||
fixtures :users, :todos, :contexts, :preferences
|
||||
|
||||
include ContextSpecHelper
|
||||
|
||||
it "should show hidden" do
|
||||
contexts(:call).should be_hide # :hide should be true
|
||||
end
|
||||
|
||||
it "should be hidden" do
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.should be_hide # :hide should be true
|
||||
it "should be produce correct .summary text for hidden context" do
|
||||
contexts(:call).summary(1).should eql("<p>1. Context is Hidden.</p>")
|
||||
end
|
||||
|
||||
it "should show not hidden" do
|
||||
contexts(:call).hide = false
|
||||
contexts(:call).should_not be_hide # :hide should be true
|
||||
end
|
||||
|
||||
it "should produce correct .summary text for active context" do
|
||||
contexts(:call).hide = false
|
||||
contexts(:call).summary(1).should eql("<p>1. Context is Active.</p>")
|
||||
end
|
||||
|
||||
it "should return .title which matches name" do
|
||||
contexts(:agenda).title.should eql(contexts(:agenda).name)
|
||||
end
|
||||
|
||||
it "should be produce correct summary text for hidden context" do
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.summary(1).should eql("<p>1. Context is Hidden.</p>")
|
||||
it "should .find_by_namepart with exact match" do
|
||||
@found = Context.find_by_namepart('agenda')
|
||||
@found.should_not eql(nil)
|
||||
@found.id.should eql(contexts(:agenda).id)
|
||||
end
|
||||
|
||||
it "should be active" do
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.hide = false
|
||||
@context.save
|
||||
@context.should_not be_hide # :hide should be true
|
||||
it "should .find_by_namepart with partial match" do
|
||||
@found = Context.find_by_namepart('ag')
|
||||
@found.should_not eql(nil)
|
||||
@found.id.should eql(contexts(:agenda).id)
|
||||
end
|
||||
|
||||
it "should produce correct summary text for active context" do
|
||||
@context.attributes = valid_context_attributes
|
||||
@context.hide = false
|
||||
@context.save
|
||||
@context.summary(1).should eql("<p>1. Context is Active.</p>")
|
||||
it "should return id with .to_param" do
|
||||
Context.find(2).to_param.should eql("2")
|
||||
end
|
||||
|
||||
end
|
||||
it "should return feed options" do
|
||||
opts = Context.feed_options(users(:admin_user))
|
||||
opts[:title].should eql("Tracks Contexts")
|
||||
opts[:description].should eql("Lists all the contexts for Admin Schmadmin")
|
||||
end
|
||||
|
||||
it "should create null Context with .null_object" do
|
||||
@empty = Context.null_object
|
||||
@empty.should be_an_instance_of(NullContext)
|
||||
@empty.id.should eql(nil)
|
||||
@empty.name.should eql('')
|
||||
end
|
||||
|
||||
it "should delete todos within context when context deleted" do
|
||||
contexts(:agenda).todos.count.should eql(3)
|
||||
agenda_todo_ids = contexts(:agenda).todos.collect{|t| t.id }
|
||||
contexts(:agenda).destroy
|
||||
agenda_todo_ids.each do |todo_id|
|
||||
Todo.find(:all).should_not include(todo_id)
|
||||
end
|
||||
end
|
||||
|
||||
it "should return correct number of done todos" do
|
||||
contexts(:agenda).done_todos.size.should eql(1)
|
||||
t = contexts(:agenda).not_done_todos[0]
|
||||
t.complete!
|
||||
t.save!
|
||||
Context.find(contexts(:agenda)).done_todos.size.should eql(2)
|
||||
end
|
||||
|
||||
it "should return correct number of not done todos" do
|
||||
contexts(:agenda).not_done_todos.size.should eql(2)
|
||||
t = contexts(:agenda).not_done_todos[0]
|
||||
t.complete!
|
||||
t.save!
|
||||
Context.find(contexts(:agenda)).not_done_todos.size.should eql(1)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
15
stories/context_detail/change_context_name.story
Normal file
15
stories/context_detail/change_context_name.story
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Story: Change context name
|
||||
|
||||
As a Tracks user
|
||||
I want to change the name of a context
|
||||
So that it can best reflect my daily life
|
||||
|
||||
Scenario: In place edit of context name
|
||||
Given a logged in user Luis
|
||||
And Luis has a context Errands
|
||||
When Luis visits the Errands context page
|
||||
And he edits the Errands context name in place to be OutAndAbout
|
||||
Then he should see the context name is OutAndAbout
|
||||
When Luis visits the context listing page
|
||||
Then he should see that a context named Errands is not present
|
||||
And he should see that a context named OutAndAbout is present
|
||||
34
stories/steps/context_detail.rb
Normal file
34
stories/steps/context_detail.rb
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
steps_for :context_detail do
|
||||
include_steps_for :users
|
||||
|
||||
Given "Luis has a context Errands" do
|
||||
@errands = @luis.contexts.create!(:name => 'Errands')
|
||||
end
|
||||
|
||||
When "Luis visits the Errands context page" do
|
||||
visits "/contexts/#{@errands.to_param}"
|
||||
end
|
||||
|
||||
When "he edits the Errands context name in place to be OutAndAbout" do
|
||||
selenium.click 'context_name_in_place_editor'
|
||||
wait_for_ajax_and_effects
|
||||
selenium.type "css=#context_name_in_place_editor-inplaceeditor input.editor_field", "OutAndAbout"
|
||||
clicks_button "ok", :wait => :ajax
|
||||
end
|
||||
|
||||
When "Luis visits the context listing page" do
|
||||
visits "/contexts"
|
||||
end
|
||||
|
||||
Then "he should see the context name is OutAndAbout" do
|
||||
should_see 'OutAndAbout'
|
||||
end
|
||||
|
||||
Then "he should see that a context named Errands is not present" do
|
||||
should_not_see 'Errands'
|
||||
end
|
||||
|
||||
Then "he should see that a context named OutAndAbout is present" do
|
||||
should_see 'OutAndAbout'
|
||||
end
|
||||
end
|
||||
|
|
@ -10,8 +10,13 @@ module Webrat
|
|||
@selenium.open(url)
|
||||
end
|
||||
|
||||
def fills_in(label_text, options)
|
||||
@selenium.type("webrat=#{label_text}", "#{options[:with]}")
|
||||
def fills_in(field_identifier, options)
|
||||
locator = if field_identifier == :current
|
||||
"css=:focus"
|
||||
else
|
||||
"webrat=#{Regexp.escape(field_identifier)}"
|
||||
end
|
||||
@selenium.type(locator, "#{options[:with]}")
|
||||
end
|
||||
|
||||
def response_body
|
||||
|
|
@ -25,11 +30,16 @@ module Webrat
|
|||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
def clicks_link(link_text, options = {})
|
||||
def clicks_link(link_text, options = {})
|
||||
@selenium.click("webratlink=#{link_text}")
|
||||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
def clicks_link_within(selector, link_text, options = {})
|
||||
@selenium.click("webratlinkwithin=#{selector}|#{link_text}")
|
||||
wait_for_result(options[:wait])
|
||||
end
|
||||
|
||||
def wait_for_result(wait_type)
|
||||
if wait_type == :ajax
|
||||
wait_for_ajax
|
||||
|
|
@ -55,8 +65,8 @@ module Webrat
|
|||
def wait_for_ajax_and_effects
|
||||
wait_for_ajax
|
||||
wait_for_effects
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def selects(option_text, options = {})
|
||||
id_or_name_or_label = options[:from]
|
||||
|
||||
|
|
@ -130,6 +140,24 @@ module Webrat
|
|||
return candidateLinks.first();
|
||||
JS
|
||||
|
||||
@selenium.add_location_strategy('webratlinkwithin', <<-JS)
|
||||
var locatorParts = locator.split('|');
|
||||
var cssAncestor = locatorParts[0];
|
||||
var linkText = locatorParts[1];
|
||||
var matchingElements = cssQuery(cssAncestor, inDocument);
|
||||
var candidateLinks = matchingElements.collect(function(ancestor){
|
||||
var links = ancestor.getElementsByTagName('a');
|
||||
return $A(links).select(function(candidateLink) {
|
||||
return PatternMatcher.matches(linkText, getText(candidateLink));
|
||||
});
|
||||
}).flatten().compact();
|
||||
if (candidateLinks.length == 0) {
|
||||
return null;
|
||||
}
|
||||
candidateLinks = candidateLinks.sortBy(function(s) { return s.length * -1; }); //reverse length sort
|
||||
return candidateLinks.first();
|
||||
JS
|
||||
|
||||
@selenium.add_location_strategy('webratselectwithoption', <<-JS)
|
||||
var optionElements = inDocument.getElementsByTagName('option');
|
||||
var locatedOption = $A(optionElements).find(function(candidate){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue