Remove membership and stripe subscription routes (#2741)

This commit is contained in:
Andy Zhao 2019-05-07 11:37:21 -04:00 committed by Mac Siri
parent 515d2fb61e
commit 97040ab603
10 changed files with 3 additions and 732 deletions

View file

@ -1,6 +1,6 @@
class PagesController < ApplicationController
# No authorization required for entirely public controller
before_action :set_cache_control_headers, only: %i[show rlyweb now membership survey badge shecoded]
before_action :set_cache_control_headers, only: %i[show rlyweb now survey badge shecoded]
def show
@page = Page.find_by!(slug: params[:slug])
@ -27,17 +27,6 @@ class PagesController < ApplicationController
set_surrogate_key_header "badge_page"
end
def membership
flash[:notice] = ""
flash[:error] = ""
@members = members_for_display
set_surrogate_key_header "membership_page"
end
def membership_form
render "membership_form", layout: false
end
def report_abuse
reported_url = params[:reported_url] || params[:url] || request.referer
@feedback_message = FeedbackMessage.new(

View file

@ -1,17 +0,0 @@
<% cache("wall-of-patrons", expires_in: 3.hours) do %>
<style>
.wall-container {
width: 94%;
max-width: 750px;
margin: auto;
}
</style>
<div class="wall-container" style="text-align:center;">
<h1> Wall of Patrons and Scholars</h1>
<% @members.each do |member| %>
<a href="/<%= member.username %>"><img style="width:70px; margin:5px; border-radius:100%;" src="<%= ProfileImage.new(member).get %>" alt="" class="featured-profile-pic"></a>
<% end %>
<p><em>Thank you for being a dev.to sustaining member!</em></p>
</div>
<% end %>

View file

@ -1,374 +0,0 @@
<% title "The DEV Sustaining Membership" %>
<%= content_for :page_meta do %>
<link rel="canonical" href="https://dev.to/membership" />
<meta name="description" content="dev.to | Membership">
<meta name="keywords" content="software development,engineering,rails,javascript,ruby">
<meta property="og:type" content="article" />
<meta property="og:url" content="https://dev.to/membership" />
<meta property="og:title" content="The DEV Sustaining Membership" />
<meta property="og:image" content="https://thepracticaldev.s3.amazonaws.com/i/jlaubn65o81m46jkg5k6.png" />
<meta property="og:description" content="Support the DEV Community and get access to exclusive events and features" />
<meta property="og:site_name" content="The Practical Dev" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@ThePracticalDev">
<meta name="twitter:title" content="The DEV Sustaining Membership">
<meta property="og:description" content="Support the DEV Community and get access to exclusive events and features" />
<meta name="twitter:image:src" content="https://thepracticaldev.s3.amazonaws.com/i/jlaubn65o81m46jkg5k6.png">
<% end %>
<div class="blank-space"></div>
<style>
body {
background: #f2f3ff;
}
.container .body p {
margin: 1.2em 0 1.50em;
}
.container .body h1 {
margin: 1.3em 0 1.50em;
}
.body .cta {
font-size: 1.5em;
border: 4px solid #3bccbb;
border-radius: 3px;
vertical-align: 2px;
padding: 8px 12px;
}
.levels-wrapper {
position: relative;
margin: calc(2vw + 10px) auto;
}
.membership-levels {
width: 86%;
max-width: 500px;
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 0.9em;
margin: auto;
}
.single-membership-level {
border: 2px solid #918ffa;
margin-bottom: 15px;
border-radius: 3px;
box-shadow: 5px 8px 0px #d7d9f8;
}
.single-level-header {
background: #557de8;
color: white;
padding: 5px;
text-align: center;
font-weight: 500;
}
.container .body .single-level-header img {
width: 20px;
height: 20px;
display: inline-block;
left: auto;
vertical-align: -4px;
}
.single-level-body {
padding: 15px;
}
.single-level-body .img-wrapper {
text-align: center;
}
.container .body .single-level-body img {
width: 80px;
height: 80px;
display: inline-block;
left: auto;
}
.enroll-form {
margin-top: 10px;
padding: 150px 0px;
text-align: center;
width: calc(100% + 159px);
margin-left: -79px;
margin-bottom: -102px;
font-size: 22px;
background: #ccfff9 url(<%= asset_path "triple-unicorn.png" %>) no-repeat center center;
}
.user-amount-wrapper {
position: relative;
width: 300px;
max-width: 25%;
margin: 0px auto;
display: inline-block;
}
.stripe-button-wrapper {
display: inline-block;
vertical-align: -7px;
}
.amount-input {
width: calc(100% - 85px);
max-width: 130px;
padding: 18px;
font-size: 20px;
padding-left: 80px;
border: 1px solid #3bccbb;
}
.amount-currency-indicator {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 60px;
text-align: center;
padding-top: 15px;
padding-left: 2px;
border-right: 1px solid #3bccbb;
color: #1faf9f;
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}
input[type=number]::-webkit-inner-spin-button {
display: none;
}
.credit-card-button {
margin-left: 15px;
}
.signin-container {
padding-top: 150px;
text-align: center;
}
.signin-container .cta {
margin: 15px 10px 0px;
display: inline-block;
min-width: 150px;
}
#notice {
text-align: center;
color: red;
padding: 5px;
}
</style>
<div class="container article">
<div class="title" style="height:30px;">
<% if flash[:error].present? %>
<div class="notice error-notice" id="notice">
ERROR: <%= sanitize(flash[:error]) %>
</div>
<% end %>
</div>
<div class="body">
<% cache("membership-shared-area", expires_in: 1.hour) do %>
<img src="<%= asset_path "sustaining-membership.svg" %>" style="height:180px;margin-top:30px;" />
<h1 style="font-size:1.9em;font-weight:600;text-align:center;">
The DEV Community<br>Sustaining Membership
</h1>
<p>
Our community is special because of each and every one of you. <br>
</p>
<p>
By contributing at
<b>any level</b>, your support will help us continue our work of building a community that is open, kind, and constructive for programmers everywhere.
</p>
<p>
Weve put together some goodies that are described below and well be expanding these perks over time, so you can expect even more in the long run.
</p>
<p>
Thanks for (at least thinking about) becoming a dev.to sustaining member. The fact that youre reading this means a lot to us.
</p>
<div class="levels-wrapper">
<div class="membership-levels">
<div class="single-membership-level">
<div class="single-level-header">Level 1</div>
<div class="single-level-body">
Your support is appreciated. For <span style="background-color:#fefa87">$1 a month</span>, you'll get:
<ul>
<li><strong>Access to beta features</strong></li>
<li> Added to our "Wall of Patrons and Scholars" with a link to your profile</strong> </li>
</ul>
<div class="img-wrapper">
<img src="<%= asset_path "emoji-apple-hands.png" %>" />
</div>
</div>
</div>
<div class="single-membership-level">
<div class="single-level-header">Level 2</div>
<div class="single-level-body">
Double digits! For <span style="background-color:#fefa87">$10 a month</span>, you'll get:
<ul>
<li><strong>An exclusive sticker pack mailed to your door</strong></li>
<li>25% off <a href="https://shop.dev.to">The DEV Shop</a> (forever!)</li>
<li><strong>Added to our "Wall of Patrons and Scholars" with a link to your profile</strong></li>
<li> Access to beta features</li>
</ul>
<div class="img-wrapper">
<img src="<%= asset_path "emoji-apple-shopping-bags.png" %>" />
</div>
</div>
</div>
<div class="single-membership-level">
<div class="single-level-header">Level 3</div>
<div class="single-level-body">
Woohooo! For <span style="background-color:#fefa87">$25 a month</span>, you'll get:
<ul>
<li><strong>Stickers + t-shirt combo pack </strong></li>
<li>25% off <a href="https://shop.dev.to">The DEV Shop</a> (forever!)</li>
<li> Added to our "Wall of Patrons and Scholars" with a link to your profile</li>
<li> Access to beta features</li>
</ul>
<div class="img-wrapper">
<img src="<%= asset_path "emoji-apple-backpack.png" %>" />
</div>
</div>
</div>
<div class="single-membership-level">
<div class="single-level-header">Level 4</div>
<div class="single-level-body">
When you contribute
<span style="background-color:#fefa87"> over $25 a month</span>, your additional support goes toward our diversity/need-based scholarship fund, providing workshop passes to members who cannot afford it. Plus, all the perks from above.
<div class="img-wrapper">
<img src="<%= asset_path "emoji-apple-revolving-hearts.png" %>" />
</div>
</div>
</div>
<div class="single-membership-level">
<div class="single-level-header">Level Triple-Unicorn
</div>
<div class="single-level-body">
For
<span style="background-color:#fefa87">$1000 a month</span>, your name will get the featured position on the Wall of Patrons and Scholars, everything described above, monthly private conversations with the DEV leadership, and an actual unicorn. Provided we can find one.
<div class="img-wrapper">
<img src="<%= asset_path "emoji-apple-unicorn.png" %>" />
<img src="<%= asset_path "emoji-apple-unicorn.png" %>" />
<img src="<%= asset_path "emoji-apple-unicorn.png" %>" />
</div>
</div>
</div>
<p><em>Perks will update according to your membership status and tier.</em></p>
</div>
</div>
<% end %>
<div class="notice error-notice" id="js-error" style="text-align:center;color:red">
</div>
<div id="membership-form-wrapper" style="height:364px;">
<!-- Form will render via JS here -->
</div>
</div>
<br>
<br>
<br>
<br>
<%= render partial: "wall_of_patrons" %>
<br>
</div>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
function initializeStripe() {
var form = document.getElementById("credit-card-form");
if (!form) {
return false;
}
form.addEventListener('submit', function (e) {
e.preventDefault();
openStripeForm();
})
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
image: 'https://thepracticaldev.s3.amazonaws.com/i/xoxvppfjorrnxudkzskw.jpg',
locale: 'auto',
token: function (token) {
addHidden(form, 'stripe_token', token.id);
if (form.amount && form.stripe_token) {
form.submit();
} else {
document.getElementById('js-error').innerHTML = 'Oops, something went wrong. Please refresh the page or contact <a href="mailto:members@dev.to">contact us</a> to get this sorted out.'
return false;
}
}
});
document.getElementById('custom-stripe-button').addEventListener('click', function (e) {
e.preventDefault();
openStripeForm();
});
function openStripeForm() {
if (getAmount() < 100) {
document.getElementById('js-error').innerHTML = 'Amount has to be at least 1 dollar.';
return false;
} else {
document.getElementById('js-error').innerHTML = '';
addHidden(form, 'amount', document.getElementById('amount-input').value);
// Open Checkout with further options:
handler.open({
description: 'Add Credit Card',
amount: getAmount(),
email: document.getElementById("member-email-holder").dataset.email,
panelLabel: "Add Card",
allowRememberMe: false,
zipCode: true,
});
}
}
// Close Checkout on page navigation:
window.addEventListener('popstate', function () {
handler.close();
});
}
function getAmount() {
return document.getElementById('amount-input').value * 100;
}
function addHidden(theForm, key, value) {
// Create a hidden input element, and append it to the form:
var input = document.createElement('input');
input.type = 'hidden';
input.name = key; // 'the key/name of the attribute/field that is sent to the server
input.value = value;
theForm.appendChild(input);
}
var dataRequester;
if (window.XMLHttpRequest) {
dataRequester = new XMLHttpRequest();
} else {
dataRequester = new ActiveXObject('Microsoft.XMLHTTP');
}
dataRequester.onreadystatechange = function () {
if (dataRequester.readyState === XMLHttpRequest.DONE && dataRequester.status === 200) {
document.getElementById('membership-form-wrapper').innerHTML = dataRequester.response;
setTimeout(function () {
initializeStripe();
}, 250)
}
}
dataRequester.open('GET', '/p/membership_form', true);
dataRequester.send();
</script>

