paid_up 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +46 -0
  5. data/LICENSE.txt +20 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +64 -0
  8. data/Rakefile +48 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/paid_up/paid_up_controller.rb +12 -0
  11. data/app/controllers/paid_up/plans_controller.rb +7 -0
  12. data/app/controllers/paid_up/subscriptions_controller.rb +37 -0
  13. data/app/helpers/paid_up/features_helper.rb +65 -0
  14. data/app/helpers/paid_up/paid_up_helper.rb +14 -0
  15. data/app/helpers/paid_up/plans_helper.rb +53 -0
  16. data/app/helpers/paid_up/subscriptions_helper.rb +21 -0
  17. data/app/models/ability.rb +37 -0
  18. data/app/models/paid_up/feature.rb +19 -0
  19. data/app/models/paid_up/features_plan.rb +14 -0
  20. data/app/models/paid_up/plan.rb +99 -0
  21. data/app/views/devise/confirmations/new.html.haml +13 -0
  22. data/app/views/devise/passwords/edit.html.haml +19 -0
  23. data/app/views/devise/passwords/new.html.haml +14 -0
  24. data/app/views/devise/registrations/_new_form.html.haml +23 -0
  25. data/app/views/devise/registrations/edit.html.haml +39 -0
  26. data/app/views/devise/registrations/new.html.haml +11 -0
  27. data/app/views/devise/sessions/_new_form.html.haml +21 -0
  28. data/app/views/devise/sessions/new.html.haml +11 -0
  29. data/app/views/devise/shared/_links.html.haml +14 -0
  30. data/app/views/devise/unlocks/new.html.haml +14 -0
  31. data/app/views/paid_up/features/_abilities_table.html.haml +22 -0
  32. data/app/views/paid_up/features/_table.html.haml +16 -0
  33. data/app/views/paid_up/plans/index.html.haml +18 -0
  34. data/app/views/paid_up/subscriptions/index.html.haml +16 -0
  35. data/app/views/paid_up/subscriptions/new.html.haml +101 -0
  36. data/bin/rails +12 -0
  37. data/config/initializers/stripe.rb +6 -0
  38. data/config/locales/en.yml +85 -0
  39. data/config/routes.rb +7 -0
  40. data/coverage/.last_run.json +5 -0
  41. data/coverage/.resultset.json +1488 -0
  42. data/coverage/.resultset.json.lock +0 -0
  43. data/db/migrate/20150407105900_create_paid_up_features_plans_table.rb +9 -0
  44. data/db/migrate/20150407110100_create_paid_up_features_table.rb +11 -0
  45. data/db/migrate/20150407110101_create_paid_up_plans_table.rb +14 -0
  46. data/lib/generators/paid_up/install/install_generator.rb +59 -0
  47. data/lib/generators/paid_up/install/templates/initializer.rb.erb +5 -0
  48. data/lib/generators/paid_up/utils.rb +16 -0
  49. data/lib/paid_up/configuration.rb +22 -0
  50. data/lib/paid_up/engine.rb +17 -0
  51. data/lib/paid_up/integer.rb +9 -0
  52. data/lib/paid_up/localization.rb +31 -0
  53. data/lib/paid_up/mixins.rb +139 -0
  54. data/lib/paid_up/railtie.rb +4 -0
  55. data/lib/paid_up/stripe_extensions.rb +17 -0
  56. data/lib/paid_up/table_validator.rb +9 -0
  57. data/lib/paid_up/unlimited.rb +17 -0
  58. data/lib/paid_up/version.rb +7 -0
  59. data/lib/paid_up.rb +27 -0
  60. data/paid_up.gemspec +248 -0
  61. data/spec/controllers/paid_up/plans_spec.rb +26 -0
  62. data/spec/controllers/paid_up/subscriptions_spec.rb +187 -0
  63. data/spec/dummy/README.rdoc +28 -0
  64. data/spec/dummy/Rakefile +6 -0
  65. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  66. data/spec/dummy/app/assets/stylesheets/application.css.scss +16 -0
  67. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  68. data/spec/dummy/app/models/group.rb +3 -0
  69. data/spec/dummy/app/models/user.rb +9 -0
  70. data/spec/dummy/app/views/layouts/application.html.haml +31 -0
  71. data/spec/dummy/app/views/pages/index.html.haml +1 -0
  72. data/spec/dummy/bin/bundle +3 -0
  73. data/spec/dummy/bin/rails +4 -0
  74. data/spec/dummy/bin/rake +4 -0
  75. data/spec/dummy/bin/setup +29 -0
  76. data/spec/dummy/config/application.rb +32 -0
  77. data/spec/dummy/config/boot.rb +5 -0
  78. data/spec/dummy/config/database.yml +25 -0
  79. data/spec/dummy/config/environment.rb +5 -0
  80. data/spec/dummy/config/environments/development.rb +46 -0
  81. data/spec/dummy/config/environments/production.rb +79 -0
  82. data/spec/dummy/config/environments/test.rb +45 -0
  83. data/spec/dummy/config/initializers/assets.rb +11 -0
  84. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  85. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  86. data/spec/dummy/config/initializers/devise.rb +259 -0
  87. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  88. data/spec/dummy/config/initializers/high_voltage.rb +3 -0
  89. data/spec/dummy/config/initializers/inflections.rb +16 -0
  90. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  91. data/spec/dummy/config/initializers/paid_up.rb +5 -0
  92. data/spec/dummy/config/initializers/session_store.rb +3 -0
  93. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  94. data/spec/dummy/config/locales/devise.en.yml +60 -0
  95. data/spec/dummy/config/locales/en.yml +23 -0
  96. data/spec/dummy/config/routes.rb +4 -0
  97. data/spec/dummy/config/secrets.yml +22 -0
  98. data/spec/dummy/config.ru +4 -0
  99. data/spec/dummy/db/development.sqlite3 +0 -0
  100. data/spec/dummy/db/migrate/20150406154440_create_users_table.rb +7 -0
  101. data/spec/dummy/db/migrate/20150517175135_create_groups_table.rb +11 -0
  102. data/spec/dummy/db/migrate/20150518000915_add_devise_to_users.rb +49 -0
  103. data/spec/dummy/db/migrate/20150518000917_create_paid_up_features_plans_table.paid_up.rb +10 -0
  104. data/spec/dummy/db/migrate/20150518000918_create_paid_up_features_table.paid_up.rb +12 -0
  105. data/spec/dummy/db/migrate/20150518000919_create_paid_up_plans_table.paid_up.rb +15 -0
  106. data/spec/dummy/db/migrate/20150518000920_add_stripe_id_column_to_user.rb +6 -0
  107. data/spec/dummy/db/schema.rb +75 -0
  108. data/spec/dummy/db/seeds/features.seeds.rb +19 -0
  109. data/spec/dummy/db/seeds/features_plans.seeds.rb +51 -0
  110. data/spec/dummy/db/seeds/plans.seeds.rb +91 -0
  111. data/spec/dummy/db/seeds.rb +0 -0
  112. data/spec/dummy/db/test.sqlite3 +0 -0
  113. data/spec/dummy/lib/assets/.keep +0 -0
  114. data/spec/dummy/log/.keep +0 -0
  115. data/spec/dummy/log/development.log +108393 -0
  116. data/spec/dummy/public/404.html +67 -0
  117. data/spec/dummy/public/422.html +67 -0
  118. data/spec/dummy/public/500.html +66 -0
  119. data/spec/dummy/public/assets/.sprockets-manifest-34b01376fc56586f4f4fd19e7b1c0e35.json +1 -0
  120. data/spec/dummy/public/assets/application-27f004bb902952dbbaad25f0f28c312f29ffee315c94fa51dea6b5ec6dc993e6.css +13 -0
  121. data/spec/dummy/public/assets/application-3a226fbacd7ba9a2b9f7972fafdd7b2486c34707d96a60c26f3bbe4579c29ca6.js +116 -0
  122. data/spec/dummy/public/assets/bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot +0 -0
  123. data/spec/dummy/public/assets/bootstrap/glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg +288 -0
  124. data/spec/dummy/public/assets/bootstrap/glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff +0 -0
  125. data/spec/dummy/public/assets/bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf +0 -0
  126. data/spec/dummy/public/assets/bootstrap/glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2 +0 -0
  127. data/spec/dummy/public/favicon.ico +0 -0
  128. data/spec/dummy/test/controllers/plans_controller_controller_test.rb +7 -0
  129. data/spec/factories/feature.rb +7 -0
  130. data/spec/factories/features_plan.rb +7 -0
  131. data/spec/factories/plan.rb +7 -0
  132. data/spec/factories/user.rb +7 -0
  133. data/spec/models/paid_up/feature_spec.rb +21 -0
  134. data/spec/models/paid_up/features_plan_spec.rb +7 -0
  135. data/spec/models/paid_up/plan_spec.rb +156 -0
  136. data/spec/models/user_spec.rb +304 -0
  137. data/spec/paid_up_spec.rb +7 -0
  138. data/spec/rails_helper.rb +65 -0
  139. data/spec/routing/paid_up/plans_spec.rb +11 -0
  140. data/spec/routing/paid_up/subscription_spec.rb +23 -0
  141. data/spec/spec_helper.rb +87 -0
  142. data/spec/support/controller_macros.rb +12 -0
  143. data/spec/support/factory_girl.rb +3 -0
  144. data/spec/support/plans_and_features.rb +209 -0
  145. data/spec/support/stripe.rb +23 -0
  146. data/spec/support/subscribers.rb +44 -0
  147. data/spec/views/paid_up/plans_spec.rb +54 -0
  148. data/spec/views/paid_up/subscriptions_spec.rb +58 -0
  149. metadata +488 -0
