date_book 0.0.1
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.
- checksums.yaml +7 -0
- data/.idea/vcs.xml +6 -0
- data/.rspec +2 -0
- data/.rubocop.yml +23 -0
- data/.rubocop_todo.yml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +94 -0
- data/Gemfile.lock +385 -0
- data/LICENSE.txt +20 -0
- data/README.md +64 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/app/assets/images/date_book/.keep +0 -0
- data/app/assets/javascripts/date_book.js +21 -0
- data/app/assets/javascripts/date_book/calendar_events.js +57 -0
- data/app/assets/javascripts/date_book/event_form.js +31 -0
- data/app/assets/javascripts/date_book/popovers.js +3 -0
- data/app/assets/javascripts/date_book/wysiwyg.js +8 -0
- data/app/assets/stylesheets/date_book.css.scss +46 -0
- data/app/controllers/date_book/calendars_controller.rb +60 -0
- data/app/controllers/date_book/date_book_controller.rb +24 -0
- data/app/controllers/date_book/events_controller.rb +105 -0
- data/app/controllers/date_book/graphql_controller.rb +35 -0
- data/app/graphql/date_book_schema.rb +18 -0
- data/app/graphql/types/calendar_type.rb +14 -0
- data/app/graphql/types/date_time_type.rb +7 -0
- data/app/graphql/types/event_occurrence_type.rb +11 -0
- data/app/graphql/types/event_type.rb +19 -0
- data/app/graphql/types/mutation_type.rb +5 -0
- data/app/graphql/types/profile_type.rb +7 -0
- data/app/graphql/types/query_type.rb +57 -0
- data/app/helpers/date_book/application_helper.rb +35 -0
- data/app/helpers/date_book/calendar_helper.rb +4 -0
- data/app/helpers/date_book/events_helper.rb +42 -0
- data/app/jobs/date_book/application_job.rb +6 -0
- data/app/mailers/date_book/application_mailer.rb +9 -0
- data/app/views/date_book/application/_all_day_checkbox.html.haml +1 -0
- data/app/views/date_book/application/_date_range.html.haml +8 -0
- data/app/views/date_book/application/_wysiwyg.html.haml +65 -0
- data/app/views/date_book/calendars/_form.html.haml +6 -0
- data/app/views/date_book/calendars/edit.html.haml +5 -0
- data/app/views/date_book/calendars/index.html.haml +28 -0
- data/app/views/date_book/calendars/new.html.haml +5 -0
- data/app/views/date_book/calendars/show.html.haml +28 -0
- data/app/views/date_book/events/_event.json.jbuilder +12 -0
- data/app/views/date_book/events/_form.html.haml +16 -0
- data/app/views/date_book/events/_occurrence_dates.html.haml +11 -0
- data/app/views/date_book/events/edit.html.haml +5 -0
- data/app/views/date_book/events/fields/_date.html.haml +1 -0
- data/app/views/date_book/events/fields/_day.html.haml +1 -0
- data/app/views/date_book/events/fields/_day_of_week.html.haml +19 -0
- data/app/views/date_book/events/fields/_duration.html.haml +6 -0
- data/app/views/date_book/events/fields/_interval.html.haml +1 -0
- data/app/views/date_book/events/fields/_time.html.haml +1 -0
- data/app/views/date_book/events/index.html.haml +16 -0
- data/app/views/date_book/events/new.html.haml +5 -0
- data/app/views/date_book/events/popover.html.haml +7 -0
- data/app/views/date_book/events/rules/_daily.html.haml +4 -0
- data/app/views/date_book/events/rules/_monthly.html.haml +5 -0
- data/app/views/date_book/events/rules/_singular.html.haml +4 -0
- data/app/views/date_book/events/rules/_weekly.html.haml +5 -0
- data/app/views/date_book/events/show.html.haml +16 -0
- data/app/views/layouts/_date_book_scripts.html.haml +4 -0
- data/app/views/layouts/blank.html.haml +1 -0
- data/bin/rails +15 -0
- data/config/locales/en.yml +44 -0
- data/config/routes.rb +12 -0
- data/date_book.gemspec +337 -0
- data/db/migrate/20170807133845_create_calendars.rb +11 -0
- data/db/migrate/20170807133846_create_events.rb +20 -0
- data/db/migrate/20170807133847_create_schedules.rb +25 -0
- data/db/migrate/20170807133848_add_fields_to_schedule.rb +6 -0
- data/db/migrate/20170807133849_create_event_occurrences.rb +16 -0
- data/db/migrate/20170807133850_add_fields_to_event_occurrences.rb +5 -0
- data/lib/date_book.rb +40 -0
- data/lib/date_book/concerns/ability.rb +27 -0
- data/lib/date_book/concerns/acts_as_calendar.rb +29 -0
- data/lib/date_book/concerns/acts_as_event.rb +66 -0
- data/lib/date_book/concerns/acts_as_event_occurrence.rb +67 -0
- data/lib/date_book/concerns/acts_as_ownable.rb +29 -0
- data/lib/date_book/concerns/acts_as_owner.rb +18 -0
- data/lib/date_book/concerns/acts_as_schedule.rb +44 -0
- data/lib/date_book/configuration.rb +43 -0
- data/lib/date_book/engine.rb +40 -0
- data/lib/date_book/localization.rb +32 -0
- data/lib/date_book/version.rb +8 -0
- data/lib/generators/date_book/install/install_generator.rb +110 -0
- data/lib/generators/date_book/install/templates/app/models/ability.rb +16 -0
- data/lib/generators/date_book/install/templates/app/models/calendar.rb +3 -0
- data/lib/generators/date_book/install/templates/app/models/event.rb +3 -0
- data/lib/generators/date_book/install/templates/app/models/event_occurrence.rb +3 -0
- data/lib/generators/date_book/install/templates/app/models/schedule.rb +3 -0
- data/lib/generators/date_book/install/templates/config/initializers/date_book.rb +5 -0
- data/lib/generators/date_book/utils.rb +25 -0
- data/lib/tasks/date_book_tasks.rake +5 -0
- data/spec/abilities/calendar_spec.rb +39 -0
- data/spec/abilities/event_spec.rb +44 -0
- data/spec/controllers/date_book/calendars_controller_spec.rb +259 -0
- data/spec/controllers/date_book/events_controller_spec.rb +283 -0
- data/spec/dummy/Rakefile +9 -0
- data/spec/dummy/app/assets/config/manifest.js +5 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css.scss +4 -0
- data/spec/dummy/app/assets/stylesheets/bootstrap-everything.scss +54 -0
- data/spec/dummy/app/controllers/application_controller.rb +21 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/mailers/application_mailer.rb +6 -0
- data/spec/dummy/app/models/ability.rb +16 -0
- data/spec/dummy/app/models/application_record.rb +5 -0
- data/spec/dummy/app/models/calendar.rb +3 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/event.rb +3 -0
- data/spec/dummy/app/models/event_occurrence.rb +3 -0
- data/spec/dummy/app/models/role.rb +13 -0
- data/spec/dummy/app/models/schedule.rb +3 -0
- data/spec/dummy/app/models/user.rb +9 -0
- data/spec/dummy/app/views/application/403.html.haml +9 -0
- data/spec/dummy/app/views/application/404.html.haml +9 -0
- data/spec/dummy/app/views/layouts/application.html.haml +43 -0
- data/spec/dummy/app/views/pages/index.html.haml +1 -0
- data/spec/dummy/bin/bundle +5 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/bin/setup +36 -0
- data/spec/dummy/bin/update +31 -0
- data/spec/dummy/config.ru +7 -0
- data/spec/dummy/config/application.rb +38 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +60 -0
- data/spec/dummy/config/environments/test.rb +45 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +7 -0
- data/spec/dummy/config/initializers/assets.rb +14 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +10 -0
- data/spec/dummy/config/initializers/bootstrap_leather.rb +9 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +7 -0
- data/spec/dummy/config/initializers/date_book.rb +5 -0
- data/spec/dummy/config/initializers/devise.rb +277 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/dummy/config/initializers/high_voltage.rb +3 -0
- data/spec/dummy/config/initializers/inflections.rb +17 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +29 -0
- data/spec/dummy/config/initializers/rolify.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +17 -0
- data/spec/dummy/config/locales/devise.en.yml +64 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +49 -0
- data/spec/dummy/config/routes.rb +15 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +8 -0
- data/spec/dummy/db/migrate/20170728171103_create_users_table.rb +7 -0
- data/spec/dummy/db/migrate/20170807134122_add_devise_to_users.rb +49 -0
- data/spec/dummy/db/migrate/20170807134128_rolify_create_roles.rb +19 -0
- data/spec/dummy/db/migrate/20170807134137_create_calendars.date_book.rb +12 -0
- data/spec/dummy/db/migrate/20170807134138_create_events.date_book.rb +21 -0
- data/spec/dummy/db/migrate/20170807134139_create_schedules.date_book.rb +26 -0
- data/spec/dummy/db/migrate/20170807134140_add_fields_to_schedule.date_book.rb +7 -0
- data/spec/dummy/db/migrate/20170807134141_create_event_occurrences.date_book.rb +17 -0
- data/spec/dummy/db/migrate/20170807134142_add_fields_to_event_occurrences.date_book.rb +6 -0
- data/spec/dummy/db/schema.rb +101 -0
- data/spec/dummy/db/seeds.rb +0 -0
- data/spec/dummy/db/seeds/calendars.seeds.rb +22 -0
- data/spec/dummy/db/seeds/events.seeds.rb +89 -0
- data/spec/dummy/db/seeds/users.seeds.rb +16 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/lib/basic_benchmark.rb +9 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/factories/calendars.rb +11 -0
- data/spec/factories/events.rb +12 -0
- data/spec/factories/roles.rb +5 -0
- data/spec/factories/users.rb +9 -0
- data/spec/features/calendars_spec.rb +185 -0
- data/spec/features/events_spec.rb +201 -0
- data/spec/helpers/date_book/calendar_helper_spec.rb +17 -0
- data/spec/helpers/date_book/events_helper_spec.rb +17 -0
- data/spec/models/calendar_spec.rb +26 -0
- data/spec/models/event_spec.rb +67 -0
- data/spec/models/role_spec.rb +5 -0
- data/spec/rails_helper.rb +116 -0
- data/spec/requests/date_book/events_spec.rb +56 -0
- data/spec/routing/date_book/calendars_routing_spec.rb +49 -0
- data/spec/routing/date_book/events_routing_spec.rb +54 -0
- data/spec/spec_helper.rb +102 -0
- data/spec/support/controller_behaviors.rb +101 -0
- data/spec/support/controller_macros.rb +25 -0
- data/spec/support/factory_girl.rb +3 -0
- data/spec/support/feature_behaviors.rb +150 -0
- data/spec/support/loaded_site.rb +5 -0
- data/spec/support/loaded_site/calendars.rb +5 -0
- data/spec/support/loaded_site/events.rb +6 -0
- data/spec/support/loaded_site/users.rb +5 -0
- data/spec/support/request_behaviors.rb +89 -0
- data/spec/support/shared_connection.rb +14 -0
- data/spec/support/utilities.rb +53 -0
- metadata +817 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
shared_examples_for 'a successful page' do |options = {}|
|
|
2
|
+
describe 'responds successfully' do
|
|
3
|
+
subject { response }
|
|
4
|
+
it { should be_success }
|
|
5
|
+
end
|
|
6
|
+
if options[:which_renders].present?
|
|
7
|
+
it_behaves_like 'a page rendering a template', options[:which_renders]
|
|
8
|
+
end
|
|
9
|
+
if options[:with_layout].present?
|
|
10
|
+
it_behaves_like 'a page rendering with a layout', options[:with_layout]
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
shared_examples_for 'a page rendering a template' do |template|
|
|
14
|
+
describe "renders the #{template} template" do
|
|
15
|
+
subject { response }
|
|
16
|
+
it { should render_template(template) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
shared_examples_for 'a page rendering with a layout' do |layout|
|
|
20
|
+
describe "renders the #{layout} layout" do
|
|
21
|
+
subject { response }
|
|
22
|
+
it { should render_template("layouts/#{layout}") }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
shared_examples_for 'an error response' do |http_status|
|
|
26
|
+
describe "issues error response code #{http_status}" do
|
|
27
|
+
subject { response }
|
|
28
|
+
it { should have_http_status(http_status) }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
shared_examples_for 'a redirect to' do |path|
|
|
32
|
+
describe "redirects to #{path}" do
|
|
33
|
+
subject { response }
|
|
34
|
+
it { should redirect_to path_to_url(path) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
shared_examples_for 'a redirect matching' do |path_expression|
|
|
38
|
+
describe "redirects matching #{path_expression}" do
|
|
39
|
+
subject { response.location }
|
|
40
|
+
it { should match path_expression }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
shared_examples_for 'a redirect to the home page' do
|
|
44
|
+
it_behaves_like 'a redirect to', '/'
|
|
45
|
+
end
|
|
46
|
+
shared_examples_for 'an error response with message' do |status, message|
|
|
47
|
+
it_behaves_like 'an error response', status
|
|
48
|
+
it_behaves_like 'a page with message', :error, message
|
|
49
|
+
end
|
|
50
|
+
shared_examples_for 'a page with message' do |flash_key, error|
|
|
51
|
+
describe 'sets message' do
|
|
52
|
+
subject { flash[flash_key] }
|
|
53
|
+
it { should eq error }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
shared_examples_for 'a page without error' do
|
|
57
|
+
describe 'sets no error message' do
|
|
58
|
+
subject { flash[:error] }
|
|
59
|
+
it { should be nil }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
shared_examples_for 'a 403 Forbidden error' do
|
|
63
|
+
it_should_behave_like(
|
|
64
|
+
'an error response with message',
|
|
65
|
+
:forbidden,
|
|
66
|
+
'You are not authorized to access this page.'
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
shared_examples_for 'a 404 Not Found error' do
|
|
70
|
+
it_should_behave_like(
|
|
71
|
+
'an error response with message',
|
|
72
|
+
:not_found,
|
|
73
|
+
'The page you requested does not exist.'
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
shared_examples_for 'a redirect with notice' do |path, message|
|
|
77
|
+
it_behaves_like 'a redirect to', path
|
|
78
|
+
describe 'sets notice' do
|
|
79
|
+
subject { flash[:notice] }
|
|
80
|
+
it { should eq message }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
shared_examples_for 'a redirect with alert' do |path, message|
|
|
84
|
+
it_behaves_like 'a redirect to', path
|
|
85
|
+
describe 'sets alert' do
|
|
86
|
+
subject { flash[:alert] }
|
|
87
|
+
it { should eq message }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
shared_examples_for 'a download' do
|
|
91
|
+
subject { response.headers['Content-Disposition'] }
|
|
92
|
+
it { should include 'attachment' }
|
|
93
|
+
end
|
|
94
|
+
shared_examples_for 'a variable assignment' do |options = {}|
|
|
95
|
+
options.each do |key, value|
|
|
96
|
+
describe "@#{key}" do
|
|
97
|
+
subject { assigns(key) }
|
|
98
|
+
it { should eq value }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module ControllerMacros
|
|
2
|
+
def login_user(user)
|
|
3
|
+
@request.env['devise.mapping'] = Devise.mappings[:user]
|
|
4
|
+
sign_in user
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
shared_context 'authentication for routes' do
|
|
9
|
+
let(:warden) do
|
|
10
|
+
instance_double('Warden::Proxy').tap do |warden|
|
|
11
|
+
allow(warden).to receive(:authenticate?).with(scope: :user)
|
|
12
|
+
.and_return(authenticated?)
|
|
13
|
+
allow(warden).to receive(:user).with(:user).and_return(user)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
let(:user) { instance_double(User) }
|
|
17
|
+
let(:authenticated?) { true }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def simulate_running_with_devise
|
|
21
|
+
stub_const(
|
|
22
|
+
'Rack::MockRequest::DEFAULT_ENV',
|
|
23
|
+
Rack::MockRequest::DEFAULT_ENV.merge('warden' => warden)
|
|
24
|
+
)
|
|
25
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
shared_examples_for 'a restricted page' do
|
|
2
|
+
describe 'redirects to the home page' do
|
|
3
|
+
subject { current_path }
|
|
4
|
+
it { should eq '/users/sign_in' }
|
|
5
|
+
end
|
|
6
|
+
it_behaves_like(
|
|
7
|
+
'a bootstrap page with an alert',
|
|
8
|
+
'danger',
|
|
9
|
+
'You must sign in or sign up to access this content.'
|
|
10
|
+
)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
shared_examples_for 'an authentication error' do
|
|
14
|
+
describe 'redirects to the home page' do
|
|
15
|
+
subject { current_path }
|
|
16
|
+
it { should eq '/' }
|
|
17
|
+
end
|
|
18
|
+
it_behaves_like(
|
|
19
|
+
'a bootstrap page with an alert',
|
|
20
|
+
'danger',
|
|
21
|
+
'You must sign in or sign up to access this content.'
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
shared_examples_for 'an authorization error' do
|
|
26
|
+
it_behaves_like(
|
|
27
|
+
'a bootstrap page with an alert',
|
|
28
|
+
'danger',
|
|
29
|
+
'You are not authorized to access this page.'
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
shared_examples_for 'an admin page' do
|
|
34
|
+
subject { page }
|
|
35
|
+
it { should have_css 'body.rails_admin' }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
shared_examples_for 'a bootstrap page' do |options = {}|
|
|
39
|
+
include ERB::Util
|
|
40
|
+
describe 'displays a page with bootstrap elements' do
|
|
41
|
+
subject { page }
|
|
42
|
+
if options[:title].present?
|
|
43
|
+
it { should have_title options[:title] }
|
|
44
|
+
it { should have_xpath '//h1', text: options[:title] }
|
|
45
|
+
end
|
|
46
|
+
it do
|
|
47
|
+
should have_selector(
|
|
48
|
+
'.navbar .navbar-header .navbar-brand',
|
|
49
|
+
text: BootstrapLeather.configuration.application_title
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
shared_examples_for 'a bootstrap page '\
|
|
56
|
+
'with a dropdown navigation list' do |options|
|
|
57
|
+
if options[:text]
|
|
58
|
+
context "has a #{options[:text]} link" do
|
|
59
|
+
before do
|
|
60
|
+
click_button 'Menu'
|
|
61
|
+
end
|
|
62
|
+
it do
|
|
63
|
+
should(
|
|
64
|
+
have_selector('li.dropdown a.dropdown-toggle', text: options[:text])
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
if options[:links]
|
|
69
|
+
options[:links].each do |link_text|
|
|
70
|
+
it "has a #{link_text} link" do
|
|
71
|
+
click_link_or_button 'Menu'
|
|
72
|
+
within find('.navbar', text: options[:text]) do
|
|
73
|
+
click_link_or_button options[:text]
|
|
74
|
+
within first('li.dropdown', text: options[:text]) do
|
|
75
|
+
expect(page).to have_link(link_text)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
it { should have_selector 'li.dropdown a.dropdown-toggle' }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
shared_examples_for 'a bootstrap page with an alert' do |type, text|
|
|
87
|
+
before do
|
|
88
|
+
wait_until { page.has_css? '.alert' }
|
|
89
|
+
end
|
|
90
|
+
subject { page }
|
|
91
|
+
it { should have_selector ".alert.alert-#{type}", text: text }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
shared_examples_for 'a bootstrap page '\
|
|
95
|
+
'listing a collection of items' do |object, options = {}|
|
|
96
|
+
options[:minimum] ||= 1
|
|
97
|
+
options[:plural_title] ||= object.model_name.human.pluralize(2).titlecase
|
|
98
|
+
options[:plural_name] ||= object.table_name
|
|
99
|
+
collection_css_class = options[:plural_name]
|
|
100
|
+
member_css_class = options[:plural_name].singularize
|
|
101
|
+
it_behaves_like 'a bootstrap page', title: options[:plural_title]
|
|
102
|
+
describe "displays a list of .#{collection_css_class} in "\
|
|
103
|
+
".#{member_css_class}" do
|
|
104
|
+
subject { page }
|
|
105
|
+
it do
|
|
106
|
+
should have_css(
|
|
107
|
+
".#{collection_css_class} .#{member_css_class}",
|
|
108
|
+
minimum: options[:minimum]
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
shared_examples_for 'a bootstrap page '\
|
|
115
|
+
'showing an item' do |object, title, options = {}|
|
|
116
|
+
options[:css_class] ||= object.table_name.singularize
|
|
117
|
+
it_behaves_like 'a bootstrap page', title: title
|
|
118
|
+
describe "displays an item at .#{options[:css_class]}" do
|
|
119
|
+
subject { page }
|
|
120
|
+
it { should have_css(".#{options[:css_class]}") }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
shared_examples_for 'a bootstrap page with a gallery' do |options = {}|
|
|
125
|
+
css = ''
|
|
126
|
+
test_name = 'displays a gallery'
|
|
127
|
+
if options[:inside]
|
|
128
|
+
test_name += " inside #{options[:inside]}"
|
|
129
|
+
css += "#{options[:inside]} "
|
|
130
|
+
end
|
|
131
|
+
css += '.gallery'
|
|
132
|
+
describe test_name do
|
|
133
|
+
subject { page }
|
|
134
|
+
it { should have_css(css) }
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
shared_examples_for 'a bootstrap form with errors' do |error_fields|
|
|
139
|
+
subject { page }
|
|
140
|
+
error_fields.each do |field|
|
|
141
|
+
it_behaves_like(
|
|
142
|
+
'a bootstrap page with an alert',
|
|
143
|
+
'danger',
|
|
144
|
+
"#{field.to_s.humanize} can't be blank"
|
|
145
|
+
)
|
|
146
|
+
it "shows errors on #{field}" do
|
|
147
|
+
expect(page.has_css?("[id$=#{field}]")).to be true
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
shared_context 'events' do
|
|
2
|
+
let(:monday_event) { Event.friendly.find('monday') }
|
|
3
|
+
let(:science_fiction_club_event) { Event.friendly.find('science-fiction-club') }
|
|
4
|
+
let(:yesterdays_event) { Event.friendly.find('yesterday-s-event') }
|
|
5
|
+
let(:tomorrows_event) { Event.friendly.find('tomorrow-s-event') }
|
|
6
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
shared_examples_for 'a Json authentication error' do
|
|
2
|
+
it_behaves_like(
|
|
3
|
+
'a json object with an error',
|
|
4
|
+
'You need to sign in or sign up before continuing.'
|
|
5
|
+
)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
shared_examples_for 'a Json authorization error' do
|
|
9
|
+
it_behaves_like(
|
|
10
|
+
'a json object with an error',
|
|
11
|
+
'You are not authorized to access this page.'
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
shared_examples_for 'a blank response' do
|
|
16
|
+
describe 'displays nothing' do
|
|
17
|
+
subject { response.body }
|
|
18
|
+
it { should eq '' }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
shared_examples_for 'a json array' do |options = {}|
|
|
23
|
+
describe 'displays an array in Json' do
|
|
24
|
+
subject { JSON.parse(response.body) }
|
|
25
|
+
it { should be_an Array }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
shared_examples_for 'a json object' do |options = {}|
|
|
30
|
+
describe 'displays an object with information about itself' do
|
|
31
|
+
subject { JSON.parse(response.body) }
|
|
32
|
+
its(['title']) { should eq options[:title] }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
shared_examples_for 'a json object with a message' do |key, text|
|
|
37
|
+
subject { JSON.parse(response.body) }
|
|
38
|
+
its([key.to_s]) { should match(/#{text}/) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
shared_examples_for 'a json object without a message' do |key|
|
|
42
|
+
subject { JSON.parse(response.body) }
|
|
43
|
+
its([key.to_s]) { should be nil }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
shared_examples_for 'a json object with an error' do |text|
|
|
47
|
+
it_behaves_like 'a json object with a message', :error, text
|
|
48
|
+
it_behaves_like 'a json object without a message', :info
|
|
49
|
+
it_behaves_like 'a json object without a message', :notice
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
shared_examples_for 'a json object with a notice' do |text|
|
|
53
|
+
it_behaves_like 'a json object with a message', :notice, text
|
|
54
|
+
it_behaves_like 'a json object without a message', :error
|
|
55
|
+
it_behaves_like 'a json object without a message', :info
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
shared_examples_for 'a json object with info' do |text|
|
|
59
|
+
it_behaves_like 'a json object with a message', :info, text
|
|
60
|
+
it_behaves_like 'a json object without a message', :error
|
|
61
|
+
it_behaves_like 'a json object without a message', :notice
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
shared_examples_for 'a json object '\
|
|
65
|
+
'listing a collection of items' do |object, options = {}|
|
|
66
|
+
options[:minimum] ||= 1
|
|
67
|
+
options[:plural_name] ||= object.table_name.to_s
|
|
68
|
+
objects_key = options[:plural_name].to_sym
|
|
69
|
+
it_behaves_like 'a json array'
|
|
70
|
+
describe "displays a list of #{objects_key}" do
|
|
71
|
+
subject { JSON.parse(response.body) }
|
|
72
|
+
its(:count) { should >= options[:minimum] }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
shared_examples_for 'a json object '\
|
|
77
|
+
'showing an item' do |object, title, options = {}|
|
|
78
|
+
describe "displays an item" do
|
|
79
|
+
subject { JSON.parse(response.body) }
|
|
80
|
+
its(['title']) { should eq title }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
shared_examples_for 'a json object with errors' do |error_fields|
|
|
85
|
+
subject { JSON.parse(response.body)[:errors] }
|
|
86
|
+
error_fields.each do |field|
|
|
87
|
+
its([field.to_s]) { should eq "#{field.to_s.humanize} can't be blank" }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
class Base
|
|
3
|
+
mattr_accessor :shared_connection
|
|
4
|
+
@@shared_connection = nil
|
|
5
|
+
|
|
6
|
+
def self.connection
|
|
7
|
+
@@shared_connection || retrieve_connection
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Forces all threads to share the same connection. This works on
|
|
13
|
+
# Capybara because it starts the web server in a thread.
|
|
14
|
+
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
def path_to_url(path)
|
|
2
|
+
protocol = request.protocol
|
|
3
|
+
host = request.host_with_port.sub(/:80$/, '')
|
|
4
|
+
stripped_path = path.sub(%r{^/}, '')
|
|
5
|
+
"#{protocol}#{host}/#{stripped_path}"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def show_page
|
|
9
|
+
save_page Rails.root.join('public', 'capybara.html')
|
|
10
|
+
# This runs launchy as a system command
|
|
11
|
+
`launchy http://localhost:3000/capybara.html`
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def wait_until(delay = 1)
|
|
15
|
+
seconds_waited = 0
|
|
16
|
+
while !yield && seconds_waited < Capybara.default_max_wait_time
|
|
17
|
+
sleep delay
|
|
18
|
+
seconds_waited += 1
|
|
19
|
+
end
|
|
20
|
+
unless yield
|
|
21
|
+
puts "Waited for #{Capybara.default_max_wait_time} seconds."
|
|
22
|
+
puts "{#{yield}} did not become true, continuing."
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def submit_via_execute(form_selector)
|
|
27
|
+
page.execute_script("$('#{form_selector}').submit();")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def click_on_body
|
|
31
|
+
page.execute_script("$('body').click();")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Used to fill wysiwig fields
|
|
35
|
+
# @param [String] locator label text for the textarea or textarea id
|
|
36
|
+
def fill_in_wysiwyg(locator, text)
|
|
37
|
+
include ActionView::Helpers::JavaScriptHelper
|
|
38
|
+
locator = find_field_by_label(locator)
|
|
39
|
+
text = text.gsub("'", "\'").gsub("\n", '\\\n')
|
|
40
|
+
|
|
41
|
+
# Fill the editor content
|
|
42
|
+
page.execute_script <<-SCRIPT
|
|
43
|
+
$('##{locator}').data('wysihtml5').editor.setValue('#{text}');
|
|
44
|
+
SCRIPT
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def find_field_by_label(locator)
|
|
48
|
+
if page.has_css?('label', text: locator)
|
|
49
|
+
find('label', text: locator)[:for]
|
|
50
|
+
else
|
|
51
|
+
locator
|
|
52
|
+
end
|
|
53
|
+
end
|