View file

@ -1,29 +0,0 @@
<% if user_signed_in? && current_user.monthly_dues == 0 %>
<div id="member-email-holder" data-email="<%= current_user.email %>"></div>
<%= form_tag "/membership-action", id: "credit-card-form", class: "enroll-form" do %>
<div class="user-amount-wrapper">
<%= number_field_tag :input_amount, 25, class: "amount-input", step: "any", min: "1", id: "amount-input" %>
<div class="amount-currency-indicator">$</div>
</div>
<div class="stripe-button-wrapper" id="stripe-button-wrapper">
<button id="custom-stripe-button" class="credit-card-button cta" type="button">ENROLL</button>
</div>
<% end %>
<% elsif user_signed_in? %>
<div class="signin-container">
<h2>Manage your membership <a href="/settings/membership">here</a> ✌️</h2>
</div>
<% else %>
<div class="signin-container">
<img style="width:30px; display:inline;" src="<%= asset_path("emoji/emoji-sparkling-heart.png") %>" />
<img style="width:30px; display:inline;" src="<%= asset_path("emoji/emoji-sparkling-heart.png") %>" />
<img style="width:30px; display:inline;" src="<%= asset_path("emoji/emoji-sparkling-heart.png") %>" />
<h2>Sign in to get your membership </h2>
<a href="/users/auth/twitter?callback_url=<%= ApplicationConfig["APP_PROTOCOL"] %><%= ApplicationConfig["APP_DOMAIN"] %>/users/auth/twitter/callback" class="cta cta-button" data-no-instant>
TWITTER
</a>
<a href="/users/auth/github?state=membership-cta" class="cta cta-button" data-no-instant>
GITHUB
</a>
</div>
<% end %>

