From 869e7ece42ebea4c7c19197bd9cbc3a63cafa954 Mon Sep 17 00:00:00 2001 From: Chris Veilleux Date: Wed, 12 Jun 2019 15:15:40 -0500 Subject: [PATCH] refactored tests to use the stripe API more and use a list of accounts in the test context. --- .../tests/features/add_account.feature | 8 - api/account/tests/features/add_device.feature | 15 +- .../tests/features/authentication.feature | 12 +- api/account/tests/features/environment.py | 38 ++--- api/account/tests/features/profile.feature | 30 +++- .../tests/features/remove_account.feature | 2 +- .../tests/features/steps/add_account.py | 89 +---------- .../tests/features/steps/add_device.py | 10 +- .../tests/features/steps/authentication.py | 62 ++++++-- api/account/tests/features/steps/common.py | 17 +- api/account/tests/features/steps/profile.py | 119 +++++++++++++- .../tests/features/steps/remove_account.py | 22 +-- .../tests/features/steps/update_membership.py | 150 ------------------ .../tests/features/update_membership.feature | 19 --- 14 files changed, 252 insertions(+), 341 deletions(-) delete mode 100644 api/account/tests/features/steps/update_membership.py delete mode 100644 api/account/tests/features/update_membership.feature diff --git a/api/account/tests/features/add_account.feature b/api/account/tests/features/add_account.feature index 63d97a05..7f790729 100644 --- a/api/account/tests/features/add_account.feature +++ b/api/account/tests/features/add_account.feature @@ -12,11 +12,3 @@ Feature: Add a new account And user does not specify an email address When the new account request is submitted Then the request will fail with a bad request error - - Scenario: Successful on-boarding with membership - Given a new account without a membership - And user with username bar is authenticated - When a user opts into a membership during on-boarding - Then the request will be successful - And the account will be updated with the membership - diff --git a/api/account/tests/features/add_device.feature b/api/account/tests/features/add_device.feature index 5fc5e0ac..4f600e36 100644 --- a/api/account/tests/features/add_device.feature +++ b/api/account/tests/features/add_device.feature @@ -2,10 +2,11 @@ Feature: Pair a device Test the device add endpoint Scenario: Add a device - Given user with username foo is authenticated - And a device pairing code - When an API request is sent to add a device - Then the request will be successful - And the device is added to the database - And the pairing code is removed from cache - And the pairing token is added to cache + Given an account + And the account is authenticated + And a device pairing code + When an API request is sent to add a device + Then the request will be successful + And the device is added to the database + And the pairing code is removed from cache + And the pairing token is added to cache diff --git a/api/account/tests/features/authentication.feature b/api/account/tests/features/authentication.feature index 451b0cf8..81f1b704 100644 --- a/api/account/tests/features/authentication.feature +++ b/api/account/tests/features/authentication.feature @@ -9,18 +9,24 @@ Feature: Authentication with JWTs be the only place authentication logic needs to be tested. Scenario: Request for user data includes valid access token - Given user with username foo is authenticated + Given an account with a valid access token When a user requests their profile Then the request will be successful And the authentication tokens will remain unchanged Scenario: Access token expired - Given an authenticated user with an expired access token + Given an account with an expired access token + When a user requests their profile + Then the request will be successful + And the authentication tokens will be refreshed + + Scenario: Access token missing but refresh token valid + Given an account with a refresh token but no access token When a user requests their profile Then the request will be successful And the authentication tokens will be refreshed Scenario: Both access and refresh tokens expired - Given a previously authenticated user with expired tokens + Given an account with expired access and refresh tokens When a user requests their profile Then the request will fail with an unauthorized error diff --git a/api/account/tests/features/environment.py b/api/account/tests/features/environment.py index 466c4b25..23e01a42 100644 --- a/api/account/tests/features/environment.py +++ b/api/account/tests/features/environment.py @@ -1,16 +1,9 @@ from behave import fixture, use_fixture from account_api.api import acct -from selene.data.account import ( - AccountRepository, -) -from selene.testing import ( - add_account, - add_account_geography, - add_agreements, - remove_account, - remove_agreements -) +from selene.testing.account import add_account, remove_account +from selene.testing.account_geography import add_account_geography +from selene.testing.agreement import add_agreements, remove_agreements from selene.util.cache import SeleneCache from selene.util.db import connect_to_db @@ -38,31 +31,22 @@ def after_all(context): def before_scenario(context, _): - context.account = context.foo_account = add_account(context.db) - context.geography_id = add_account_geography(context.db, context.account) + account = add_account(context.db) + context.accounts = dict(foo=account) + context.geography_id = add_account_geography(context.db, account) def after_scenario(context, _): - db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) - _delete_account(context, db) - _clean_cache() - - -def _delete_account(context, db): - """Delete the account and all its related data. + """Scenario-level cleanup. The database is setup with cascading deletes that take care of cleaning up[ referential integrity for us. All we have to do here is delete the account and all rows on all tables related to that account will also be deleted. """ - acct_repository = AccountRepository(db) - remove_account(db, context.foo_account) - bar_acct = acct_repository.get_account_by_email('bar@mycroft.ai') - if bar_acct is not None: - remove_account(db, bar_acct) - test_acct = acct_repository.get_account_by_email('test@mycroft.ai') - if test_acct is not None: - remove_account(db, test_acct) + + for account in context.accounts.values(): + remove_account(context.db, account) + _clean_cache() def _clean_cache(): diff --git a/api/account/tests/features/profile.feature b/api/account/tests/features/profile.feature index 7954c6ed..a9e11c5b 100644 --- a/api/account/tests/features/profile.feature +++ b/api/account/tests/features/profile.feature @@ -3,7 +3,29 @@ Feature: Manage account profiles settings. Scenario: Retrieve authenticated user's account - Given user with username foo is authenticated - When a user requests their profile - Then the request will be successful - And user profile is returned + Given an account with a monthly membership +# And the account is authenticated + When a user requests their profile + Then the request will be successful + And user profile is returned + + Scenario: user with free account opts into a membership + Given an account without a membership + And the account is authenticated + When a monthly membership is added + Then the request will be successful + And the account should have a monthly membership + + Scenario: user opts out monthly membership + Given an account with a monthly membership +# And the account is authenticated + When the membership is cancelled + Then the request will be successful + And the account should have no membership + + Scenario: user changes from a monthly membership to yearly membership + Given an account with a monthly membership +# And the account is authenticated + When the membership is changed to yearly + Then the request will be successful + And the account should have a yearly membership diff --git a/api/account/tests/features/remove_account.feature b/api/account/tests/features/remove_account.feature index 18a0f915..99fa472d 100644 --- a/api/account/tests/features/remove_account.feature +++ b/api/account/tests/features/remove_account.feature @@ -2,7 +2,7 @@ Feature: Delete an account Test the API call to delete an account and all its related data from the database. Scenario: Successful account deletion - Given user with username foo is authenticated + Given an account with a monthly membership When the user's account is deleted Then the request will be successful And the membership is removed from stripe diff --git a/api/account/tests/features/steps/add_account.py b/api/account/tests/features/steps/add_account.py index 7df26878..9c184ca6 100644 --- a/api/account/tests/features/steps/add_account.py +++ b/api/account/tests/features/steps/add_account.py @@ -1,19 +1,15 @@ from binascii import b2a_base64 -from datetime import date, datetime -from dataclasses import dataclass -from unittest.mock import call, patch +from datetime import date from behave import given, then, when from flask import json -from hamcrest import assert_that, equal_to, is_in, none, not_none +from hamcrest import assert_that, equal_to, is_in, not_none from selene.data.account import ( AccountRepository, - MONTHLY_MEMBERSHIP, PRIVACY_POLICY, TERMS_OF_USE ) -from selene.testing.account import add_account new_account_request = dict( termsOfUse=True, @@ -27,50 +23,16 @@ new_account_request = dict( ) -@dataclass -class StripeMock(object): - """Object intended to behave like stripe Customer/Subscription create""" - id: str - - @given('a user completes new account setup') def build_new_account_request(context): context.new_account_request = new_account_request -@given('user opts out of membership') -def add_maybe_later_membership(context): - context.new_account_request['support'].update( - membership=None, - paymentMethod=None, - paymentAccountId=None - ) - - -@given('user opts into a membership') -def change_membership_option(context): - context.new_account_request['support'].update( - membership='Monthly Membership', - paymentMethod='Stripe', - paymentToken='tok_visa' - ) - - @given('user does not specify an email address') def remove_email_from_request(context): del(context.new_account_request['login']['email']) -@given('a new account without a membership') -def add_account_no_membership(context): - new_account_overrides = dict( - email_address='bar@mycroft.ai', - username='bar', - membership=None - ) - context.bar_account = add_account(context.db, **new_account_overrides) - - @when('the new account request is submitted') def call_add_account_endpoint(context): context.client.content_type = 'application/json' @@ -81,44 +43,12 @@ def call_add_account_endpoint(context): ) -@when('a user opts into a membership during on-boarding') -def call_update_account_endpoint(context): - onboarding_request = dict( - membership=dict( - newMembership=True, - membershipType=MONTHLY_MEMBERSHIP, - paymentToken='test_payment_token', - paymentMethod='Stripe' - ) - ) - with patch('stripe.Subscription.create') as subscription_patch: - subscription_patch.return_value = StripeMock(id='test_subscription') - with patch('stripe.Customer.create') as customer_patch: - customer_patch.return_value = StripeMock(id='test_customer') - context.response = context.client.patch( - '/api/account', - data=json.dumps(onboarding_request), - content_type='application/json' - ) - assert_that( - customer_patch.mock_calls, - equal_to([call( - email='bar@mycroft.ai', - source='test_payment_token' - )]) - ) - assert_that( - subscription_patch.mock_calls, - equal_to([call( - customer='test_customer', - items=[{'plan': 'monthly_premium'}]) - ])) - - @then('the account will be added to the system') def check_db_for_account(context): acct_repository = AccountRepository(context.db) account = acct_repository.get_account_by_email('bar@mycroft.ai') + # add account to context so it will deleted by cleanup step + context.accounts['bar'] = account assert_that(account, not_none()) assert_that( account.email_address, equal_to('bar@mycroft.ai') @@ -128,14 +58,3 @@ def check_db_for_account(context): for agreement in account.agreements: assert_that(agreement.type, is_in((PRIVACY_POLICY, TERMS_OF_USE))) assert_that(agreement.accept_date, equal_to(str(date.today()))) - - -@then('the account will be updated with the membership') -def validate_membership_update(context): - account_repository = AccountRepository(context.db) - membership = account_repository.get_active_account_membership( - context.account.id - ) - assert_that(membership.type, equal_to(MONTHLY_MEMBERSHIP)) - assert_that(membership.start_date, equal_to(datetime.utcnow().date())) - assert_that(membership.end_date, none()) diff --git a/api/account/tests/features/steps/add_device.py b/api/account/tests/features/steps/add_device.py index 5d2f3641..c50a47cc 100644 --- a/api/account/tests/features/steps/add_device.py +++ b/api/account/tests/features/steps/add_device.py @@ -1,7 +1,7 @@ import json from behave import given, when, then -from hamcrest import assert_that, equal_to, has_key, none, not_none +from hamcrest import assert_that, equal_to, none, not_none from selene.data.device import DeviceRepository from selene.util.cache import SeleneCache @@ -26,6 +26,11 @@ def set_device_pairing_code(context): context.pairing_code = 'ABC123' +@given('an account') +def define_account(context): + context.username = 'foo' + + @when('an API request is sent to add a device') def add_device(context): device = dict( @@ -57,6 +62,7 @@ def validate_pairing_code_removal(context): @then('the device is added to the database') def validate_response(context): device_id = context.response.data.decode() + account = context.accounts['foo'] db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) device_repository = DeviceRepository(db) device = device_repository.get_device_by_id(device_id) @@ -64,7 +70,7 @@ def validate_response(context): assert_that(device, not_none()) assert_that(device.name, equal_to('home')) assert_that(device.placement, equal_to('kitchen')) - assert_that(device.account_id, equal_to(context.account.id)) + assert_that(device.account_id, equal_to(account.id)) @then('the pairing token is added to cache') diff --git a/api/account/tests/features/steps/authentication.py b/api/account/tests/features/steps/authentication.py index 2ed4d40c..298862d4 100644 --- a/api/account/tests/features/steps/authentication.py +++ b/api/account/tests/features/steps/authentication.py @@ -1,27 +1,61 @@ from behave import given, then from hamcrest import assert_that, equal_to, is_not -from selene.api.testing import ( +from selene.testing.api import ( generate_access_token, generate_refresh_token, + set_access_token_cookie, + set_refresh_token_cookie, validate_token_cookies ) -from selene.data.account import AccountRepository from selene.util.auth import AuthenticationToken -from selene.util.db import connect_to_db + +EXPIRE_IMMEDIATELY = 0 -@given('an authenticated user with an expired access token') -def generate_refresh_token_only(context): - generate_access_token(context, expire=True) - generate_refresh_token(context) +@given('an account with a valid access token') +def use_account_with_valid_access_token(context): + context.username = 'foo' + context.access_token = generate_access_token(context) + set_access_token_cookie(context) + context.refresh_token = generate_refresh_token(context) + set_refresh_token_cookie(context) + + +@given('an account with an expired access token') +def generate_expired_access_token(context): + context.username = 'foo' + context.access_token = generate_access_token( + context, + duration=EXPIRE_IMMEDIATELY + ) + set_access_token_cookie(context, duration=EXPIRE_IMMEDIATELY) + context.refresh_token = generate_refresh_token(context) + set_refresh_token_cookie(context) context.old_refresh_token = context.refresh_token.jwt -@given('a previously authenticated user with expired tokens') +@given('an account with a refresh token but no access token') +def generate_refresh_token_only(context): + context.username = 'foo' + context.refresh_token = generate_refresh_token(context) + set_refresh_token_cookie(context) + context.old_refresh_token = context.refresh_token.jwt + + +@given('an account with expired access and refresh tokens') def expire_both_tokens(context): - generate_access_token(context, expire=True) - generate_refresh_token(context, expire=True) + context.username = 'foo' + context.access_token = generate_access_token( + context, + duration=EXPIRE_IMMEDIATELY + ) + set_access_token_cookie(context, duration=EXPIRE_IMMEDIATELY) + context.refresh_token = generate_refresh_token( + context, + duration=EXPIRE_IMMEDIATELY + ) + set_refresh_token_cookie(context, duration=EXPIRE_IMMEDIATELY) @then('the authentication tokens will remain unchanged') @@ -37,10 +71,6 @@ def check_for_new_cookies(context): context.refresh_token, is_not(equal_to(context.old_refresh_token)) ) - db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) - acct_repository = AccountRepository(db) - account = acct_repository.get_account_by_id(context.account.id) - refresh_token = AuthenticationToken( context.client_config['REFRESH_SECRET'], 0 @@ -49,4 +79,6 @@ def check_for_new_cookies(context): refresh_token.validate() assert_that(refresh_token.is_valid, equal_to(True)) assert_that(refresh_token.is_expired, equal_to(False)) - assert_that(refresh_token.account_id, equal_to(account.id)) + assert_that( + refresh_token.account_id, + equal_to(context.accounts['foo'].id)) diff --git a/api/account/tests/features/steps/common.py b/api/account/tests/features/steps/common.py index e8a4d509..cca06575 100644 --- a/api/account/tests/features/steps/common.py +++ b/api/account/tests/features/steps/common.py @@ -3,13 +3,20 @@ from http import HTTPStatus from behave import given, then from hamcrest import assert_that, equal_to, is_in -from selene.api.testing import generate_access_token, generate_refresh_token +from selene.testing.api import ( + generate_access_token, + generate_refresh_token, + set_access_token_cookie, + set_refresh_token_cookie +) -@given('user with username {username} is authenticated') -def setup_authenticated_user(context, username): - generate_access_token(context, username) - generate_refresh_token(context, username) +@given('the account is authenticated') +def use_account_with_valid_access_token(context): + context.access_token = generate_access_token(context) + set_access_token_cookie(context) + context.refresh_token = generate_refresh_token(context) + set_refresh_token_cookie(context) @then('the request will be successful') diff --git a/api/account/tests/features/steps/profile.py b/api/account/tests/features/steps/profile.py index 1682954f..f7ec0a5a 100644 --- a/api/account/tests/features/steps/profile.py +++ b/api/account/tests/features/steps/profile.py @@ -1,9 +1,40 @@ +import json from datetime import date -from behave import then, when -from hamcrest import assert_that, equal_to, has_item, none +from behave import given, then, when +from hamcrest import assert_that, equal_to, has_item, none, starts_with -from selene.data.account import PRIVACY_POLICY +from selene.data.account import AccountRepository, PRIVACY_POLICY +from selene.testing.api import ( + generate_access_token, + generate_refresh_token, + set_access_token_cookie, + set_refresh_token_cookie +) +from selene.testing.membership import MONTHLY_MEMBERSHIP, YEARLY_MEMBERSHIP + +BAR_EMAIL_ADDRESS = 'bar@mycroft.ai' +STRIPE_METHOD = 'Stripe' +VISA_TOKEN = 'tok_visa' + + +@given('an account with a monthly membership') +def add_membership_to_account(context): + """Use the API to add a monthly membership on Stripe + + The API is used so that the Stripe API can be interacted with. + """ + context.username = 'foo' + context.access_token = generate_access_token(context) + set_access_token_cookie(context) + context.refresh_token = generate_refresh_token(context) + set_refresh_token_cookie(context) + add_membership_via_api(context) + + +@given('an account without a membership') +def get_account_no_membership(context): + context.username = 'foo' @when('a user requests their profile') @@ -14,12 +45,58 @@ def call_account_endpoint(context): ) +@when('a monthly membership is added') +def add_monthly_membership(context): + context.response = add_membership_via_api(context) + + +@when('the membership is cancelled') +def cancel_membership(context): + membership_data = dict( + newMembership=False, + membershipType=None + ) + context.response = context.client.patch( + '/api/account', + data=json.dumps(dict(membership=membership_data)), + content_type='application/json' + ) + + +def add_membership_via_api(context): + membership_data = dict( + newMembership=True, + membershipType=MONTHLY_MEMBERSHIP, + paymentMethod=STRIPE_METHOD, + paymentToken=VISA_TOKEN + ) + return context.client.patch( + '/api/account', + data=json.dumps(dict(membership=membership_data)), + content_type='application/json' + ) + + +@when('the membership is changed to yearly') +def change_to_yearly_account(context): + membership_data = dict( + newMembership=False, + membershipType=YEARLY_MEMBERSHIP + ) + context.response = context.client.patch( + '/api/account', + data=json.dumps(dict(membership=membership_data)), + content_type='application/json' + ) + + @then('user profile is returned') def validate_response(context): response_data = context.response.json + account = context.accounts['foo'] assert_that( response_data['emailAddress'], - equal_to(context.account.email_address) + equal_to(account.email_address) ) assert_that( response_data['membership']['type'], @@ -38,3 +115,37 @@ def validate_response(context): equal_to(str(date.today().strftime('%B %d, %Y'))) ) assert_that(agreement, has_item('id')) + + +@then('the account should have a monthly membership') +def validate_monthly_account(context): + acct_repository = AccountRepository(context.db) + membership = acct_repository.get_active_account_membership( + context.accounts['foo'].id + ) + assert_that( + membership.type, + equal_to(MONTHLY_MEMBERSHIP) + ) + assert_that(membership.payment_account_id, starts_with('cus')) + assert_that(membership.start_date, equal_to(date.today())) + assert_that(membership.end_date, none()) + + +@then('the account should have no membership') +def validate_absence_of_membership(context): + acct_repository = AccountRepository(context.db) + membership = acct_repository.get_active_account_membership( + context.accounts['foo'].id + ) + assert_that(membership, none()) + + +@then('the account should have a yearly membership') +def yearly_account(context): + acct_repository = AccountRepository(context.db) + membership = acct_repository.get_active_account_membership( + context.accounts['foo'].id + ) + assert_that(membership.type, equal_to(YEARLY_MEMBERSHIP)) + assert_that(membership.payment_account_id, starts_with('cus')) diff --git a/api/account/tests/features/steps/remove_account.py b/api/account/tests/features/steps/remove_account.py index b74edf54..ffce2cac 100644 --- a/api/account/tests/features/steps/remove_account.py +++ b/api/account/tests/features/steps/remove_account.py @@ -1,30 +1,30 @@ import os -from unittest.mock import call, patch import stripe from behave import then, when -from hamcrest import assert_that, equal_to, not_none +from hamcrest import assert_that, equal_to from stripe.error import InvalidRequestError +from selene.data.account import AccountRepository + @when('the user\'s account is deleted') def account_deleted(context): - with patch('stripe.Subscription') as stripe_patch: - context.response = context.client.delete('/api/account') - assert_that( - stripe_patch.mock_calls, - equal_to([call.retrieve('bar'), call.retrieve().delete()]) - ) + acct_repository = AccountRepository(context.db) + membership = acct_repository.get_active_account_membership( + context.accounts['foo'].id + ) + context.accounts['foo'].membership = membership + context.response = context.client.delete('/api/account') @then('the membership is removed from stripe') def check_stripe(context): - stripe_id = context.account.membership.payment_account_id - assert_that(stripe_id, not_none()) + account = context.accounts['foo'] stripe.api_key = os.environ['STRIPE_PRIVATE_KEY'] subscription_not_found = False try: - stripe.Subscription.retrieve(stripe_id) + stripe.Subscription.retrieve(account.membership.payment_account_id) except InvalidRequestError: subscription_not_found = True assert_that(subscription_not_found, equal_to(True)) diff --git a/api/account/tests/features/steps/update_membership.py b/api/account/tests/features/steps/update_membership.py deleted file mode 100644 index a1ddd75d..00000000 --- a/api/account/tests/features/steps/update_membership.py +++ /dev/null @@ -1,150 +0,0 @@ -from binascii import b2a_base64 -from datetime import date -import json - -from behave import given, when, then -from hamcrest import assert_that, equal_to, starts_with, none - -from selene.api.testing import generate_access_token, generate_refresh_token -from selene.data.account import ( - AccountRepository, - Account, - AccountAgreement, - PRIVACY_POLICY -) -from selene.util.db import connect_to_db - -TEST_EMAIL_ADDRESS = 'test@mycroft.ai' - -new_account_request = dict( - username='test', - termsOfUse=True, - privacyPolicy=True, - login=dict( - federatedPlatform=None, - federatedToken=None, - email=b2a_base64(b'test@mycroft.ai').decode(), - password=b2a_base64(b'12345678').decode() - ), - support=dict( - openDataset=True, - membership='Maybe Later', - paymentMethod=None, - paymentAccountId=None - ) -) - -MONTHLY_MEMBERSHIP = 'Monthly Membership' -STRIPE_METHOD = 'Stripe' -VISA_TOKEN = 'tok_visa' -YEARLY_MEMBERSHIP = 'Yearly Membership' - - -@given('a user with a free account') -def create_account(context): - context.account = Account( - email_address='test@mycroft.ai', - username='test', - membership=None, - agreements=[ - AccountAgreement(type=PRIVACY_POLICY, accept_date=date.today()) - ] - ) - db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) - acct_repository = AccountRepository(db) - account_id = acct_repository.add(context.account, 'foo') - context.account.id = account_id - generate_access_token(context) - generate_refresh_token(context) - - -@when('a monthly membership is added') -def update_membership(context): - membership_data = dict( - newMembership=True, - membershipType=MONTHLY_MEMBERSHIP, - paymentMethod=STRIPE_METHOD, - paymentToken=VISA_TOKEN - ) - context.response = context.client.patch( - '/api/account', - data=json.dumps(dict(membership=membership_data)), - content_type='application/json' - ) - - -@when('the account is requested') -def request_account(context): - db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) - context.response_account = AccountRepository(db).get_account_by_email( - TEST_EMAIL_ADDRESS - ) - - -@then('the account should have a monthly membership') -def monthly_account(context): - account = context.response_account - assert_that( - account.membership.type, - equal_to(MONTHLY_MEMBERSHIP) - ) - assert_that(account.membership.payment_account_id, starts_with('cus')) - - -@given('a user with a monthly membership') -def create_monthly_account(context): - new_account_request['support'].update( - membership=MONTHLY_MEMBERSHIP, - paymentMethod=STRIPE_METHOD, - paymentToken=VISA_TOKEN - ) - context.client.post( - '/api/account', - data=json.dumps(new_account_request), - content_type='application/json' - ) - db = connect_to_db(context.client_config['DB_CONNECTION_CONFIG']) - account_repository = AccountRepository(db) - account = account_repository.get_account_by_email(TEST_EMAIL_ADDRESS) - context.account = account - generate_access_token(context) - generate_refresh_token(context) - - -@when('the membership is cancelled') -def cancel_membership(context): - membership_data = dict( - newMembership=False, - membershipType=None - ) - context.client.patch( - '/api/account', - data=json.dumps(dict(membership=membership_data)), - content_type='application/json' - ) - - -@then('the account should have no membership') -def free_account(context): - account = context.response_account - assert_that(account.membership, none()) - - -@when('the membership is changed to yearly') -def change_to_yearly_account(context): - membership_data = dict( - newMembership=False, - membershipType=YEARLY_MEMBERSHIP - ) - context.client.patch( - '/api/account', - data=json.dumps(dict(membership=membership_data)), - content_type='application/json' - ) - - -@then('the account should have a yearly membership') -def yearly_account(context): - account = context.response_account - assert_that(account.membership.type, equal_to(YEARLY_MEMBERSHIP)) - assert_that(account.membership.payment_account_id, starts_with('cus')) diff --git a/api/account/tests/features/update_membership.feature b/api/account/tests/features/update_membership.feature deleted file mode 100644 index fd414175..00000000 --- a/api/account/tests/features/update_membership.feature +++ /dev/null @@ -1,19 +0,0 @@ -Feature: Test the API call to update a membership - - Scenario: user with free account opts into a membership - Given a user with a free account - When a monthly membership is added - And the account is requested - Then the account should have a monthly membership - - Scenario: user opts out monthly membership - Given a user with a monthly membership - When the membership is cancelled - And the account is requested - Then the account should have no membership - - Scenario: user changes from a monthly membership to yearly membership - Given a user with a monthly membership - When the membership is changed to yearly - And the account is requested - Then the account should have a yearly membership \ No newline at end of file