saasy 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.
Files changed (146) hide show
  1. data/CHANGELOG.md +114 -0
  2. data/Gemfile +26 -0
  3. data/README.md +118 -0
  4. data/Rakefile +38 -0
  5. data/app/controllers/accounts_controller.rb +68 -0
  6. data/app/controllers/billings_controller.rb +25 -0
  7. data/app/controllers/invitations_controller.rb +65 -0
  8. data/app/controllers/memberships_controller.rb +45 -0
  9. data/app/controllers/plans_controller.rb +24 -0
  10. data/app/controllers/profiles_controller.rb +19 -0
  11. data/app/helpers/limits_helper.rb +13 -0
  12. data/app/mailers/billing_mailer.rb +53 -0
  13. data/app/mailers/invitation_mailer.rb +18 -0
  14. data/app/models/invitation.rb +113 -0
  15. data/app/models/limit.rb +49 -0
  16. data/app/models/membership.rb +26 -0
  17. data/app/models/permission.rb +19 -0
  18. data/app/models/signup.rb +163 -0
  19. data/app/views/accounts/_account.html.erb +9 -0
  20. data/app/views/accounts/_blank_slate.html.erb +6 -0
  21. data/app/views/accounts/_projects.html.erb +12 -0
  22. data/app/views/accounts/_subnav.html.erb +10 -0
  23. data/app/views/accounts/edit.html.erb +34 -0
  24. data/app/views/accounts/index.html.erb +9 -0
  25. data/app/views/accounts/new.html.erb +36 -0
  26. data/app/views/billing_mailer/completed_trial.text.erb +13 -0
  27. data/app/views/billing_mailer/expiring_trial.text.erb +15 -0
  28. data/app/views/billing_mailer/new_unactivated.text.erb +1 -0
  29. data/app/views/billing_mailer/problem.html.erb +13 -0
  30. data/app/views/billing_mailer/problem.text.erb +14 -0
  31. data/app/views/billing_mailer/receipt.html.erb +41 -0
  32. data/app/views/billing_mailer/receipt.text.erb +25 -0
  33. data/app/views/billings/_form.html.erb +8 -0
  34. data/app/views/billings/edit.html.erb +13 -0
  35. data/app/views/billings/show.html.erb +29 -0
  36. data/app/views/invitation_mailer/invitation.text.erb +6 -0
  37. data/app/views/invitations/new.html.erb +17 -0
  38. data/app/views/invitations/show.html.erb +22 -0
  39. data/app/views/layouts/saucy.html.erb +36 -0
  40. data/app/views/limits/_meter.html.erb +13 -0
  41. data/app/views/memberships/edit.html.erb +21 -0
  42. data/app/views/memberships/index.html.erb +17 -0
  43. data/app/views/plans/_plan.html.erb +32 -0
  44. data/app/views/plans/_terms.html.erb +15 -0
  45. data/app/views/plans/edit.html.erb +33 -0
  46. data/app/views/plans/index.html.erb +12 -0
  47. data/app/views/profiles/_inputs.html.erb +5 -0
  48. data/app/views/profiles/edit.html.erb +36 -0
  49. data/app/views/projects/_form.html.erb +36 -0
  50. data/app/views/projects/edit.html.erb +22 -0
  51. data/app/views/projects/index.html.erb +28 -0
  52. data/app/views/projects/new.html.erb +13 -0
  53. data/app/views/projects/show.html.erb +0 -0
  54. data/app/views/shared/_project_dropdown.html.erb +55 -0
  55. data/app/views/shared/_saucy_javascript.html.erb +33 -0
  56. data/config/locales/en.yml +37 -0
  57. data/config/routes.rb +19 -0
  58. data/features/run_features.feature +83 -0
  59. data/features/step_definitions/clearance_steps.rb +45 -0
  60. data/features/step_definitions/rails_steps.rb +73 -0
  61. data/features/step_definitions/saucy_steps.rb +8 -0
  62. data/features/support/env.rb +4 -0
  63. data/features/support/file.rb +11 -0
  64. data/lib/generators/saucy/base.rb +18 -0
  65. data/lib/generators/saucy/features/features_generator.rb +91 -0
  66. data/lib/generators/saucy/features/templates/README +3 -0
  67. data/lib/generators/saucy/features/templates/factories.rb +71 -0
  68. data/lib/generators/saucy/features/templates/features/edit_profile.feature +9 -0
  69. data/lib/generators/saucy/features/templates/features/edit_project_permissions.feature +37 -0
  70. data/lib/generators/saucy/features/templates/features/edit_user_permissions.feature +47 -0
  71. data/lib/generators/saucy/features/templates/features/manage_account.feature +35 -0
  72. data/lib/generators/saucy/features/templates/features/manage_billing.feature +93 -0
  73. data/lib/generators/saucy/features/templates/features/manage_plan.feature +143 -0
  74. data/lib/generators/saucy/features/templates/features/manage_projects.feature +139 -0
  75. data/lib/generators/saucy/features/templates/features/manage_users.feature +142 -0
  76. data/lib/generators/saucy/features/templates/features/new_account.feature +33 -0
  77. data/lib/generators/saucy/features/templates/features/project_dropdown.feature +77 -0
  78. data/lib/generators/saucy/features/templates/features/sign_up.feature +32 -0
  79. data/lib/generators/saucy/features/templates/features/sign_up_paid.feature +65 -0
  80. data/lib/generators/saucy/features/templates/features/trial_plans.feature +82 -0
  81. data/lib/generators/saucy/features/templates/step_definitions/account_steps.rb +30 -0
  82. data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +25 -0
  83. data/lib/generators/saucy/features/templates/step_definitions/cron_steps.rb +23 -0
  84. data/lib/generators/saucy/features/templates/step_definitions/email_steps.rb +40 -0
  85. data/lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb +1 -0
  86. data/lib/generators/saucy/features/templates/step_definitions/html_steps.rb +51 -0
  87. data/lib/generators/saucy/features/templates/step_definitions/plan_steps.rb +16 -0
  88. data/lib/generators/saucy/features/templates/step_definitions/project_steps.rb +4 -0
  89. data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +37 -0
  90. data/lib/generators/saucy/features/templates/step_definitions/user_steps.rb +100 -0
  91. data/lib/generators/saucy/features/templates/support/braintree.rb +5 -0
  92. data/lib/generators/saucy/install/install_generator.rb +40 -0
  93. data/lib/generators/saucy/install/templates/controllers/projects_controller.rb +3 -0
  94. data/lib/generators/saucy/install/templates/create_saucy_tables.rb +115 -0
  95. data/lib/generators/saucy/install/templates/models/account.rb +3 -0
  96. data/lib/generators/saucy/install/templates/models/plan.rb +3 -0
  97. data/lib/generators/saucy/install/templates/models/project.rb +3 -0
  98. data/lib/generators/saucy/specs/specs_generator.rb +20 -0
  99. data/lib/generators/saucy/specs/templates/support/braintree.rb +5 -0
  100. data/lib/generators/saucy/views/views_generator.rb +23 -0
  101. data/lib/saucy.rb +10 -0
  102. data/lib/saucy/account.rb +132 -0
  103. data/lib/saucy/account_authorization.rb +67 -0
  104. data/lib/saucy/configuration.rb +29 -0
  105. data/lib/saucy/engine.rb +35 -0
  106. data/lib/saucy/fake_braintree.rb +134 -0
  107. data/lib/saucy/layouts.rb +36 -0
  108. data/lib/saucy/plan.rb +54 -0
  109. data/lib/saucy/project.rb +125 -0
  110. data/lib/saucy/projects_controller.rb +94 -0
  111. data/lib/saucy/railties/tasks.rake +28 -0
  112. data/lib/saucy/routing_extensions.rb +121 -0
  113. data/lib/saucy/subscription.rb +237 -0
  114. data/lib/saucy/user.rb +30 -0
  115. data/spec/controllers/accounts_controller_spec.rb +228 -0
  116. data/spec/controllers/application_controller_spec.rb +32 -0
  117. data/spec/controllers/invitations_controller_spec.rb +215 -0
  118. data/spec/controllers/memberships_controller_spec.rb +117 -0
  119. data/spec/controllers/plans_controller_spec.rb +13 -0
  120. data/spec/controllers/profiles_controller_spec.rb +48 -0
  121. data/spec/controllers/projects_controller_spec.rb +216 -0
  122. data/spec/environment.rb +95 -0
  123. data/spec/layouts_spec.rb +21 -0
  124. data/spec/mailers/billing_mailer_spec.rb +68 -0
  125. data/spec/mailers/invitiation_mailer_spec.rb +19 -0
  126. data/spec/models/account_spec.rb +218 -0
  127. data/spec/models/invitation_spec.rb +320 -0
  128. data/spec/models/limit_spec.rb +70 -0
  129. data/spec/models/membership_spec.rb +37 -0
  130. data/spec/models/permission_spec.rb +30 -0
  131. data/spec/models/plan_spec.rb +81 -0
  132. data/spec/models/project_spec.rb +223 -0
  133. data/spec/models/signup_spec.rb +177 -0
  134. data/spec/models/subscription_spec.rb +481 -0
  135. data/spec/models/user_spec.rb +72 -0
  136. data/spec/route_extensions_spec.rb +51 -0
  137. data/spec/saucy_spec.rb +62 -0
  138. data/spec/scaffold/config/routes.rb +5 -0
  139. data/spec/spec_helper.rb +39 -0
  140. data/spec/support/authentication_helpers.rb +81 -0
  141. data/spec/support/authorization_helpers.rb +56 -0
  142. data/spec/support/braintree.rb +7 -0
  143. data/spec/support/clearance_matchers.rb +55 -0
  144. data/spec/support/notifications.rb +57 -0
  145. data/spec/views/accounts/_account.html.erb_spec.rb +37 -0
  146. metadata +325 -0
