def test_user_cannot_add_another_users_verified_email(session): """A user cannot add another users verified email address.""" # Given a user with a verified email and another user user_1 = create_user(session, email='*****@*****.**') user_1.emails[0].verify() user_2 = create_user(session, email='*****@*****.**') # When trying to add the first user's email on the second user # Then expect a DuplicateEmailError with pytest.raises(DuplicateEmailError): user_2.add_email(email='*****@*****.**')
def test_user_cannot_set_primary_email_to_another_users_email(session): """A User cannot set a primary email to another user's email.""" # Given 2 users and user_1 has an verified email user_1 = create_user(session, email='*****@*****.**') user_1.emails[0].verify() user_2 = create_user(session, email='*****@*****.**') # When user_2 tries to set user_1's verified email as a primary email # Then an IntegrityError should be thrown with pytest.raises(IntegrityError): user_2.primary_email = '*****@*****.**' user_2.save()
def test_user_can_add_emails(session): """A user can add emails to their existing account.""" # Given a user user = create_user(session, email='*****@*****.**') # When an email is added using `add_email` method user.add_email('*****@*****.**') # Then that email should be accessible assert user.emails[1].email == '*****@*****.**' # When an email is added using `add_email` method using keyword user.add_email(email='*****@*****.**') # Then that email should be accessible assert user.emails[2].email == '*****@*****.**' # When a list of emails is added using `add_email` method user.add_email(emails=['*****@*****.**', '*****@*****.**']) # Then that email should be accessible assert user.emails[3].email == '*****@*****.**' assert user.emails[4].email == '*****@*****.**' # When an email is added using SQLAlchemy's `append` method user.emails.append(Email(email='*****@*****.**')) # Then that email should be accessible assert user.emails[5].email == '*****@*****.**'
def test_user_can_set_a_primary_email_from_their_emails(session): """A user has set a primary email from their emails. This attribute is also accessible via the email dynamic property.""" # Given a user with verified emails user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) for email in user.emails: email.verify() # When setting the primary email user.primary_email = '*****@*****.**' session.commit() # Then the primary email is accessible assert user.primary_email == '*****@*****.**' assert user.email == '*****@*****.**' # When setting the primary email via the `email` property to a verified email user.email = '*****@*****.**' session.commit() # Then the primary email is accessible assert user.email == '*****@*****.**' assert user.primary_email == '*****@*****.**'
def test_an_email_is_initially_created_unverified(session): """An email is initially created unverified.""" # Given a user with an email user = create_user(session, email='*****@*****.**') # When the email has been initially created # Then it should not yet be verified assert not user.emails[0].verified assert not user.emails[0].is_verified
def test_user_has_is_confirmed_property_set_to_false_initially(session): """An email model's string is the email itself.""" # Given a user with an email user = create_user(session, email='*****@*****.**') session.commit() # When initially checking its is_confirmed property # Then it should be false assert user.is_confirmed == False
def test_user_can_add_another_users_unverified_email(session): """A user *can* add another user's unverified email address. If they haven't verified it, it's still up for grabs. This keeps someone from 'holding' an email hostage. Note that in the database, the old row is removed and a new row is created.""" # Given a user with an unverified email and another user user_1 = create_user(session, email='*****@*****.**') user_2 = create_user(session, email='*****@*****.**') # When second user tries to take the unverified email user_2.add_email(email='*****@*****.**') session.commit() # Then the second user should now be the new owner assert '*****@*****.**' in user_2.emails assert '*****@*****.**' not in user_1.emails
def test_users_primary_email_must_be_verified__when_using_orm(session): """A users primary email must be verified. The ORM will enforce this.""" # Given a user with an unverified email user = create_user(session, email='*****@*****.**') # When the user attempts to change the primary_email_fk attribute # Then expect an error with pytest.raises(IntegrityConstraintViolation): user.primary_email_fk = '*****@*****.**' user.save()
def test_user_can_use_the_email_property_to_add_emails(session): """A user can use the email property to add emails to their existing account.""" user = create_user(session, email='*****@*****.**') # When an email is added using `add_email` method user.email = '*****@*****.**' # Then that email should be accessible assert user.emails[1].email == '*****@*****.**'
def test_user_can_remove_emails(session): """A user can remove emails from their account.""" # Given a user with multiple emails user = create_user(session, email='*****@*****.**') # When an email is removed user.remove_email('*****@*****.**') session.commit() # Then that email should no longer be accessible assert len(user.emails) == 0
def test_users_primary_email_must_exist_in_email_table(session): """A user's primary email must exist as one of the emails in the email table.""" # Given a user user = create_user(session, email='*****@*****.**') # When trying to set the primary email to a non-existing email # Then an IntegrityError should be thrown with pytest.raises(OperationalError): user.primary_email = '*****@*****.**' user.save()
def test_user_is_confirmed_property_set_to_true_after_verifying_email(session): """An email model's string is the email itself.""" # Given a user with an email user = create_user(session, email='*****@*****.**') # When the user verifies its email and sets it as primary user.emails[0].verify() user.primary_email = user.emails[0] user.save() # Then it should be confirmed assert user.is_confirmed == True
def test_user_can_have_more_than_one_email(session): """A user can be created with more than one email.""" # Given a user with more than one email user = create_user( session, email=None, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) # Then those emails should all be accessible assert user.emails[0].email == '*****@*****.**' assert user.emails[1].email == '*****@*****.**' assert user.emails[2].email == '*****@*****.**'
def test_primary_email_property_returns_first_email_if_not_set_and_no_verified( session): """A user's primary email propery returns the first email if the primary email is not yet set and none of the emails are verified.""" # Given a user with no verified emails user = create_user(session, emails=[ '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**' ]) # When accessing the primary_email property # Then expect it to be the first verified email assert user.primary_email == '*****@*****.**'
def test_a_primary_email_cannot_be_deleted_using__the_sql(session): """A primary email cannot be deleted. This is enforced in the SQL.""" # Given a user with a primary email set user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) user.emails[0].verify() user.primary_email = '*****@*****.**' user.save() # When attempting to delete this primary email # Then expect an IntegrityError with pytest.raises(IntegrityError): session.query(Email).filter_by(email='*****@*****.**').delete()
def test_user_cannot_delete_their_primary_email__using_sql(session): """A User cannot delete their primary email.""" # Given a user with an email set as primary. user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) user.emails[0].verify() user.primary_email = '*****@*****.**' user.save() # When attempting to delete this email # Then expect an IntegrityError with pytest.raises(IntegrityError): user.emails[0].delete()
def test_users_primary_email_must_be_verified__when_using_sql(session): """A users primary email must be verified. The Database will also enforce this.""" # Given a user with an unverified email saved to the database user = create_user(session, email='*****@*****.**') session.commit() # When the user attempts to update the primary_email_fk column query = User.__table__.update().where(User.id==user.id).\ values(primary_email_fk='*****@*****.**') # Then expect an error with pytest.raises(OperationalError): session.connection().execute(query)
def test_a_user_can_be_deleted(session): """When a user is deleted, the user's emails are also deleted.""" # Given a user with its corresponding id user = create_user(session, email='*****@*****.**') user.save() user_id = user.id assert session.query(User).filter_by(id=user_id).count() == 1 # When the user is deleted user.delete() # Expect not to find the user. assert session.query(User).filter_by(id=user_id).count() == 0
def test_a_user_cannot_set_their_primary_email_to_null__using_sql(session): """A user cannot set their primary email to null.""" # Given a user with an email set as primary. user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) user.emails[0].verify() user.primary_email = '*****@*****.**' user.save() # When attempting to delete this email # Then expect an OperationalError with pytest.raises(OperationalError): user.primary_email = None user.save()
def test_users_primary_email_returns_first_email_when_no_verified_emails_exist( session): """Whan a user doesn't have a verified email, the primary_email property will return the first email. However, it will not save this as the primary email in the database.""" # Given a user with several emails user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) session.commit() # When a user's primary email is not set # Then the first email in the list is the default assert user.primary_email == '*****@*****.**' assert user.primary_email_fk == None
def test_user_can_update_attributes_other_than_unverified_primary_email__when_using_orm( session): """A users can update other attributes besides the email when using ORM. In other words, the primary email can remain 'NULL' in an update as long as it isn't being changed.""" # Given a user with an unverified email saved to the database user = create_user(session, email='*****@*****.**') session.commit() # When the user attempts to update first_name user.first_name = 'Janett' user.save() # Then expect no errors and the first_name to be changed assert user.first_name == 'Janett'
def test_an_email_cannot_be_changed_after_its_created__when_using_sql(session): """An email cannot be changed once created. The database enforces this. It must be deleted and a new email should then be added. Note that in order to be saved in the database, the email must be created off a user since it requires a user_id.""" # Given a user with an email user = create_user(session, email='*****@*****.**') session.commit() # When the user attempts to change the email query = Email.__table__.update().where(Email.email=='*****@*****.**').\ values(email='*****@*****.**') # Then expect an error with pytest.raises(OperationalError): session.connection().execute(query)
def test_an_email_cannot_be_changed_after_its_created__when_using_orm(session): """An email cannot be changed once created. The ORM enforces this. It must be deleted and a new email should then be added. Note that in order to be saved in the database, the email must be created off a user since it requires a user_id. NOTE: It may be a good idea to make this transparent to the user from a UX standpoint.""" # Given a user with an email user = create_user(session, email='*****@*****.**') # When the user attempts to change the email # Then expect an error with pytest.raises(IntegrityConstraintViolation): user.emails[0].email = '*****@*****.**' user.emails[0].save()
def test_when_an_email_is_deleted_the_user_remains_untouched(session): """When a user is deleted, the user's emails are also deleted.""" # Given a user with multiple email addresses user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) user.save() user_id = user.id # When one of those emails is deleted session.query(Email).filter_by(email='*****@*****.**').delete() assert session.query(Email).filter_by( email='*****@*****.**').count() == 0 # Expect the user to still be there assert session.query(User).filter_by(id=user_id).count() == 1
def test_primary_email_property_returns_first_verified_email_if_not_set( session): """A user's primary email propery returns the first verified email if the primary email is not yet set.""" # Given a user with multiple emails, some verified user = create_user(session, emails=[ '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**' ]) user.emails[2].verify() user.emails[3].verify() session.commit() # When accessing the primary_email property # Then expect it to be the first verified email assert user.primary_email == '*****@*****.**'
def test_user_can_update_attributes_other_than_unverified_primary_email__when_using_sql( session): """A users can update other attributes besides the email when using SQL. In other words, the primary email can remain 'NULL' in an update as long as it isn't being changed.""" # Given a user with an unverified email saved to the database user = create_user(session, email='*****@*****.**') session.commit() # When the user attempts to update first_name column session.connection().execute( User.__table__.update().where(User.id==user.id).\ values(first_name='Janett') ) # Then expect no errors and the first_name to be changed user = user.fresh() assert user.first_name == 'Janett'
def test_a_user_with_a_primary_email_can_be_deleted(session): """A user with a primary email can be deleted. This also deletes the primary email.""" # Given a user with a primary email set user = create_user( session, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) user.emails[0].verify() user.primary_email = '*****@*****.**' user.save() user_id = user.id # When deletin the user user.delete() # Then expect both the user and the email to be gone from the database assert session.query(Email).filter_by( email='*****@*****.**').count() == 0 assert session.query(User).filter_by(id=user_id).count() == 0
def test_an_email_can_generate_verification_token(app, session): """An email can generate a verification token.""" # Given an email (on a user) and that email's verification token user = create_user(session, email='*****@*****.**') email_verification_token = user.email.verification_token # When the token is used to retrieve the email email_to_verify = Email.get_email_by_token(email_verification_token) # Then it returns the email to verify assert email_to_verify == '*****@*****.**' # When the token is decoded from jwt import decode as jwt_decode decoded_token = jwt_decode(email_verification_token, app.config['SECRET_KEY'], algorithms=['HS256']) # Then the email and user id should be accessible. assert decoded_token['email'] == '*****@*****.**' assert decoded_token['user_id'] == user.id
def test_users_primary_email_defaults_to_their_first_verified_email(session): """When a user doesn't have a primary_email, their first verified email is set to the primary email. NOTE: This means that, from the ORM's perspective, a primary_email might be unverified.""" # Given a user with several emails user = create_user( session, email=None, emails=['*****@*****.**', '*****@*****.**', '*****@*****.**']) # When a user's primary email is not set # Then the first email in the list is the default assert user.primary_email == '*****@*****.**' assert user.email == '*****@*****.**' # When committing the database after retrieving the email # Then the database does not try to save this unverified email session.commit() # (this would throw a database error) assert user.primary_email_fk == None
def test_user_can_generate_password_reset_token(app, session): """A user can generate a password reset token.""" # Given a user and the user's password reset token user = create_user(session, password='******', email='*****@*****.**') password_reset_token = user.password_reset_token # When the user is retrieved by password reset token verified_user = User.verify_password_reset_token(password_reset_token) # Then it returns the user to change the password assert verified_user.id == user.id # When the token is decoded from jwt import decode as jwt_decode decoded_token = jwt_decode(password_reset_token, app.config['SECRET_KEY'], algorithms=['HS256']) # Then the user's email should be accessible. assert decoded_token['password_reset_for_email'] == '*****@*****.**'