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.
- data/CHANGELOG.md +114 -0
- data/Gemfile +26 -0
- data/README.md +118 -0
- data/Rakefile +38 -0
- data/app/controllers/accounts_controller.rb +68 -0
- data/app/controllers/billings_controller.rb +25 -0
- data/app/controllers/invitations_controller.rb +65 -0
- data/app/controllers/memberships_controller.rb +45 -0
- data/app/controllers/plans_controller.rb +24 -0
- data/app/controllers/profiles_controller.rb +19 -0
- data/app/helpers/limits_helper.rb +13 -0
- data/app/mailers/billing_mailer.rb +53 -0
- data/app/mailers/invitation_mailer.rb +18 -0
- data/app/models/invitation.rb +113 -0
- data/app/models/limit.rb +49 -0
- data/app/models/membership.rb +26 -0
- data/app/models/permission.rb +19 -0
- data/app/models/signup.rb +163 -0
- data/app/views/accounts/_account.html.erb +9 -0
- data/app/views/accounts/_blank_slate.html.erb +6 -0
- data/app/views/accounts/_projects.html.erb +12 -0
- data/app/views/accounts/_subnav.html.erb +10 -0
- data/app/views/accounts/edit.html.erb +34 -0
- data/app/views/accounts/index.html.erb +9 -0
- data/app/views/accounts/new.html.erb +36 -0
- data/app/views/billing_mailer/completed_trial.text.erb +13 -0
- data/app/views/billing_mailer/expiring_trial.text.erb +15 -0
- data/app/views/billing_mailer/new_unactivated.text.erb +1 -0
- data/app/views/billing_mailer/problem.html.erb +13 -0
- data/app/views/billing_mailer/problem.text.erb +14 -0
- data/app/views/billing_mailer/receipt.html.erb +41 -0
- data/app/views/billing_mailer/receipt.text.erb +25 -0
- data/app/views/billings/_form.html.erb +8 -0
- data/app/views/billings/edit.html.erb +13 -0
- data/app/views/billings/show.html.erb +29 -0
- data/app/views/invitation_mailer/invitation.text.erb +6 -0
- data/app/views/invitations/new.html.erb +17 -0
- data/app/views/invitations/show.html.erb +22 -0
- data/app/views/layouts/saucy.html.erb +36 -0
- data/app/views/limits/_meter.html.erb +13 -0
- data/app/views/memberships/edit.html.erb +21 -0
- data/app/views/memberships/index.html.erb +17 -0
- data/app/views/plans/_plan.html.erb +32 -0
- data/app/views/plans/_terms.html.erb +15 -0
- data/app/views/plans/edit.html.erb +33 -0
- data/app/views/plans/index.html.erb +12 -0
- data/app/views/profiles/_inputs.html.erb +5 -0
- data/app/views/profiles/edit.html.erb +36 -0
- data/app/views/projects/_form.html.erb +36 -0
- data/app/views/projects/edit.html.erb +22 -0
- data/app/views/projects/index.html.erb +28 -0
- data/app/views/projects/new.html.erb +13 -0
- data/app/views/projects/show.html.erb +0 -0
- data/app/views/shared/_project_dropdown.html.erb +55 -0
- data/app/views/shared/_saucy_javascript.html.erb +33 -0
- data/config/locales/en.yml +37 -0
- data/config/routes.rb +19 -0
- data/features/run_features.feature +83 -0
- data/features/step_definitions/clearance_steps.rb +45 -0
- data/features/step_definitions/rails_steps.rb +73 -0
- data/features/step_definitions/saucy_steps.rb +8 -0
- data/features/support/env.rb +4 -0
- data/features/support/file.rb +11 -0
- data/lib/generators/saucy/base.rb +18 -0
- data/lib/generators/saucy/features/features_generator.rb +91 -0
- data/lib/generators/saucy/features/templates/README +3 -0
- data/lib/generators/saucy/features/templates/factories.rb +71 -0
- data/lib/generators/saucy/features/templates/features/edit_profile.feature +9 -0
- data/lib/generators/saucy/features/templates/features/edit_project_permissions.feature +37 -0
- data/lib/generators/saucy/features/templates/features/edit_user_permissions.feature +47 -0
- data/lib/generators/saucy/features/templates/features/manage_account.feature +35 -0
- data/lib/generators/saucy/features/templates/features/manage_billing.feature +93 -0
- data/lib/generators/saucy/features/templates/features/manage_plan.feature +143 -0
- data/lib/generators/saucy/features/templates/features/manage_projects.feature +139 -0
- data/lib/generators/saucy/features/templates/features/manage_users.feature +142 -0
- data/lib/generators/saucy/features/templates/features/new_account.feature +33 -0
- data/lib/generators/saucy/features/templates/features/project_dropdown.feature +77 -0
- data/lib/generators/saucy/features/templates/features/sign_up.feature +32 -0
- data/lib/generators/saucy/features/templates/features/sign_up_paid.feature +65 -0
- data/lib/generators/saucy/features/templates/features/trial_plans.feature +82 -0
- data/lib/generators/saucy/features/templates/step_definitions/account_steps.rb +30 -0
- data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +25 -0
- data/lib/generators/saucy/features/templates/step_definitions/cron_steps.rb +23 -0
- data/lib/generators/saucy/features/templates/step_definitions/email_steps.rb +40 -0
- data/lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb +1 -0
- data/lib/generators/saucy/features/templates/step_definitions/html_steps.rb +51 -0
- data/lib/generators/saucy/features/templates/step_definitions/plan_steps.rb +16 -0
- data/lib/generators/saucy/features/templates/step_definitions/project_steps.rb +4 -0
- data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +37 -0
- data/lib/generators/saucy/features/templates/step_definitions/user_steps.rb +100 -0
- data/lib/generators/saucy/features/templates/support/braintree.rb +5 -0
- data/lib/generators/saucy/install/install_generator.rb +40 -0
- data/lib/generators/saucy/install/templates/controllers/projects_controller.rb +3 -0
- data/lib/generators/saucy/install/templates/create_saucy_tables.rb +115 -0
- data/lib/generators/saucy/install/templates/models/account.rb +3 -0
- data/lib/generators/saucy/install/templates/models/plan.rb +3 -0
- data/lib/generators/saucy/install/templates/models/project.rb +3 -0
- data/lib/generators/saucy/specs/specs_generator.rb +20 -0
- data/lib/generators/saucy/specs/templates/support/braintree.rb +5 -0
- data/lib/generators/saucy/views/views_generator.rb +23 -0
- data/lib/saucy.rb +10 -0
- data/lib/saucy/account.rb +132 -0
- data/lib/saucy/account_authorization.rb +67 -0
- data/lib/saucy/configuration.rb +29 -0
- data/lib/saucy/engine.rb +35 -0
- data/lib/saucy/fake_braintree.rb +134 -0
- data/lib/saucy/layouts.rb +36 -0
- data/lib/saucy/plan.rb +54 -0
- data/lib/saucy/project.rb +125 -0
- data/lib/saucy/projects_controller.rb +94 -0
- data/lib/saucy/railties/tasks.rake +28 -0
- data/lib/saucy/routing_extensions.rb +121 -0
- data/lib/saucy/subscription.rb +237 -0
- data/lib/saucy/user.rb +30 -0
- data/spec/controllers/accounts_controller_spec.rb +228 -0
- data/spec/controllers/application_controller_spec.rb +32 -0
- data/spec/controllers/invitations_controller_spec.rb +215 -0
- data/spec/controllers/memberships_controller_spec.rb +117 -0
- data/spec/controllers/plans_controller_spec.rb +13 -0
- data/spec/controllers/profiles_controller_spec.rb +48 -0
- data/spec/controllers/projects_controller_spec.rb +216 -0
- data/spec/environment.rb +95 -0
- data/spec/layouts_spec.rb +21 -0
- data/spec/mailers/billing_mailer_spec.rb +68 -0
- data/spec/mailers/invitiation_mailer_spec.rb +19 -0
- data/spec/models/account_spec.rb +218 -0
- data/spec/models/invitation_spec.rb +320 -0
- data/spec/models/limit_spec.rb +70 -0
- data/spec/models/membership_spec.rb +37 -0
- data/spec/models/permission_spec.rb +30 -0
- data/spec/models/plan_spec.rb +81 -0
- data/spec/models/project_spec.rb +223 -0
- data/spec/models/signup_spec.rb +177 -0
- data/spec/models/subscription_spec.rb +481 -0
- data/spec/models/user_spec.rb +72 -0
- data/spec/route_extensions_spec.rb +51 -0
- data/spec/saucy_spec.rb +62 -0
- data/spec/scaffold/config/routes.rb +5 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/authentication_helpers.rb +81 -0
- data/spec/support/authorization_helpers.rb +56 -0
- data/spec/support/braintree.rb +7 -0
- data/spec/support/clearance_matchers.rb +55 -0
- data/spec/support/notifications.rb +57 -0
- data/spec/views/accounts/_account.html.erb_spec.rb +37 -0
- 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
|