@@ -0,0 +1,33 @@
1
+ Feature: user adds a new account
2
+
3
+ Background:
4
+ Given a plan exists with a name of "Free"
5
+
6
+ Scenario: existing user adds an account
7
+ Given I am signed up as "user@example.com/test"
8
+ When I go to the sign up page for the "Free" plan
9
+ And I fill in "Email" with "user@example.com"
10
+ And I fill in "Password" with "test"
11
+ And I press "Sign up"
12
+ Then I should see "created"
13
+ But I should not see "Instructions for confirming"
14
+ And I should be on the new project page for the newest account by "user@example.com"
15
+
16
+ Scenario: sign up for two accounts
17
+ When I go to the sign up page for the "Free" plan
18
+ And I fill in "Email" with "email@person.com"
19
+ And I fill in "Password" with "password"
20
+ And I press "Sign up"
21
+ Then I should see "created"
22
+ And I should be on the new project page for the newest account by "email@person.com"
23
+ When I go to the settings page
24
+ Then I should see 1 account
25
+ And I follow "Add new account"
26
+ And I follow "Free"
27
+ Then I should see "Your existing user, email, will be added as the first administrator on this new account."
28
+ And I press "Sign up"
29
+ Then I should see "created"
30
+ But I should not see "Instructions for confirming"
31
+ And I should be on the new project page for the newest account by "email@person.com"
32
+ When I go to the settings page
33
+ Then I should see 2 accounts
@@ -0,0 +1,77 @@
1
+ Feature: Project Dropdown
2
+ As a user
3
+ So that I can work on several projects
4
+ I can easily switch between projects
5
+
6
+ Background:
7
+ Given I am signed in as "user@example.com" under the "Werther's" account
8
+ And the following projects exist:
9
+ | name | account |
10
+ | Pacelog | name: Werther's |
11
+ | Narrator | name: Werther's |
12
+ | Flapper | name: Werther's |
13
+ And "user@example.com" is a member of the "Pacelog" project
14
+
15
+ @javascript
16
+ Scenario: Navigate from one project to another
17
+ Given "user@example.com" is a member of the "Narrator" project
18
+ When I go to the "Pacelog" project page
19
+ Then the page should not include "#project-selection ul.expanded"
20
+ When I click "#project-selection h1 a img"
21
+ Then the page should include "#project-selection ul.expanded"
22
+ And I should not see "Flapper"
23
+ When I follow "Narrator" within "#project-selection ul"
24
+ Then I should be on the "Narrator" project page
25
+
26
+ @javascript
27
+ Scenario: Click outside the projects dropdown to hide it
28
+ Given "user@example.com" is a member of the "Narrator" project
29
+ When I go to the "Narrator" project page
30
+ Then the page should not include "#project-selection ul.expanded"
31
+ When I click "#project-selection h1 a img"
32
+ Then the page should include "#project-selection ul.expanded"
33
+ When I click "body"
34
+ Then the page should not include "#project-selection ul.expanded"
35
+
36
+ Scenario: On project pages, the project name is rendered in the header
37
+ When I go to the "Pacelog" project page
38
+ Then I should see "Pacelog" within "#project-selection h1 a"
39
+
40
+ Scenario: On project pages with multiple projects, the project name and chooser are rendered in the header
41
+ Given "user@example.com" is a member of the "Narrator" project
42
+ When I go to the "Pacelog" project page
43
+ Then I should see "Pacelog" within "#project-selection h1 a"
44
+ And the page should include "#project-selection h1 a img"
45
+
46
+ Scenario: On non-project pages, the account name is rendered in the header with the project chooser
47
+ Given "user@example.com" is an admin of the "Narrator" project
48
+ When I am on the memberships page for the "Werther's" account
49
+ Then I should see "Projects" within "#project-selection h1 a"
50
+ And the page should include "#project-selection h1 a img"
51
+
52
+ When I am on the edit profile page
53
+ Then I should see "Projects" within "#project-selection h1 a"
54
+ And the page should include "#project-selection h1 a img"
55
+
56
+ Scenario: An admin on non-project pages, the new project link goes to the new project page for the right account
57
+ Given "user@example.com" is an admin of the "Narrator" project
58
+ When I am on the edit profile page
59
+ Then I should see "Create a new project" within "#project-selection"
60
+ When I follow "Create a new project"
61
+ Then I should be on the new project page for the "Werther's" account
62
+
63
+ Scenario: An admin on project pages, the new project link goes to the new project page for the right account
64
+ Given "user@example.com" is an admin of the "Narrator" project
65
+ When I go to the "Pacelog" project page
66
+ Then I should see "Create a new project" within "#project-selection"
67
+ When I follow "Create a new project"
68
+ Then I should be on the new project page for the "Werther's" account
69
+
70
+ Scenario: A non-admin on non-project pages, should not see the new project link
71
+ Given "user@example.com" is a member of the "Narrator" project
72
+ When I am on the edit profile page
73
+ Then I should not see "Create a new project" within "#project-selection"
74
+
75
+ Scenario: A non-admin on project pages, should not see the new project link
76
+ When I go to the "Pacelog" project page
77
+ Then I should not see "Create a new project" within "#project-selection"
@@ -0,0 +1,32 @@
1
+ Feature: Sign up
2
+ In order to get access to protected sections of the site
3
+ A user
4
+ Should be able to sign up
5
+
6
+ Background:
7
+ Given a plan exists with a name of "Free"
8
+
9
+ Scenario: User sees signup terms
10
+ When I go to the plans page
11
+ Then I should see "Free"
12
+ And I should see "Upgrade or Downgrade Anytime"
13
+ And I there should be a link to the help site
14
+ When I follow "Free"
15
+ Then I should see "By clicking Sign up you agree to our Terms of Service"
16
+
17
+ Scenario: User signs up with invalid data
18
+ When I go to the sign up page for the "Free" plan
19
+ Then I should see "Free"
20
+ And I fill in "Email" with "invalidemail"
21
+ And I fill in "Password" with "password"
22
+ And I should not see "Billing Information"
23
+ And I press "Sign up"
24
+ Then the form should have inline error messages
25
+
26
+ Scenario: User signs up with valid data
27
+ When I go to the list of plans page
28
+ And I follow "Free"
29
+ And I fill in "Email" with "email@person.com"
30
+ And I fill in "Password" with "password"
31
+ And I press "Sign up"
32
+ Then I should see "created"
@@ -0,0 +1,65 @@
1
+ Feature: Sign up
2
+ In order to get access to protected sections of the site
3
+ A user
4
+ Should be able to sign up
5
+
6
+ Background:
7
+ Given a paid plan exists with a name of "Paid"
8
+ And a plan exists with a name of "Free"
9
+
10
+ Scenario: User signs up for a paid plan with invalid data
11
+ When I go to the sign up page for the "Paid" plan
12
+ Then I should see "Paid"
13
+ And I should see "$1/month"
14
+ And the "Card number" field should have autocomplete off
15
+ And the "Verification code" field should have autocomplete off
16
+ And I fill in "Email" with "invalidemail"
17
+ And I fill in "Password" with "password"
18
+ And I should see "Billing Information"
19
+ And I press "Sign up"
20
+ Then the form should have inline error messages
21
+
22
+ Scenario: User signs up for a paid plan with valid data
23
+ When I go to the list of plans page
24
+ Then I should see the "Paid" plan before the "Free" plan
25
+ When I follow "Paid"
26
+ And I fill in "Email" with "email@person.com"
27
+ And I fill in "Password" with "password"
28
+ And I fill in "Cardholder name" with "Ralph Robot"
29
+ And I fill in "Billing email" with "accounting@example.com"
30
+ And I fill in "Card number" with "4111111111111111"
31
+ And I fill in "Verification code" with "123"
32
+ And I select "March" from "Expiration month"
33
+ And I select "2020" from "Expiration year"
34
+ And I press "Sign up"
35
+ Then I should see "created"
36
+
37
+ Scenario: User signs up for a paid plan with an invalid credit card number
38
+ Given that the credit card "4111112" is invalid
39
+ When I go to the list of plans page
40
+ And I follow "Paid"
41
+ And I fill in "Email" with "email@person.com"
42
+ And I fill in "Password" with "password"
43
+ And I fill in "Cardholder name" with "Ralph Robot"
44
+ And I fill in "Billing email" with "accounting@example.com"
45
+ And I fill in "Card number" with "4111112"
46
+ And I fill in "Verification code" with "123"
47
+ And I select "March" from "Expiration month"
48
+ And I select "2020" from "Expiration year"
49
+ And I press "Sign up"
50
+ Then "Card number" should have the error "is invalid"
51
+
52
+ Scenario: User signs up for a paid plan with a credit card that cannot be processed
53
+ Given that the credit card "4111111111111111" should not be honored
54
+ When I go to the list of plans page
55
+ And I follow "Paid"
56
+ And I fill in "Email" with "email@person.com"
57
+ And I fill in "Password" with "password"
58
+ And I fill in "Cardholder name" with "Ralph Robot"
59
+ And I fill in "Billing email" with "accounting@example.com"
60
+ And I fill in "Card number" with "4111111111111111"
61
+ And I fill in "Verification code" with "123"
62
+ And I select "March" from "Expiration month"
63
+ And I select "2020" from "Expiration year"
64
+ And I press "Sign up"
65
+ Then "Card number" should have the error "Do Not Honor"
@@ -0,0 +1,82 @@
1
+ Feature: Trial plans
2
+
3
+ Background:
4
+ Given the following plan exists:
5
+ | name | price | trial |
6
+ | Temp | 0 | true |
7
+ | Eternal | 0 | false |
8
+ And the following limits exist:
9
+ | plan | name | value | value_type |
10
+ | name: Temp | users | 2 | number |
11
+ | name: Eternal | users | 2 | number |
12
+
13
+ Scenario: Sign up for a trial plan
14
+ When I go to the list of plans page
15
+ And I follow "Temp"
16
+ Then I should see "Free"
17
+ And I should see "Trial"
18
+ And I should see "Your trial will expire after 30 days"
19
+ But I should not see "users"
20
+ When I fill in "Email" with "email@person.com"
21
+ And I fill in "Password" with "password"
22
+ And I press "Sign up"
23
+ Then I should see "created"
24
+
25
+ Scenario: use an account during the trial
26
+ Given a "Temp" account exists with a name of "Test" created 29 days ago
27
+ And I am signed in as an admin of the "Test" account
28
+ When I go to the projects page for the "Test" account
29
+ Then I should see "Test"
30
+ And I should not see "expired"
31
+
32
+ Scenario: Try to use an expired trial plan
33
+ Given a "Temp" account exists with a name of "Test" created 30 days ago
34
+ And I am signed in as an admin of the "Test" account
35
+ When I go to the projects page for the "Test" account
36
+ Then I should be on the upgrade plan page for the "Test" account
37
+ And I should see "expired"
38
+ And the "Temp" plan should be disabled
39
+
40
+ Scenario: Sign up for a non-trial plan
41
+ When I go to the list of plans page
42
+ And I follow "Eternal"
43
+ Then I should see "users"
44
+ But I should not see "Trial"
45
+ And I should not see "expire"
46
+
47
+ Scenario: Use a non-trial plan forever
48
+ Given an "Eternal" account exists with a name of "Test" created 30 days ago
49
+ And I am signed in as an admin of the "Test" account
50
+ When I go to the projects page for the "Test" account
51
+ Then I should see "Test"
52
+ And I should not see "expired"
53
+
54
+ Scenario: Receive a reminder about an expiring trial plan
55
+ Given a "Temp" account exists with a name of "Test" created 23 days ago
56
+ And a user exists with an email of "admin@example.com"
57
+ And "admin@example.com" is an admin of the "Test" account
58
+ When the daily Saucy jobs are processed
59
+ And I sign in as "admin@example.com"
60
+ And I follow the link sent to "admin@example.com" with subject "Your trial is expiring soon"
61
+ Then I should be on the upgrade plan page for the "Test" account
62
+
63
+ Scenario: Receive a reminder about activating an account
64
+ Given an account exists with a name of "Test"
65
+ And a user exists with an email of "admin@example.com"
66
+ And "admin@example.com" is an admin of the "Test" account
67
+ And the "Test" account was created 7 days ago
68
+ When the daily Saucy jobs are processed
69
+ Then an email with subject "A check in" should be sent to "admin@example.com"
70
+ When I sign in as "admin@example.com/password"
71
+ And I follow the link sent to "admin@example.com" with subject "A check in"
72
+ Then I should be on the new project page for the newest account by "admin@example.com"
73
+
74
+ Scenario: Receive a reminder about an expired trial plan
75
+ Given a "Temp" account exists with a name of "Test" created 30 days ago
76
+ And a user exists with an email of "admin@example.com"
77
+ And "admin@example.com" is an admin of the "Test" account
78
+ When the daily Saucy jobs are processed
79
+ And I sign in as "admin@example.com"
80
+ And I follow the link sent to "admin@example.com" with subject "Your trial has ended"
81
+ Then I should be on the upgrade plan page for the "Test" account
82
+
@@ -0,0 +1,30 @@
1
+ Given /^an? "([^"]+)" account exists with a name of "([^"]*)" created (\d+) days ago$/ do |plan_name, account_name, days|
2
+ plan = Plan.find_by_name!(plan_name)
3
+ Factory(:account, :created_at => days.to_i.days.ago, :plan => plan, :name => account_name)
4
+ end
5
+
6
+ Given /^the "([^"]*)" account was created (\d+) days ago$/ do |account_name, days|
7
+ Account.find_by_name!(account_name).tap do |account|
8
+ account.created_at = days.to_i.days.ago
9
+ account.save!
10
+ end
11
+ end
12
+
13
+ Given /^the following limit exists for the "([^"]*)" account:$/ do |account_name, table|
14
+ Account.find_by_name!(account_name).tap do |account|
15
+ table.hashes.each do |limit|
16
+ account.plan.limits.create!(limit)
17
+ end
18
+ end
19
+ end
20
+
21
+ When /^I follow "([^"]*)" for the "([^"]*)" account$/ do |link_text, account_name|
22
+ account = Account.find_by_name!(account_name)
23
+ within "##{dom_id(account)}" do
24
+ click_link link_text
25
+ end
26
+ end
27
+
28
+ Then /^I should see (\d+) accounts?$/ do |count|
29
+ page.all("#user_accounts li").size.should == count.to_i
30
+ end
@@ -0,0 +1,25 @@
1
+ Given /^that the credit card "([^"]*)" is invalid$/ do |number|
2
+ FakeBraintree.failures[number] = { "message" => "Credit card number is invalid.", "errors" => { "customer" => { "errors" => [], "credit-card" => { "errors" => [{ "message" => "Credit card number is invalid.", "code" => 81715, "attribute" => :number }] }}}}
3
+ end
4
+
5
+ Given /^that the credit card "([^"]*)" should not be honored$/ do |number|
6
+ FakeBraintree.failures[number] = { "message" => "Do Not Honor", "code" => "2000", "status" => "processor_declined" }
7
+ end
8
+
9
+ Given /^the "([^"]*)" account is past due$/ do |account_name|
10
+ account = Account.find_by_name!(account_name)
11
+ account.update_attribute(:subscription_status, Braintree::Subscription::Status::PastDue)
12
+ end
13
+
14
+ Given /^the following transaction exist for the "([^"]*)" account:$/ do |account_name, table|
15
+ account = Account.find_by_name!(account_name)
16
+ subscription = FakeBraintree.subscriptions[account.subscription_token]
17
+ subscription["transactions"] = []
18
+ table.hashes.each do |transaction|
19
+ FakeBraintree.transaction = { :status => transaction["status"],
20
+ :amount => transaction["amount"],
21
+ :created_at => Time.parse(transaction["created_at"]),
22
+ :subscription_id => account.subscription_token }
23
+ subscription["transactions"] << FakeBraintree.generated_transaction
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+
3
+ module RakeHelpers
4
+ def fake_rake
5
+ old_rake = Rake.application
6
+ rake = Rake::Application.new
7
+ Rake.application = rake
8
+ task :environment
9
+ yield(rake)
10
+ ensure
11
+ Rake.application = old_rake
12
+ end
13
+ end
14
+
15
+ World(RakeHelpers)
16
+
17
+ When /^the daily Saucy jobs are processed$/ do
18
+ fake_rake do |rake|
19
+ Saucy::Engine.new.load_tasks
20
+ rake['saucy:daily'].invoke
21
+ end
22
+ end
23
+
@@ -0,0 +1,40 @@
1
+ When /^I follow the link sent to "([^"]+)"$/ do |email_address|
2
+ email = ActionMailer::Base.deliveries.detect do |tmail|
3
+ tmail.to.include?(email_address)
4
+ end or raise "No email sent to #{email_address}"
5
+
6
+ unless match = email.body.match(%r{http://\S+})
7
+ raise "No link included in the email:\n#{email.body}"
8
+ end
9
+ url = match[0]
10
+
11
+ visit url
12
+ end
13
+
14
+ When /^I follow the link sent to "([^"]+)" with subject "([^"]+)"$/ do |email_address, subject|
15
+ to_address = ActionMailer::Base.deliveries.select do |tmail|
16
+ tmail.to.include?(email_address)
17
+ end or raise "No email sent to #{email_address}"
18
+
19
+ email = to_address.detect do |tmail|
20
+ tmail.subject.include?(subject)
21
+ end or raise "No email sent to #{email_address} with subject #{subject}"
22
+
23
+ unless match = email.body.match(%r{http://\S+})
24
+ raise "No link included in the email:\n#{email.body}"
25
+ end
26
+ url = match[0]
27
+
28
+ visit url
29
+ end
30
+
31
+ Then /^an email with subject "([^"]*)" should be sent to "([^"]*)"$/ do |subject, to_address|
32
+ email = ActionMailer::Base.deliveries.detect do |tmail|
33
+ tmail.subject.include?(subject)
34
+ end or raise "No email with subject #{subject}"
35
+
36
+ unless email.to.include?(to_address)
37
+ raise "No email sent to #{to_address}"
38
+ end
39
+ end
40
+
@@ -0,0 +1 @@
1
+ require 'factory_girl/step_definitions'
@@ -0,0 +1,51 @@
1
+ Then /^the form should have inline error messages$/ do
2
+ page.should have_css(".error")
3
+ end
4
+
5
+ When /^the "([^"]*)" field should have autocomplete off$/ do |field|
6
+ field = page.find_field(field)
7
+ field["autocomplete"].should == "off"
8
+ end
9
+
10
+ Then /^"([^"]*)" should have the error "([^"]*)"$/ do |field, error|
11
+ field = page.find_field(field)
12
+ field.find(:xpath, "following-sibling::p[@class='inline-errors'][contains(text(), '#{error}')]").should_not be_nil
13
+ end
14
+
15
+ Then /^the "([^"]*)" field(?: within "([^"]*)")? should have nothing in it$/ do |field, selector|
16
+ with_scope(selector) do
17
+ field = find_field(field)
18
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
19
+ if field_value.respond_to? :should
20
+ field_value.should be_nil
21
+ else
22
+ assert_nil(field_value)
23
+ end
24
+ end
25
+ end
26
+
27
+ Then /^I there should be a link to the help site$/ do
28
+ page.should have_css("a[href*='help.example.com']")
29
+ end
30
+
31
+ Then /^"([^"]*)" should not be expanded$/ do |selector|
32
+ page.has_css?("#{selector}")
33
+ page.has_no_css?("#{selector}.expanded")
34
+ end
35
+
36
+ Then /^"([^"]*)" should be expanded/ do |selector|
37
+ page.has_css?("#{selector}")
38
+ page.has_css?("#{selector}.expanded")
39
+ end
40
+
41
+ When %r{^I click "([^"]*)"$} do |selector|
42
+ find(selector).click
43
+ end
44
+
45
+ Then /^the page should (not )?include "([^"]*)"$/ do |should_not_contain, selector|
46
+ if should_not_contain.present?
47
+ page.should have_no_css(selector)
48
+ else
49
+ page.should have_css(selector)
50
+ end
51
+ end