View file

@ -1,66 +0,0 @@
<% title "DEV Scholarships" %>
<%= content_for :page_meta do %>
<link rel="canonical" href="https://dev.to/p/scholarships" />
<meta name="description" content="Scholarships for DEV workshops">
<meta name="keywords" content="software development,engineering,rails,javascript,ruby">
<meta property="og:type" content="article" />
<meta property="og:url" content="https://dev.to/p/scholarships" />
<meta property="og:title" content="Scholarships for DEV workshops" />
<meta property="og:image" content="https://thepracticaldev.s3.amazonaws.com/i/g355ol6qsrg0j2mhngz9.png" />
<meta property="og:description" content="Apply for scholarships to DEV workshops" />
<meta property="og:site_name" content="The DEV Community" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@ThePracticalDev">
<meta name="twitter:title" content="Scholarships for DEV workshops">
<meta name="twitter:description" content="Apply for scholarships to DEV workshops">
<meta name="twitter:image:src" content="https://thepracticaldev.s3.amazonaws.com/i/g355ol6qsrg0j2mhngz9.png">
<% end %>
<!-- <p id="notice"><%#= notice %></p> -->
<div class="blank-space"></div>
<div class="container article">
<div class="title" style="height:30px">
</div>
<h1 style="text-align:center">
The DEV Scholarship
</h1>
<div class="body">
<p>
This scholarship is for anyone interested in attending DEV workshops but does not have the means to be a level 3
<a href="/membership">sustaining member</a>.
</p>
<p>
Scholarship recipients will receive full access to all DEV workshops for one year. These workshops are taught by experts from the community and range from beginner to advanced topics.
<a href="/events">Check out our upcoming sessions</a>.
</p>
<% if current_user && current_user.scholar %>
<h4 style="text-align: center">
Congratulations on your DEV scholarship!
<% if current_user.workshop_expiration %>
Your scholarship will end on
<%= current_user.workshop_expiration.strftime("%b %d, %Y") %>.
<% end %>
</h4>
<% else %>
<p>
We encourage you to <b>apply below</b> and if within your means, to become a level 1 or 2 sustaining member.
</p>
<div class="typeform-widget" data-url="https://jes31.typeform.com/to/AJhky6" style="width: 100%; height: 500px; margin-bottom: 80px;"></div>
<script> (function () {
var qs, js, q, s, d = document, gi = d.getElementById, ce = d.createElement, gt = d.getElementsByTagName,
id = "typef_orm", b = "https://embed.typeform.com/";
if (!gi.call(d, id)) {
js = ce.call(d, "script");
js.id = id;
js.src = b + "embed.js";
q = gt.call(d, "script")[0];
q.parentNode.insertBefore(js, q)
}
})() </script>
<div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"></div>
<% end %>
</div>
</div>

