qcourses 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +23 -0
  3. data/Gemfile.lock +75 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +52 -0
  7. data/VERSION +1 -0
  8. data/config.ru +3 -0
  9. data/db/migrations/001_initial_database.rb +25 -0
  10. data/db/migrations/002_create_registrations.rb +29 -0
  11. data/demo_app.rb +11 -0
  12. data/lib/factories.rb +111 -0
  13. data/lib/qcourses/configuration.rb +35 -0
  14. data/lib/qcourses/controllers/base.rb +20 -0
  15. data/lib/qcourses/controllers/courses_controller.rb +16 -0
  16. data/lib/qcourses/controllers/events_controller.rb +54 -0
  17. data/lib/qcourses/controllers/registrations_controller.rb +51 -0
  18. data/lib/qcourses/controllers.rb +5 -0
  19. data/lib/qcourses/date_ex.rb +18 -0
  20. data/lib/qcourses/models/course.rb +30 -0
  21. data/lib/qcourses/models/course_repository.rb +90 -0
  22. data/lib/qcourses/models/event.rb +54 -0
  23. data/lib/qcourses/models/location.rb +17 -0
  24. data/lib/qcourses/models/registration.rb +36 -0
  25. data/lib/qcourses/models.rb +28 -0
  26. data/lib/qcourses/qcourses.rake.rb +21 -0
  27. data/lib/qcourses/renderers.rb +26 -0
  28. data/lib/qcourses/resource_paths.rb +45 -0
  29. data/lib/qcourses/string_ex.rb +5 -0
  30. data/lib/qcourses/view_helpers.rb +70 -0
  31. data/lib/qcourses/web_app.rb +29 -0
  32. data/lib/qcourses.rb +21 -0
  33. data/public/css/default.css +91 -0
  34. data/public/img/delete.gif +0 -0
  35. data/public/javascript/jquery-1.7.js +9300 -0
  36. data/public/javascript/jquery-1.7.min.js +4 -0
  37. data/public/javascript/qcourses.js +20 -0
  38. data/spec/factories_spec.rb +131 -0
  39. data/spec/qcourses/configuration_spec.rb +37 -0
  40. data/spec/qcourses/controllers/courses_controller_spec.rb +43 -0
  41. data/spec/qcourses/controllers/events_controller_spec.rb +100 -0
  42. data/spec/qcourses/controllers/registrations_controller_spec.rb +100 -0
  43. data/spec/qcourses/models/course_repository_spec.rb +147 -0
  44. data/spec/qcourses/models/event_spec.rb +74 -0
  45. data/spec/qcourses/models/location_spec.rb +19 -0
  46. data/spec/qcourses/models/registration_spec.rb +55 -0
  47. data/spec/qcourses/renderers_spec.rb +82 -0
  48. data/spec/qcourses/string_ex_spec.rb +11 -0
  49. data/spec/qcourses/view_helpers_spec.rb +90 -0
  50. data/spec/spec_helper.rb +38 -0
  51. data/spec/support/factories.rb +24 -0
  52. data/spec/support/matchers.rb +61 -0
  53. data/spec/support/request_specs.rb +4 -0
  54. data/spec/support/test_files.rb +20 -0
  55. data/views/admin.haml +9 -0
  56. data/views/events/index.haml +18 -0
  57. data/views/events/new.haml +34 -0
  58. data/views/layout.haml +9 -0
  59. data/views/registration.haml +9 -0
  60. data/views/registrations/new.haml +37 -0
  61. data/views/registrations/participant.haml +12 -0
  62. data/views/registrations/success.haml +4 -0
  63. data/views/trainings/error.haml +1 -0
  64. data/views/trainings/index.haml +9 -0
  65. metadata +306 -0
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require 'capybara/rspec'
3
+
4
+ module Qcourses
5
+
6
+ describe RegistrationsController, :type => :request do
7
+ let(:app) { Capybara.app = RegistrationsController }
8
+ let(:event) { Rubory.create :event }
9
+
10
+ describe 'get new' do
11
+ def url(id)
12
+ "/registrations/new/#{id}"
13
+ end
14
+
15
+ it "should render a form" do
16
+ get url(event.id)
17
+ last_response.should be_ok
18
+ last_body.should have_selector("form#registrations[@method='post'][@action='/registrations/#{event.id}']")
19
+ end
20
+
21
+ it "should return a 404 when event is not available" do
22
+ get url(event.id + 33334)
23
+ last_response.should be_not_found
24
+ end
25
+
26
+ it "should return a 404 when event is in the past" do
27
+ event.update :from => Date.today
28
+ get url(event.id)
29
+ last_response.should be_not_found
30
+ end
31
+
32
+ end
33
+
34
+ describe 'post registration' do
35
+ def url(id)
36
+ "/registrations/#{id}"
37
+ end
38
+
39
+ let(:participants) { [valid_participant] }
40
+ let!(:valid_company) { Rubory.attributes_for :company }
41
+ let!(:valid_participant) { Rubory.attributes_for :employee }
42
+ let(:valid_registration) { { employee: participants, company: valid_company} }
43
+
44
+ context "on valid attributes" do
45
+ it "redirects to thank you" do
46
+ post url(event.id), valid_registration
47
+ last_response.should be_redirect
48
+ follow_redirect!
49
+ last_body.should have_selector(".thanks")
50
+ end
51
+ it "creates a registration" do
52
+ expect { post url(event.id), valid_registration }.to change { Registration.count }.by(1)
53
+ end
54
+ it "creates a company" do
55
+ expect { post url(event.id), valid_registration }.to change { Company.count }.by(1)
56
+ end
57
+ it "creates an employee" do
58
+ expect { post url(event.id), valid_registration }.to change { Employee.count }.by(1)
59
+ end
60
+ context "with more employees" do
61
+ let!(:another_participant) { Rubory.attributes_for :employee }
62
+ let(:participants) { [valid_participant, another_participant] }
63
+ it "creates more registrations" do
64
+ expect { post url(event.id), valid_registration }.to change { Registration.count }.by(2)
65
+ end
66
+ it "creates a company" do
67
+ expect { post url(event.id), valid_registration }.to change { Company.count }.by(1)
68
+ end
69
+ it "creates more employees" do
70
+ expect { post url(event.id), valid_registration }.to change { Employee.count }.by(2)
71
+ end
72
+ end
73
+ end
74
+ context "problems with event" do
75
+ it "should return a 404 when event is not available" do
76
+ post url(event.id + 33334)
77
+ last_response.should be_not_found
78
+ end
79
+
80
+ it "should return a 404 when event is in the past" do
81
+ event.update :from => Date.today
82
+ post url(event.id)
83
+ last_response.should be_not_found
84
+ end
85
+ end
86
+ context "problems with attributes" do
87
+ context "participant invalid" do
88
+ it "shows error on attribute" do
89
+ valid_participant[:email] = ''
90
+ post url(event.id), valid_registration
91
+ last_response.should be_ok
92
+ last_body.should have_selector("form input.error[name='employee[][email]']")
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+
@@ -0,0 +1,147 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ class StubCourseFileOpener
5
+ def initialize(files = {})
6
+ @files=files
7
+ @files.default = ''
8
+ end
9
+ def define_file(filename, content)
10
+ @files[filename] = content
11
+ end
12
+ def open(name, &block)
13
+ StringIO.open(@files[name], &block)
14
+ end
15
+ end
16
+
17
+ class StubDirectory
18
+
19
+ def initialize
20
+ @results = {}
21
+ @results.default = []
22
+ end
23
+
24
+ def glob(pattern)
25
+ @results[pattern]
26
+ end
27
+
28
+ def pattern(pattern, options = {returns: []})
29
+ @results[pattern] = options[:returns]
30
+ end
31
+ end
32
+
33
+ describe 'CourseRepository' do
34
+ let(:directory) { StubDirectory.new }
35
+ let(:file_opener) { StubCourseFileOpener.new('first_course.mdown' => "Name: first course",
36
+ 'second_course.mdown' => "Name: second course") }
37
+ let(:repository) { CourseRepository.new(directory, file_opener) }
38
+ let(:first_course) { repository.all.first }
39
+
40
+ describe 'class methods' do
41
+ it "can't be used when not configured yet" do
42
+ expect { CourseRepository.all }.to raise_exception CourseRepository::Error
43
+ end
44
+ end
45
+
46
+ describe 'all' do
47
+ context "detecting course files" do
48
+ it "returns a course for all the **/courses/*.mdown files" do
49
+ directory.pattern("**/courses/*.mdown", returns: ['first_course.mdown', 'second_course.mdown'])
50
+
51
+ repository.all.should == [ Course.new(identification: 'first_course', name: 'first course'),
52
+ Course.new(identification: 'second_course', name: 'second_course') ]
53
+ end
54
+
55
+ it "returns a course for all the **/cursussen/*.mdown files " do
56
+ directory.pattern("**/cursussen/*.mdown", returns: ['first_course.mdown', 'second_course.mdown'])
57
+
58
+ repository.all.should == [ Course.new(identification: 'first_course', name: 'first course'),
59
+ Course.new(identification: 'second_course', name: 'second_course') ]
60
+ end
61
+ it "ignores duplication in courses" do
62
+ directory.pattern("**/courses/*.mdown", returns: ['first_course.mdown'])
63
+ directory.pattern("**/cursussen/*.mdown", returns: ['first_course.mdown'])
64
+
65
+ repository.all.should == [ Course.new(identification: 'first_course', name: 'first course')]
66
+ end
67
+
68
+ it "uses just the actual filenames as the course name - not the complete path" do
69
+ directory.pattern("**/cursussen/*.mdown", returns: ['en/courses/first_course.mdown'])
70
+ file_opener.define_file('en/courses/first_course.mdown', "Name: first course")
71
+
72
+ first_course.should == Course.new(identification: 'first_course', name: 'first course')
73
+ end
74
+
75
+ it "skips index files" do
76
+ directory.pattern("**/cursussen/*.mdown", returns: ['en/courses/index.mdown'])
77
+ file_opener.define_file('en/courses/index.mdown', "Name: first course")
78
+
79
+ repository.all.should == []
80
+ end
81
+ end
82
+
83
+ context "parsing the course" do
84
+ before do
85
+ directory.pattern("**/cursussen/*.mdown", returns: ['first_course.mdown'])
86
+ end
87
+ def course_file_contains(content)
88
+ file_opener.define_file('first_course.mdown', content)
89
+ end
90
+ it "accepts more headers after name" do
91
+ course_file_contains(%Q{Name: first course
92
+ Category: training})
93
+ first_course.name.should == 'first course'
94
+ end
95
+ it "accepts more headers before name" do
96
+ course_file_contains(%Q{Category: training
97
+ Name: first course })
98
+ first_course.name.should == 'first course'
99
+ end
100
+ it "ignores headers after first empty line" do
101
+ course_file_contains(%Q{Category: training
102
+
103
+ Name: first course })
104
+ first_course.name.should == 'first_course'
105
+ end
106
+ it "ignores lines after first line that does not contain colon" do
107
+ course_file_contains(%Q{Category training
108
+ Name: first course })
109
+ first_course.name.should == 'first_course'
110
+ end
111
+ context "name" do
112
+ it "uses identification as the name if the name is not defined" do
113
+ course_file_contains('')
114
+ first_course.name.should == 'first_course'
115
+ end
116
+ it "reads the name from the Name header" do
117
+ course_file_contains('Name: first course')
118
+ first_course.name.should == 'first course'
119
+ end
120
+ it "accepts colon in name" do
121
+ course_file_contains('Name: first: course')
122
+ first_course.name.should == 'first: course'
123
+ end
124
+ end
125
+ context "subtitle" do
126
+ it "is empty if the subtitle is not defined" do
127
+ course_file_contains('')
128
+ first_course.subtitle.should == ''
129
+ end
130
+ it "reads the subtitle from the Subtitle header" do
131
+ course_file_contains('Subtitle: learn stuff!')
132
+ first_course.subtitle.should == 'learn stuff!'
133
+ end
134
+ end
135
+ end
136
+ end
137
+ describe "find(course_identification)" do
138
+ it "returns the associated course" do
139
+ repository.find('first_course').should == first_course
140
+ end
141
+ it "returns nil if course does not exist" do
142
+ repository.find('non-existing').should be_nil
143
+ end
144
+ end
145
+ end
146
+
147
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ describe Event do
5
+
6
+
7
+ describe "storing events" do
8
+ subject { Event.new valid_attributes }
9
+ context "location as a string" do
10
+ let(:valid_attributes) { { course_id: 'agile_engineering', from: "10-04-2012", to: "13-04-2012", location: "Tilburg"} }
11
+
12
+ it "can be stored and loaded" do
13
+ subject.save
14
+ reloaded = Event[subject.id]
15
+ reloaded.should == subject
16
+ end
17
+
18
+ it "should fail on empty location" do
19
+ subject.should reject_values("").for(:location)
20
+ end
21
+ it { should accept_values("2012-04-01", "10-10-2012").for(:from) }
22
+ it { should accept_values("2012-04-01", "10-10-2012").for(:to) }
23
+ end
24
+ end
25
+
26
+ describe "attributes" do
27
+
28
+ let(:subject) {Event.new(course_id: 'ae', from: "10-04-2012", to: "12-04-2012") }
29
+ its(:from) { should be_a(Time) }
30
+ its(:from) { should == Time.parse("10-04-2012") }
31
+ its(:to) { should be_a(Time) }
32
+
33
+
34
+ describe "from course" do
35
+ let(:course_repository) { CourseRepository.in_memory }
36
+ let!(:course) { course_repository.create_course :identification => 'ae', :name => "AE", :subtitle => 'learn ae' }
37
+ its(:name) { should == course.name }
38
+ its(:subtitle) { should == course.subtitle }
39
+
40
+ context 'when course not available' do
41
+ before { subject.course_id = 'removed_id' }
42
+ its(:name) { should == 'removed course (removed_id)' }
43
+ its(:subtitle) { should == '' }
44
+ end
45
+ end
46
+
47
+ describe 'location' do
48
+ it "is converted to a location object" do
49
+ subject.location = "Tilburg"
50
+ subject.location.should be_a(Location)
51
+ subject.location.name.should == 'Tilburg'
52
+ end
53
+
54
+ it "_name attribute delegates to location or is unknown" do
55
+ subject.location_name.should == 'unknown'
56
+ subject.location = "Tilburg"
57
+ subject.location_name.should == subject.location.name
58
+ end
59
+
60
+ context "with same name exists" do
61
+ let!(:existing_location) { Location.create(name: "Tilburg") }
62
+ it "existing location is used when available" do
63
+ subject.location = "Tilburg"
64
+ subject.location.should == existing_location
65
+ end
66
+ it "existing location is located case insensitive" do
67
+ subject.location = "tilburG"
68
+ subject.location.should == existing_location
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ describe Location do
5
+ describe 'storing locations' do
6
+ subject { Location.new valid_attributes }
7
+ let(:valid_attributes) {{name: 'Qwan Tilburg', address: "Gondelstraat", postal_code: "2323 AA", city: "Tilburg", url:"/contact" }}
8
+
9
+ it "should be able to save an read back" do
10
+ subject.save
11
+ read_back = Location[subject.id]
12
+ read_back.should == subject
13
+ end
14
+
15
+ it {should reject_values(nil, "").for(:name)}
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ describe Registration do
5
+ describe "saving" do
6
+ let(:employee) { Rubory.create :employee }
7
+ let(:event) { Rubory.create :event }
8
+ let(:subject) {Registration.new(employee: employee, event: event)}
9
+
10
+ it "can be saved and read back" do
11
+ subject.save
12
+ reloaded = Registration[subject.id]
13
+ reloaded.should == subject
14
+ end
15
+
16
+ it { should reject_values(nil).for(:employee) }
17
+ it { should reject_values(nil).for(:event) }
18
+ end
19
+ end
20
+
21
+ describe Employee do
22
+ describe "saving" do
23
+ let(:subject) { Rubory.build :employee }
24
+ it "can be saved and read back" do
25
+ subject.save
26
+ reloaded = Employee[subject.id]
27
+ reloaded.should == subject
28
+ end
29
+
30
+ it { should reject_values(nil, "").for(:name) }
31
+ it { should reject_values(
32
+ nil, "",
33
+ "rob@", "@mo.nl", "123.nl", "123@nl", "aaa.123.nl", "aaa.123@nl").for(:email) }
34
+ end
35
+ end
36
+
37
+ describe Company do
38
+ describe "saving" do
39
+ let(:subject) { Rubory.build :company }
40
+ it "can be saved and read back" do
41
+ subject.save
42
+ reloaded = Company[subject.id]
43
+ reloaded.should == subject
44
+ end
45
+
46
+ it { should reject_values(nil, "").for(:name) }
47
+ it { should reject_values(nil, "").for(:contact_person) }
48
+ it { should reject_values(nil, "").for(:invoice_address) }
49
+ it { should reject_values(nil, "").for(:postal_code) }
50
+ it { should reject_values(nil, "").for(:city) }
51
+ it { should reject_values( nil, "", "rob@", "@mo.nl", "123.nl", "123@nl", "aaa.123.nl", "aaa.123@nl")
52
+ .for(:contact_email) }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ describe Renderers do
5
+ require 'sinatra'
6
+ let(:template_cache) { Tilt::Cache.new }
7
+ include Sinatra::Templates
8
+ include Renderers
9
+ let(:local_root) { spec_path 'files/local' }
10
+ let(:root) { spec_path "files/remote" }
11
+ let(:views) { 'views' }
12
+
13
+ after do
14
+ delete_files('files')
15
+ end
16
+
17
+ def html_for(result)
18
+ Capybara.string(result)
19
+ end
20
+
21
+ describe 'haml' do
22
+ it "uses the local path if it exists" do
23
+ create_file('files/local/views/view.haml', '%h1 local view')
24
+ html_for(haml(:'view')).should have_selector('h1', :text => 'local view')
25
+ end
26
+ it "uses the remote path if it exists" do
27
+ create_file('files/remote/views/view.haml', '%h1 remote view')
28
+ html_for(haml(:'view')).should have_selector('h1', :text => 'remote view')
29
+ end
30
+ it "remote path overrides local if it exists" do
31
+ create_file('files/local/views/view.haml', '%h1 local view')
32
+ create_file('files/remote/views/view.haml', '%h1 remote view')
33
+ html_for(haml(:'view')).should have_selector('h1', :text => 'remote view')
34
+ end
35
+ it "uses the string if haml is a string" do
36
+ html_for(haml('%h1 inline view')).should have_selector('h1', :text => 'inline view')
37
+ end
38
+
39
+ context "with layout available locally" do
40
+ before do
41
+ create_file('files/local/views/view.haml', '%h1 local view')
42
+ create_file('files/local/views/layout.haml', "%h1 local layout \n=yield")
43
+ end
44
+ it "renders no layout when layout specified to be false" do
45
+ html_for(haml(:'view', layout: false )).should_not have_selector( 'h1', :text => 'local layout')
46
+ end
47
+ it "renders layout when layout specified to be true" do
48
+ html_for(haml(:'view', layout: true)).should have_selector( 'h1', :text => 'local layout')
49
+ end
50
+ it "renders layout when layout specified by name" do
51
+ html_for(haml(:'view', layout: :layout)).should have_selector( 'h1', :text => 'local layout')
52
+ end
53
+ it "complains about layout not to exist when layout is not available" do
54
+ expect { haml(:'view', layout: :admini) }.to raise_exception(Errno::ENOENT)
55
+ end
56
+ end
57
+
58
+ context "with layout available remotely" do
59
+ before do
60
+ create_file('files/local/views/view.haml', '%h1 local view')
61
+ create_file('files/remote/views/layout.haml', "%h1 remote layout \n=yield")
62
+ end
63
+ it "renders no layout when layout specified to be false" do
64
+ html_for(haml(:'view', layout: false )).should_not have_selector( 'h1', :text => 'remote layout')
65
+ end
66
+ it "renders layout when layout specified to be true" do
67
+ html_for(haml(:'view', layout: true )).should have_selector( 'h1', :text => 'remote layout')
68
+ end
69
+ it "renders layout when layout specified by name" do
70
+ html_for(haml(:'view', layout: :layout)).should have_selector( 'h1', :text => 'remote layout')
71
+ end
72
+ it "complains about layout not to exist when layout is not available" do
73
+ expect { haml(:'view', layout: :admin) }.to raise_exception(Errno::ENOENT)
74
+ end
75
+ it "falls back to local layout when remote does not exist" do
76
+ create_file('files/local/views/admin.haml', "%h1 local admin layout \n=yield")
77
+ html_for(haml(:'view', layout: :admin)).should have_selector( 'h1', :text => 'local admin layout')
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe String do
4
+ describe "underscore" do
5
+ it "underscores a camel cased string" do
6
+ "Event".underscore.should == "event"
7
+ "EventName".underscore.should == "event_name"
8
+ "EEEventName".underscore.should == "ee_event_name"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ module Qcourses
4
+ describe ViewHelpers do
5
+ require 'sinatra'
6
+ let(:template_cache) { Tilt::Cache.new }
7
+ include Sinatra::Templates
8
+ include ViewHelpers
9
+
10
+ describe 'human_period' do
11
+ let(:event) { Event.new(from: "30-11-2012", to: "02-12-2013") }
12
+ let(:subject) { human_period(event.from, event.to) }
13
+
14
+ it "formats both dates short with a hyphen inbetween" do
15
+ subject.should == "30/11/2012 - 2/12/2013"
16
+ end
17
+
18
+ context "when dates are in same year" do
19
+ before { event.to = "02-12-2012" }
20
+ it "formats both dates with a hyphen when dates are in different months" do
21
+ subject.should == '30/11 - 2/12 2012'
22
+ end
23
+
24
+ context "when dates are in same month" do
25
+ it "formats both dates with a hyphen" do
26
+ event.from = "1-12-2012"
27
+ subject.should == '1 - 2 December 2012'
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "input_for" do
34
+ def html_for(result)
35
+ Capybara.string(result)
36
+ end
37
+ before do
38
+ @employee = Employee.new :name => 'gijs'
39
+ @employee.valid?
40
+ end
41
+ describe "on an existing object" do
42
+ it 'creates an input tag' do
43
+ html_for(input_for(:employee, :name)).should have_selector("input[type='text'][name='employee[name]'][value='gijs']")
44
+ html_for(input_for(@employee, :name)).should have_selector("input[type='text'][name='employee[name]'][value='gijs']")
45
+ end
46
+ it 'creates an an error class if attribute has error' do
47
+ result = html_for(input_for(:employee, :email))
48
+ result.should have_selector("input[type='text'][name='employee[email]'][class='error']")
49
+ result.should have_selector("span[class='error']", :text => @employee.errors.on(:email).first)
50
+ end
51
+ it 'can suppress error messagee if attribute has error' do
52
+ result = html_for(input_for(:employee, :email, :suppress_error_messages => true))
53
+ result.should have_selector("input[type='text'][name='employee[email]'][class='error']")
54
+ result.should_not have_selector("span[class='error']", :text => @employee.errors.on(:email).first)
55
+ end
56
+ it 'can have a class' do
57
+ html_for(input_for(:employee, :name, :class => 'short')).should have_selector("input[name='employee[name]'][class='short']")
58
+ html_for(input_for(:employee, :email, :class => 'short')).should have_selector("input[name='employee[email]'][class='error short']")
59
+ end
60
+ end
61
+ describe "on an array object" do
62
+ it "creates an input tag with an extra [] inthe name" do
63
+ html_for(input_for(:employee, :name, :array_element=>true)).should have_selector("input[type='text'][name='employee[][name]'][value='gijs']")
64
+ end
65
+ end
66
+ end
67
+ describe "text_field_for" do
68
+ def html_for(result)
69
+ Capybara.string(result)
70
+ end
71
+ before do
72
+ @company = Company.new
73
+ end
74
+ describe "on an existing object" do
75
+ it 'creates a textarea tag' do
76
+ html_for(textarea_for(:company, :invoice_address)).should have_selector("textarea[name='company[invoice_address]']")
77
+ html_for(textarea_for(@company, :invoice_address)).should have_selector("textarea[name='company[invoice_address]']")
78
+ end
79
+ it "contains the value" do
80
+ @company.invoice_address = "Gondelstraat\nTilburg"
81
+ html_for(textarea_for(:company, :invoice_address)).should have_selector("textarea[name='company[invoice_address]']", :text=>@company.invoice_address)
82
+ end
83
+ it 'creates an an error class if attribute has error' do
84
+ @company.errors.add(:invoice_address, "wrong address")
85
+ html_for(textarea_for(:company, :invoice_address)).should have_selector("textarea[name='company[invoice_address]'][class='error']")
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,38 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ ENV['RACK_ENV'] = 'test'
6
+
7
+ require 'rspec'
8
+ require 'qcourses'
9
+ require 'rack/test'
10
+ require 'capybara'
11
+
12
+ Qcourses.configure do |config|
13
+ config.root = File.expand_path('..',File.dirname(__FILE__))
14
+ end
15
+
16
+ # Requires supporting files with custom matchers and macros, etc,
17
+ # in ./support/ and its subdirectories.
18
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
19
+
20
+ class RSpec::Core::ExampleGroup
21
+ # Setting an around filter globally doesn't appear to work in 2.7 (and maybe other versions),
22
+ # so set one up for each subclass.
23
+ def self.inherited(subclass)
24
+ super
25
+ subclass.around do |example|
26
+ Qcourses::CourseRepository.destroy
27
+ Sequel::Model.db.transaction(:rollback=>:always){example.call}
28
+ end
29
+ end
30
+ end
31
+
32
+ RSpec.configure do |config|
33
+ config.include Rack::Test::Methods
34
+ config.include TestFiles
35
+ config.filter_run_excluding :broken => true
36
+ config.filter_run :focus => true
37
+ config.run_all_when_everything_filtered = true
38
+ end
@@ -0,0 +1,24 @@
1
+ require 'factories'
2
+ require 'qcourses/date_ex'
3
+ Rubory.use_default_module('Qcourses')
4
+
5
+ Rubory.define(:company) do
6
+ name { |n| "company_#{n}" }
7
+ contact_person "some contact"
8
+ contact_email { |n| "contact_#{n}@email.com" }
9
+ invoice_address "some address"
10
+ postal_code "1234 AA"
11
+ city "Amsterdam"
12
+ end
13
+
14
+ Rubory.define(:employee) do
15
+ name "some employee"
16
+ email { |n| "email_#{n}@qwan.it" }
17
+ associate :company
18
+ end
19
+
20
+ Rubory.define(:event) do
21
+ from { Date.tomorrow }
22
+ to { Date.tomorrow.tomorrow }
23
+ location "Tilburg"
24
+ end