@@ -0,0 +1,156 @@
1
+ require 'rails_helper'
2
+
3
+ describe PaidUp::Plan do
4
+ it { should have_many(:features_plans).class_name('PaidUp::FeaturesPlan') }
5
+ it { should have_many(:features).class_name('PaidUp::Feature').through(:features_plans) }
6
+
7
+ it { should validate_presence_of(:description) }
8
+ it { should validate_presence_of(:name) }
9
+
10
+ include_context 'plans and features'
11
+
12
+ describe '.subscribable' do
13
+ context 'returns all subscribable plans' do
14
+ subject { PaidUp::Plan.subscribable }
15
+ it { should eq [free_plan, no_ads_plan, group_leader_plan, professional_plan]}
16
+ end
17
+ end
18
+
19
+ describe '.free' do
20
+ context 'returns the free plan' do
21
+ subject { PaidUp::Plan.free }
22
+ it { should eq free_plan}
23
+ end
24
+ end
25
+
26
+ describe '#feature_setting' do
27
+ describe 'when setting_type is integer' do
28
+ context 'returns the setting value if available' do
29
+ subject { group_leader_plan.feature_setting(groups_feature.id) }
30
+ it { should eq(1) }
31
+ end
32
+ context 'returns 0 if not available' do
33
+ subject { free_plan.feature_setting(groups_feature.id) }
34
+ it { should eq(0) }
35
+ end
36
+ end
37
+
38
+ describe 'when setting_type is boolean' do
39
+ context 'returns the setting value if available' do
40
+ subject { group_leader_plan.feature_setting(configuration_feature.id) }
41
+ it { should eq(true) }
42
+ end
43
+ context 'returns false if not available' do
44
+ subject { free_plan.feature_setting(configuration_feature.id) }
45
+ it { should eq(false) }
46
+ end
47
+ end
48
+ end
49
+
50
+ describe '#feature_setting_by_name' do
51
+ describe 'when setting_type is integer' do
52
+ context 'returns the setting value if available' do
53
+ subject { group_leader_plan.feature_setting_by_name('groups') }
54
+ it { should eq(1) }
55
+ end
56
+ context 'returns 0 if not available' do
57
+ subject { free_plan.feature_setting_by_name('groups') }
58
+ it { should eq(0) }
59
+ end
60
+ end
61
+
62
+ describe 'when setting_type is boolean' do
63
+ context 'returns the setting value if available' do
64
+ subject { group_leader_plan.feature_setting_by_name('ad_free') }
65
+ it { should eq(true) }
66
+ end
67
+ context 'returns false if not available' do
68
+ subject { free_plan.feature_setting_by_name('ad_free') }
69
+ it { should eq(false) }
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '#feature_unlimited?' do
75
+ context 'returns true if unlimited' do
76
+ subject { professional_plan.feature_unlimited?(groups_feature.id) }
77
+ it { should eq(true) }
78
+ end
79
+ context 'returns false if an integer' do
80
+ subject { group_leader_plan.feature_unlimited?(groups_feature.id) }
81
+ it { should eq(false) }
82
+ end
83
+ context 'returns false if not found' do
84
+ subject { free_plan.feature_unlimited?(groups_feature.id) }
85
+ it { should eq(false) }
86
+ end
87
+ end
88
+
89
+ describe '#interval' do
90
+ context 'on free plan' do
91
+ subject { free_plan.interval }
92
+ it { should eq 'month' }
93
+ end
94
+ context 'on a regular plan' do
95
+ subject { no_ads_plan.interval }
96
+ it { should eq 'month' }
97
+ end
98
+ end
99
+
100
+ describe '#interval_count' do
101
+ context 'on free plan' do
102
+ subject { free_plan.interval_count }
103
+ it { should eq 1 }
104
+ end
105
+ context 'on a regular plan' do
106
+ subject { no_ads_plan.interval_count }
107
+ it { should eq 1 }
108
+ end
109
+ end
110
+
111
+ describe '#amount' do
112
+ context 'on default plan' do
113
+ subject { free_plan.amount }
114
+ it { should eq 0 }
115
+ end
116
+ context 'on a regular plan' do
117
+ subject { no_ads_plan.amount }
118
+ it { should eq 100 }
119
+ end
120
+ end
121
+
122
+ describe '#money' do
123
+ context 'on default plan' do
124
+ subject { free_plan.money }
125
+ it { should be_a Money }
126
+ end
127
+ context 'on a regular plan' do
128
+ subject { no_ads_plan.money }
129
+ it { should be_a Money }
130
+ end
131
+ end
132
+
133
+ describe '#charge' do
134
+ context 'on default plan' do
135
+ subject { free_plan.charge }
136
+ it { should eq 0 }
137
+ end
138
+ context 'on a regular plan' do
139
+ subject { no_ads_plan.charge }
140
+ it { should eq 1 }
141
+ end
142
+ end
143
+
144
+ describe '#currency' do
145
+ context 'on default plan' do
146
+ subject { free_plan.currency }
147
+ it { should eq 'USD' }
148
+ end
149
+ context 'on a regular plan' do
150
+ subject { no_ads_plan.currency }
151
+ it { should eq 'USD' }
152
+ end
153
+ end
154
+
155
+
156
+ end
@@ -0,0 +1,304 @@
1
+ require 'rails_helper'
2
+ require "cancan/matchers"
3
+
4
+ describe User do
5
+ include_context 'subscribers'
6
+
7
+ context '#stripe_data' do
8
+ subject { no_ads_subscriber.stripe_data }
9
+ it { should be_a Stripe::Customer }
10
+ end
11
+
12
+ context '#cards' do
13
+ subject { professional_subscriber.cards.first }
14
+ it { should be_a Stripe::Card }
15
+ end
16
+
17
+ context '#subscribe_to_plan' do
18
+ context 'starting from no subscription' do
19
+ before do
20
+ token = working_stripe_token free_subscriber
21
+ free_subscriber.subscribe_to_plan no_ads_plan, token
22
+ end
23
+ subject { free_subscriber.plan }
24
+ it { should eq(no_ads_plan) }
25
+ end
26
+
27
+ context 'starting from lower subscription' do
28
+ context 'with saved card' do
29
+ before do
30
+ no_ads_subscriber.subscribe_to_plan group_leader_plan
31
+ end
32
+ subject { no_ads_subscriber.plan }
33
+ it { should eq(group_leader_plan) }
34
+ end
35
+ context 'with new token' do
36
+ before do
37
+ token = working_stripe_token no_ads_subscriber
38
+ no_ads_subscriber.subscribe_to_plan group_leader_plan, token
39
+ end
40
+ subject { no_ads_subscriber.plan }
41
+ it { should eq(group_leader_plan) }
42
+ end
43
+ end
44
+
45
+ context '#subscribe_to_free_plan' do
46
+ context 'starting from no subscription' do
47
+ let(:test_user) {
48
+ user = FactoryGirl.create(
49
+ :user,
50
+ name: 'Test User'
51
+ )
52
+ user.subscribe_to_free_plan
53
+ user
54
+ }
55
+ subject { test_user.plan }
56
+ it { should eq(free_plan) }
57
+ end
58
+
59
+ context 'starting from higher subscription' do
60
+ before do
61
+ professional_subscriber.subscribe_to_free_plan
62
+ end
63
+ subject { professional_subscriber.plan }
64
+ it { should eq(free_plan) }
65
+ end
66
+ end
67
+ end
68
+
69
+ context '#plan' do
70
+ context 'when using free plan' do
71
+ subject { free_subscriber.plan }
72
+ it { should eq free_plan }
73
+ end
74
+ context 'when subscribed to a plan' do
75
+ subject { no_ads_subscriber.plan }
76
+ it { should eq no_ads_plan }
77
+ end
78
+ end
79
+
80
+ context '#table_rows_remaining' do
81
+ context 'when using a plan without the feature' do
82
+ subject { no_ads_subscriber.table_rows_remaining 'groups' }
83
+ it { should eq 0 }
84
+ end
85
+ context 'when subscribed to a plan with the feature limited' do
86
+ subject { group_leader_subscriber.table_rows_remaining 'groups' }
87
+ it { should eq 1 }
88
+ end
89
+ context 'when subscribed to a plan with the feature unlimited' do
90
+ subject { professional_subscriber.table_rows_remaining 'groups' }
91
+ it { should eq PaidUp::Unlimited.to_i }
92
+ end
93
+ end
94
+
95
+ context '#table_rows_unlimited?' do
96
+ context 'when using a plan without the feature' do
97
+ subject { no_ads_subscriber.table_rows_unlimited? 'groups' }
98
+ it { should eq false }
99
+ end
100
+ context 'when subscribed to a plan with the feature limited' do
101
+ subject { group_leader_subscriber.table_rows_unlimited? 'groups' }
102
+ it { should eq false }
103
+ end
104
+ context 'when subscribed to a plan with the feature unlimited' do
105
+ subject { professional_subscriber.table_rows_unlimited? 'groups' }
106
+ it { should eq true }
107
+ end
108
+ end
109
+
110
+ context '#table_rows_allowed' do
111
+ context 'when using a plan without the feature' do
112
+ subject { no_ads_subscriber.table_rows_allowed 'groups' }
113
+ it { should eq 0 }
114
+ end
115
+ context 'when subscribed to a plan with the feature limited' do
116
+ subject { group_leader_subscriber.table_rows_allowed 'groups' }
117
+ it { should eq 1 }
118
+ end
119
+ context 'when subscribed to a plan with the feature unlimited' do
120
+ subject { professional_subscriber.table_rows_allowed 'groups' }
121
+ it { should eq PaidUp::Unlimited.to_i }
122
+ end
123
+ end
124
+
125
+ context '#table_rows' do
126
+ context 'when possessing no rows' do
127
+ subject { professional_subscriber.table_rows 'groups' }
128
+ it { should eq 0 }
129
+ end
130
+ context 'when possessing 3 rows' do
131
+ subject {
132
+ professional_subscriber.groups.create! name: 'Test Group'
133
+ professional_subscriber.groups.create! name: 'Test Group'
134
+ professional_subscriber.groups.create! name: 'Test Group'
135
+ professional_subscriber.table_rows 'groups'
136
+ }
137
+ it { should eq 3 }
138
+ end
139
+ end
140
+
141
+ context '#plan_stripe_id' do
142
+ context 'when using free plan' do
143
+ subject { free_subscriber.plan_stripe_id }
144
+ it { should eq 'free-plan' }
145
+ end
146
+ context 'when subscribed to a plan' do
147
+ subject { no_ads_subscriber.plan_stripe_id }
148
+ it { should eq 'no-ads-plan' }
149
+ end
150
+ end
151
+
152
+ context '#subscription' do
153
+ context 'when using free plan' do
154
+ subject { free_subscriber.subscription }
155
+ it { should be_a Stripe::Subscription }
156
+ end
157
+ context 'when subscribed to a plan' do
158
+ subject { no_ads_subscriber.subscription }
159
+ it { should be_a Stripe::Subscription }
160
+ end
161
+ end
162
+
163
+ context '#is_subscribed_to?' do
164
+ context 'when using free plan' do
165
+ subject { free_subscriber.is_subscribed_to? free_plan }
166
+ it { should be true }
167
+ end
168
+ context 'when true' do
169
+ subject { professional_subscriber.is_subscribed_to? professional_plan }
170
+ it { should be true }
171
+ end
172
+ context 'when false' do
173
+ subject { no_ads_subscriber.is_subscribed_to? professional_plan }
174
+ it { should be false }
175
+ end
176
+ end
177
+
178
+ context '#can_upgrade_to?' do
179
+ context 'when using free plan' do
180
+ context 'checking against free plan' do
181
+ subject { free_subscriber.can_upgrade_to? free_plan }
182
+ it { should be false }
183
+ end
184
+ context 'checking against another plan' do
185
+ subject { free_subscriber.can_upgrade_to? no_ads_plan }
186
+ it { should be true }
187
+ end
188
+ end
189
+ context 'when true' do
190
+ subject { no_ads_subscriber.can_upgrade_to? professional_plan }
191
+ it { should be true }
192
+ end
193
+ context 'when false' do
194
+ subject { professional_subscriber.can_upgrade_to? no_ads_plan }
195
+ it { should be false }
196
+ end
197
+ end
198
+
199
+ context '#can_downgrade_to?' do
200
+ context 'when using free plan' do
201
+ context 'checking against free plan' do
202
+ subject { free_subscriber.can_downgrade_to? free_plan }
203
+ it { should be false }
204
+ end
205
+ context 'checking against another plan' do
206
+ subject { free_subscriber.can_downgrade_to? no_ads_plan }
207
+ it { should be false }
208
+ end
209
+ end
210
+ context 'when false' do
211
+ subject { no_ads_subscriber.can_downgrade_to? professional_plan }
212
+ it { should be false }
213
+ end
214
+ context 'when true' do
215
+ subject { professional_subscriber.can_downgrade_to? no_ads_plan }
216
+ it { should be true }
217
+ end
218
+ end
219
+
220
+ context '#using_free_plan?' do
221
+ context 'when false' do
222
+ subject { no_ads_subscriber.using_free_plan? }
223
+ it { should be false }
224
+ end
225
+ context 'when true' do
226
+ subject { free_subscriber.using_free_plan? }
227
+ it { should be true }
228
+ end
229
+ end
230
+
231
+ ####################
232
+ # Abilities #
233
+ ####################
234
+
235
+
236
+ describe "Abilities" do
237
+ subject(:ability){ Ability.new(user) }
238
+
239
+ context "when anonymous" do
240
+ let(:user){ User.new }
241
+ it{ should be_able_to(:read, Group) }
242
+ it{ should_not be_able_to(:manage, Group) }
243
+ it{ should_not be_able_to(:own, Group) }
244
+ it{ should_not be_able_to(:create, Group) }
245
+ it{ should_not be_able_to(:use, :ad_free) }
246
+ it{ should_not be_able_to(:use, :calendar) }
247
+ end
248
+ context "when on free plan" do
249
+ let(:user){ free_subscriber }
250
+ it{ should be_able_to(:read, Group) }
251
+ it{ should_not be_able_to(:manage, Group) }
252
+ it{ should_not be_able_to(:own, Group) }
253
+ it{ should_not be_able_to(:create, Group) }
254
+ it{ should_not be_able_to(:use, :ad_free) }
255
+ it{ should_not be_able_to(:use, :calendar) }
256
+ end
257
+ context "when on group plan" do
258
+ context "given no groups are owned" do
259
+ let(:user){ group_leader_subscriber }
260
+ it{ should be_able_to(:read, Group) }
261
+ it{ should be_able_to(:manage, Group) }
262
+ it{ should be_able_to(:own, Group) }
263
+ it{ should be_able_to(:create, Group) }
264
+ it{ should be_able_to(:use, :ad_free) }
265
+ it{ should_not be_able_to(:use, :calendar) }
266
+ end
267
+ context "given one group is owned" do
268
+ let(:user){
269
+ group_leader_subscriber.groups.create!(name: 'Test Group')
270
+ group_leader_subscriber.reload
271
+ }
272
+ it{ should be_able_to(:read, Group) }
273
+ it{ should be_able_to(:manage, Group) }
274
+ it{ should be_able_to(:own, Group) }
275
+ it{ should_not be_able_to(:create, Group) }
276
+ it{ should be_able_to(:use, :ad_free) }
277
+ it{ should_not be_able_to(:use, :calendar) }
278
+ end
279
+ end
280
+ context "when on professional plan" do
281
+ context "given no groups are owned" do
282
+ let(:user){ professional_subscriber }
283
+ it{ should be_able_to(:read, Group) }
284
+ it{ should be_able_to(:manage, Group) }
285
+ it{ should be_able_to(:own, Group) }
286
+ it{ should be_able_to(:create, Group) }
287
+ it{ should be_able_to(:use, :ad_free) }
288
+ it{ should be_able_to(:use, :calendar) }
289
+ end
290
+ context "given one group is owned" do
291
+ let(:user){
292
+ professional_subscriber.groups.create!(name: 'Test Group')
293
+ professional_subscriber.reload
294
+ }
295
+ it{ should be_able_to(:read, Group) }
296
+ it{ should be_able_to(:manage, Group) }
297
+ it{ should be_able_to(:own, Group) }
298
+ it{ should be_able_to(:create, Group) }
299
+ it{ should be_able_to(:use, :ad_free) }
300
+ it{ should be_able_to(:use, :calendar) }
301
+ end
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ describe "PaidUp" do
4
+ it 'should return correct version string' do
5
+ PaidUp.version_string.should == "PaidUp version #{PaidUp::VERSION}"
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
5
+ ENV['RAILS_ENV'] ||= 'test'
6
+ require 'spec_helper'
7
+ require File.expand_path('../dummy/config/environment', __FILE__)
8
+ require 'rspec/rails'
9
+ # Add additional requires below this line. Rails is not loaded until this point!
10
+ require 'shoulda/matchers'
11
+ require 'factory_girl_rails'
12
+
13
+ # Requires supporting ruby files with custom matchers and macros, etc, in
14
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
15
+ # run as spec files by default. This means that files in spec/support that end
16
+ # in _spec.rb will both be required and run as specs, causing the specs to be
17
+ # run twice. It is recommended that you do not name files matching this glob to
18
+ # end with _spec.rb. You can configure this pattern with the --pattern
19
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
20
+ #
21
+ # The following line is provided for convenience purposes. It has the downside
22
+ # of increasing the boot-up time by auto-requiring all files in the support
23
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
24
+ # require only the support files necessary.
25
+ #
26
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
27
+
28
+ # Checks for pending migrations before tests are run.
29
+ # If you are not using ActiveRecord, you can remove this line.
30
+ # ActiveRecord::Migration.maintain_test_schema!
31
+
32
+ RSpec.configure do |config|
33
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
34
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures
35
+
36
+ config.expect_with(:rspec) { |c| c.syntax = :should }
37
+
38
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
39
+ # examples within a transaction, remove the following line or assign false
40
+ # instead of true.
41
+ config.use_transactional_fixtures = true
42
+
43
+ # RSpec Rails can automatically mix in different behaviours to your tests
44
+ # based on their file location, for example enabling you to call `get` and
45
+ # `post` in specs under `spec/controllers`.
46
+ #
47
+ # You can disable this behaviour by removing the line below, and instead
48
+ # explicitly tag your specs with their type, e.g.:
49
+ #
50
+ # RSpec.describe UsersController, :type => :controller do
51
+ # # ...
52
+ # end
53
+ #
54
+ # The different available types are documented in the features, such as in
55
+ # https://relishapp.com/rspec/rspec-rails/docs
56
+ config.infer_spec_type_from_file_location!
57
+
58
+ config.before(:each) { @routes = PaidUp::Engine.routes }
59
+ config.include PaidUp::Engine.routes.url_helpers
60
+
61
+ config.include Devise::TestHelpers, type: :controller
62
+ config.include Devise::TestHelpers, type: :view
63
+ config.include ControllerMacros, type: :controller
64
+ config.include ControllerMacros, type: :view
65
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'PaidUp::Routing' do
4
+ include_context 'plans and features'
5
+ routes { PaidUp::Engine.routes }
6
+
7
+ describe "routes to the list of all plans" do
8
+ subject { get plans_path }
9
+ it { should route_to(:controller => "paid_up/plans", :action => "index")}
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'PaidUp::Routing' do
4
+ include_context 'plans and features'
5
+ routes { PaidUp::Engine.routes }
6
+
7
+ describe 'nested resource' do
8
+ context "routes to a new subscription for a plan" do
9
+ subject { get new_plan_subscription_path(professional_plan) }
10
+ it { should route_to(:controller => "paid_up/subscriptions", :action => "new", :plan_id => professional_plan.id.to_s) }
11
+ end
12
+ context "routes to create a subscription for a plan" do
13
+ subject { post plan_subscriptions_path(professional_plan) }
14
+ it { should route_to(:controller => "paid_up/subscriptions", :action => "create", :plan_id => professional_plan.id.to_s) }
15
+ end
16
+ end
17
+ describe 'top-level resource' do
18
+ context "routes to a display of subscriptions for a user" do
19
+ subject { get subscriptions_path }
20
+ it { should route_to(:controller => "paid_up/subscriptions", :action => "index") }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,87 @@
1
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ =begin
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ # Limits the available syntax to the non-monkey patched syntax that is
54
+ # recommended. For more details, see:
55
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
56
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
57
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
58
+ config.disable_monkey_patching!
59
+
60
+ # Many RSpec users commonly either run the entire suite or an individual
61
+ # file, and it's useful to allow more verbose output when running an
62
+ # individual spec file.
63
+ if config.files_to_run.one?
64
+ # Use the documentation formatter for detailed output,
65
+ # unless a formatter has already been configured
66
+ # (e.g. via a command-line flag).
67
+ config.default_formatter = 'doc'
68
+ end
69
+
70
+ # Print the 10 slowest examples and example groups at the
71
+ # end of the spec run, to help surface which specs are running
72
+ # particularly slow.
73
+ config.profile_examples = 10
74
+
75
+ # Run specs in random order to surface order dependencies. If you find an
76
+ # order dependency and want to debug it, you can fix the order by providing
77
+ # the seed, which is printed after each run.
78
+ # --seed 1234
79
+ config.order = :random
80
+
81
+ # Seed global randomization in this process using the `--seed` CLI option.
82
+ # Setting this allows you to use `--seed` to deterministically reproduce
83
+ # test failures related to randomization by passing the same `--seed` value
84
+ # as the one that triggered the failure.
85
+ Kernel.srand config.seed
86
+ =end
87
+ end
@@ -0,0 +1,12 @@
1
+ module ControllerMacros
2
+ def access_anonymous
3
+ sign_out :user
4
+ User.new
5
+ end
6
+
7
+ def login_subscriber(subscriber)
8
+ @request.env["devise.mapping"] = Devise.mappings[:user]
9
+ sign_in subscriber
10
+ subscriber
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.include FactoryGirl::Syntax::Methods
3
+ end