View file

@ -126,7 +126,6 @@ Rails.application.routes.draw do
resources :blocks
resources :notifications, only: [:index]
resources :tags, only: [:index]
resources :stripe_subscriptions, only: %i[create update destroy]
resources :stripe_active_cards, only: %i[create update destroy]
resources :stripe_cancellations, only: [:create]
resources :live_articles, only: [:index]
@ -173,9 +172,6 @@ Rails.application.routes.draw do
get "/social_previews/organization/:id" => "social_previews#organization", as: :organization_social_preview
get "/social_previews/tag/:id" => "social_previews#tag", as: :tag_social_preview
### Subscription vanity url
post "membership-action" => "stripe_subscriptions#create"
get "/async_info/base_data", controller: "async_info#base_data", defaults: { format: :json }
get "/hello-goodbye-to-the-go-go-go",
@ -245,7 +241,6 @@ Rails.application.routes.draw do
get "/security", to: "pages#bounty"
get "/survey", to: redirect("https://dev.to/ben/final-thoughts-on-the-state-of-the-web-survey-44nn")
get "/now" => "pages#now"
get "/membership" => "pages#membership"
get "/events" => "events#index"
get "/workshops", to: redirect("events")
get "/sponsorship-info" => "pages#sponsorship_faq"
@ -259,7 +254,6 @@ Rails.application.routes.draw do
get "/freestickers/edit" => "giveaways#edit"
get "/scholarship", to: redirect("/p/scholarships")
get "/scholarships", to: redirect("/p/scholarships")
get "/memberships", to: redirect("/membership")
get "/shop", to: redirect("https://shop.dev.to/")
get "/tag-moderation" => "pages#tag_moderation"
get "/community-moderation" => "pages#community_moderation"
@ -271,7 +265,7 @@ Rails.application.routes.draw do
scope "p" do
pages_actions = %w[rly rlyweb welcome twitter_moniter editor_guide publishing_from_rss_guide information
markdown_basics scholarships wall_of_patrons membership_form badges]
markdown_basics scholarships wall_of_patrons badges]
pages_actions.each do |action|
get action, action: action, controller: "pages"
end

View file

@ -58,13 +58,6 @@ RSpec.describe "Pages", type: :request do
end
end
describe "GET /membership" do
it "has proper headline" do
get "/membership"
expect(response.body).to include("Sustaining Membership")
end
end
describe "GET /welcome" do
it "has proper headline" do
get "/welcome"

View file

@ -29,20 +29,6 @@ RSpec.describe "StripeSubscriptions", type: :request do
end
end
describe "PATCH StripeActiveCards#update" do
before do
post "/stripe_subscriptions", params: { amount: "12",
stripe_token: stripe_helper.generate_card_token }
end
it "properly updates the default card" do
first_card = Stripe::Customer.retrieve(user.stripe_id_code).sources.first
put "/stripe_active_cards/#{first_card.id}"
source = Stripe::Customer.retrieve(user.stripe_id_code).default_source
expect(source).to eq(first_card.id)
end
end
describe "DESTROY StripeActiveCards#destroy" do
context "when a valid request is made" do
before do
@ -65,28 +51,5 @@ RSpec.describe "StripeSubscriptions", type: :request do
expect(customer.sources.all.count).to eq(0)
end
end
context "when a user only has one card and one subscription" do
before do
valid_instance(user)
post "/stripe_subscriptions", params: { amount: 12 }
customer = Stripe::Customer.retrieve(user.stripe_id_code)
original_card_id = customer.sources.all(object: "card").first.id
delete "/stripe_active_cards/#{original_card_id}"
end
it "provides the proper flash error" do
expect(flash[:error]).to include("Can't remove card if you have an active membership.")
end
it "redirects to billing page" do
expect(response).to redirect_to("/settings/billing")
end
it "does not delete the card" do
customer = Stripe::Customer.retrieve(user.stripe_id_code)
expect(customer.sources.all.count).to eq(1)
end
end
end
end

View file

@ -1,171 +0,0 @@
require "rails_helper"
RSpec.describe "StripeSubscriptions", type: :request do
let(:user) { create(:user, :super_admin) }
let(:mock_instance) { instance_double(MembershipService) }
let(:stripe_helper) { StripeMock.create_test_helper }
before do
StripeMock.start
sign_in user
end
after { StripeMock.stop }
describe "POST StripeSubscriptions#create" do
context "when a valid request is made" do
# Amount is a string here because Stripe returns a string when form is submitted
before do
post "/stripe_subscriptions", params: {
amount: "12",
stripe_token: stripe_helper.generate_card_token
}
end
it "creates a customer in Stripe and assigns it to the correct user" do
customer = Stripe::Customer.retrieve(user.stripe_id_code)
expect(customer.is_a?(Stripe::Customer)).to eq(true)
end
it "assigns the proper role based on the amount" do
expect(user.roles.last.name).to eq("level_2_member")
end
it "updates the user's monthly_dues with the proper amount" do
expect(user.monthly_dues).to eq(1200)
end
it "redirects to /settings/membership" do
expect(response.body).to include("Thank you so much")
end
end
it "can't accept anything less than $1" do
post "/stripe_subscriptions", params: {
amount: rand(100) / 100,
stripe_token: stripe_helper.generate_card_token
}
expect(response).to redirect_to("/membership")
user.reload
expect(user.stripe_id_code).to eq(nil)
expect(user.roles.count).to eq(1)
end
# only one type of invalid request right now
context "when an invalid request is made" do
it "redirects to /enter if there's no current_user" do
sign_out user
post "/stripe_subscriptions", params: { amount: "1" }
expect(response).to redirect_to("/enter")
end
it "errors if amount is less than 0" do
post "/stripe_subscriptions", params: { amount: "-1" }
expect(response).to redirect_to("/membership")
end
it "errors if amount is 0" do
post "/stripe_subscriptions", params: { amount: "0" }
expect(response).to redirect_to("/membership")
end
it "denies requests without credit card" do
post "/stripe_subscriptions", params: { amount: "25" }
expect(response).to redirect_to("/membership")
# user.reload
# expect(user.stripe_id_code).to be(nil)
end
end
it "handles errors if MembershipService#subscribe_customer fails" do
allow(MembershipService).to receive(:new).and_return(mock_instance)
allow(mock_instance).to receive(:subscribe_customer).and_return(nil)
post "/stripe_subscriptions", params: { amount: "1" }
expect(response).to redirect_to("/membership")
end
end
describe "PUT StripeSubscriptions#update" do
before do
user.add_role(:level_2_member)
end
context "when there's a subscription for update" do
before do
post "/stripe_subscriptions", params: {
amount: "12",
stripe_token: stripe_helper.generate_card_token
}
end
it "assigns the proper role with a new subscription" do
put "/stripe_subscriptions/current_user", params: {
amount: "30",
stripe_token: stripe_helper.generate_card_token
}
expect(user.has_role?("level_4_member")).to eq(true)
end
it "updates the user's monthly_dues with the proper amount" do
put "/stripe_subscriptions/current_user", params: {
amount: "30",
stripe_token: stripe_helper.generate_card_token
}
user.reload
expect(user.monthly_dues).to eq(3000)
end
it "handles errors if MembershipService#update_subscription fails" do
allow(MembershipService).to receive(:new).and_return(mock_instance)
allow(mock_instance).to receive(:update_subscription).and_return(nil)
put "/stripe_subscriptions/current_user", params: {
amount: "30",
stripe_token: stripe_helper.generate_card_token
}
expect(response).to redirect_to("/settings/membership")
end
it "can't accept anything less than $1" do
put "/stripe_subscriptions/current_user", params: { amount: rand(100) / 100 }
expect(response).to redirect_to("/settings/billing")
user.reload
expect(user.stripe_id_code).not_to eq(nil)
expect(user.has_role?(:level_1_member)).to eq(false)
end
end
end
describe "DESTROY StripeSubscriptions#destroy" do
before do
user.add_role(:level_2_member)
post "/stripe_subscriptions", params: {
amount: "12",
stripe_token: stripe_helper.generate_card_token
}
end
context "when a valid request is made" do
it "deletes membership" do
delete "/stripe_subscriptions/current_user", params: {
stripe_token: stripe_helper.generate_card_token
}
expect(user.has_role?("level_2_member")).to eq(false)
end
it "returns user monthly dues to zero" do
delete "/stripe_subscriptions/current_user", params: {
stripe_token: stripe_helper.generate_card_token
}
user.reload
expect(user.monthly_dues).to eq(0)
end
it "handles errors if MembershipService#unsubscribe_customer fails" do
allow(MembershipService).to receive(:new).and_return(mock_instance)
allow(mock_instance).to receive(:unsubscribe_customer).and_return(nil)
delete "/stripe_subscriptions/current_user"
expect(response).to redirect_to("/settings")
end
end
end
end

View file

@ -15,7 +15,7 @@ RSpec.describe "UserSettings", type: :request do
before { login_as user }
it "renders various settings tabs properly" do
%w[organization switch-organizations billing misc account].each do |tab|
%w[organization switch-organizations misc account].each do |tab|
get "/settings/#{tab}"
expect(response.body).to include("Settings for")
end
@ -26,17 +26,6 @@ RSpec.describe "UserSettings", type: :request do
to raise_error(ActiveRecord::RecordNotFound)
end
it "doesn't let user access membership if user has no monthly_dues" do
get "/settings/membership"
expect(response.body).not_to include("Settings for")
end
it "allows user with monthly_dues to access membership" do
user.update_column(:monthly_dues, 5)
get "/settings/membership"
expect(response.body).to include("Settings for")
end
it "allows users to visit the account page" do
get "/settings/account"
expect(response.body).to include("Danger Zone")