def test_datetime_and_field_should_work(self): original_timestamp = timezone.now() - timedelta(hours=1) transaction = TransactionFactory(timestamp=original_timestamp) self.selenium.get( self.live_server_url + f"/admin/market/transaction/{transaction.id}/change/") self.assertIn(CONFIRM_CHANGE, self.selenium.page_source) # Set date via text input date_input = self.selenium.find_element(By.ID, "id_date") date_input.clear() date_input.send_keys("2021-01-01") self.assertEqual(date_input.get_attribute("value"), "2021-01-01") # Set timestamp via text input timestamp_date = self.selenium.find_element(By.ID, "id_timestamp_0") timestamp_date.clear() timestamp_date.send_keys(str(timezone.now().date())) timestamp_time = self.selenium.find_element(By.ID, "id_timestamp_1") timestamp_time.clear() timestamp_time.send_keys(str(timezone.now().time())) # Click save and continue self.selenium.find_element(By.NAME, "_continue").click() # Click Yes I'm Sure on confirmation page self.assertIn("Confirm", self.selenium.page_source) self.selenium.find_element(By.NAME, "_continue").click() transaction.refresh_from_db() self.assertEqual(str(transaction.date), "2021-01-01") self.assertTrue(transaction.timestamp > original_timestamp)
def test_should_not_delete_related_goals_or_user(self): user = UserFactory.create() transaction = TransactionFactory(user=user, goals=[GoalFactory.create(user=user)]) transaction.delete() self.assertEqual(User.query.count(), 1) self.assertEqual(Transaction.query.count(), 0) self.assertEqual(Goal.query.count(), 1)
def test_withdraw_limit_exceeded(self, mock_withdraws): """withdraw: check if exception is raised when current date transaction + transaction value exceeds daily limit. """ # given mock_withdraws.return_value = Decimal("40.00") account = self.create_account( balance=Decimal("50.00"), daily_withdraw_limit=Decimal("30.00"), ) # this is better tested in the endpoints. Since here we are mocking # daily_value. We can probably remove it! transaction = TransactionFactory( transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=Decimal("30.00"), account=account) # when with self.assertRaises(ApiException) as error_context: withdraw(transaction) # then exception = error_context.exception self.assertEqual(exception.errors['details'], daily_withdraw_limit) exception.errors['details'] = None self.assertEqual(exception.errors, AccountFailures.limit_exceeded)
def test_cannot_confirm_for_models_with_validator_on_model_field_if_validator_fails( self, ): # ItemSale.currency has a validator on it shop = ShopFactory() item = ItemFactory() InventoryFactory(shop=shop, item=item, quantity=10) transaction = TransactionFactory(shop=shop) data = { "transaction": transaction.id, "item": item.id, "quantity": 1, "currency": "FAKE", "total": 10.00, "_confirm_add": True, "_save": True, } response = self.client.post(reverse("admin:market_itemsale_add"), data) # Should show form with error and not confirmation page self.assertEqual(response.status_code, 200) expected_templates = [ "admin/market/itemsale/change_form.html", "admin/market/change_form.html", "admin/change_form.html", ] self.assertEqual(response.template_name, expected_templates) self.assertEqual(ItemSale.objects.count(), 0) self.assertIn("error", str(response.rendered_content)) self.assertIn("Invalid Currency", str(response.rendered_content)) # Should still ask for confirmation self.assertIn(CONFIRM_ADD, response.rendered_content)
def test_get_transactions_filter_operation(self): """get_transactions: check if all account transactions are returned when filtering by transaction_type. """ # given transactions = [ TransactionFactory(transaction_type=TransactionTypeEnum.withdraw), TransactionFactory(transaction_type=TransactionTypeEnum.deposit) ] account = self.create_account(transactions=transactions) # when query = get_transactions(account.id, transaction_type=TransactionTypeEnum.withdraw) # then self.assertEqual(1, query.count())
def test_should_delete_users_goals_and_transactions(self): for i in range(2): user = UserFactory.create() GoalFactory.create(user=user, transactions=[TransactionFactory.create(user=user)]) User.query.first().delete() self.assertEqual(User.query.count(), 1) self.assertEqual(Goal.query.count(), 1) self.assertEqual(Transaction.query.count(), 1)
def test_get_statement_paginated(self): """get: check if paginated statement is received for a valid account""" # given transactions = [ TransactionFactory(transaction_date=datetime(2020, 12, 15)), TransactionFactory(transaction_date=datetime(2020, 12, 16)), TransactionFactory(transaction_date=datetime(2020, 12, 19)) ] account = self.create_account(transactions=transactions) # when response = self.app.test_client().get( f'/accounts/statement/{account.id}?limit=1&offset=2', ) response_data = json.loads(response.data) # then self.assert200(response) self.assertEqual(len(response_data['transactions']), 1) self.assertEqual(response_data['id'], account.id)
def run(self): """Runs this command.""" if User.query.filter_by(email='*****@*****.**').first(): print('Example user and data already exists.') return user = UserFactory.instance.create(first_name='John', last_name='Smith', email='*****@*****.**', password=('matcha')) user.save() print('Created user `[email protected]` with password `matcha`') amex = AccessTokenFactory.create(user=user, institution__name='amex').institution bofa = AccessTokenFactory.create(user=user, institution__name='bofa').institution print('Created example institutions: amex, boa') fake = Faker() goal = GoalFactory.create(user=user, name='Roth IRA', amount=5500) for i in range(51): TransactionFactory.create(goals=[goal], institution=amex, name=fake.bs(), amount=fake.pydecimal(left_digits=3, right_digits=2), post_date=fake.date_time_this_year()) goal.save() print('Created goal `{}` with `{}` Transactions'.format(goal.name, 50)) goal = GoalFactory.create(user=user, name='Spend less on food', amount=1000) for j in range(51): TransactionFactory.create(goals=[goal], institution=bofa, name=fake.bs(), amount=fake.pydecimal(left_digits=3, right_digits=2), post_date=fake.date_time_this_month()) goal.save() print('Created goal `{}` with `{}` Transactions'.format(goal.name, 30))
def setUp(self): super().setUp() self.access_token = AccessTokenFactory.create() self.user = self.access_token.user self.token = generate_token_for_user(self.user) self.institution = self.access_token.institution self.transaction = TransactionFactory.create( user=self.user, institution=self.institution) self.deleted_user = UserFactory.create() self.nonexistent_token = generate_token_for_user(self.deleted_user) self.deleted_user.delete()
def test_cannot_confirm_for_models_with_clean_overridden_if_clean_fails( self): shop = ShopFactory() item = ItemFactory() InventoryFactory(shop=shop, item=item, quantity=1) transaction = TransactionFactory(shop=shop) # Asking to buy more than the shop has in stock data = { "transaction": transaction.id, "item": item.id, "quantity": 9, "currency": "USD", "total": 10.00, "_confirm_add": True, "_save": True, } response = self.client.post(reverse("admin:market_itemsale_add"), data) # Should not have been added yet self.assertEqual(ItemSale.objects.count(), 0) # Ensure it shows the form and not the confirmation page self.assertEqual(response.status_code, 200) expected_templates = [ "admin/market/itemsale/change_form.html", "admin/market/change_form.html", "admin/change_form.html", ] self.assertEqual(response.template_name, expected_templates) self.assertTrue("error" in str(response.content)) self.assertTrue("Shop does not have enough of the item stocked" in str( response.content)) # Should still be asking for confirmation self.assertIn(CONFIRM_ADD, response.rendered_content) # Fix the issue by buying only what shop has in stock data["quantity"] = 1 # _confirm_add would still be in the POST data response = self.client.post(reverse("admin:market_itemsale_add"), data) # Should show confirmation page # Ensure not redirected (confirmation page does not redirect) self.assertEqual(response.status_code, 200) expected_templates = [ "admin/market/itemsale/change_confirmation.html", "admin/market/change_confirmation.html", "admin/change_confirmation.html", ] self.assertEqual(response.template_name, expected_templates) self._assertSubmitHtml(rendered_content=response.rendered_content)
def test_get_transactions_filter_date(self): """get_transactions: check if corrent number of transactions are returned when filtering by date. """ # given transactions = [ TransactionFactory(transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime(2020, 12, 15)), TransactionFactory(transaction_type=TransactionTypeEnum.deposit, transaction_date=datetime(2020, 12, 16)), TransactionFactory(transaction_type=TransactionTypeEnum.deposit, transaction_date=datetime(2020, 12, 19)) ] account = self.create_account(transactions=transactions) # when filters = Filters(_from='2020-12-12', _to='2020-12-18') query = get_transactions(account.id, filters=filters) # then self.assertEqual(2, query.count())
def test_get_statement_filter_by_period(self): """get: check if statement with transactions per period is received for a valid account """ # given transactions = [ TransactionFactory(transaction_date=datetime(2020, 12, 15)), TransactionFactory(transaction_date=datetime(2020, 12, 16)), TransactionFactory(transaction_date=datetime(2020, 12, 19)) ] account = self.create_account(transactions=transactions) # when response = self.app.test_client().get( f'/accounts/statement/{account.id}?from=2020-12-14&to=2020-12-17', ) response_data = json.loads(response.data) # then self.assert200(response) self.assertEqual(len(response_data['transactions']), 2) self.assertEqual(response_data['id'], account.id)
def test_get_transactions_with_no_institution_should_succeed(self): other_transaction = TransactionFactory.create(user=self.user) url = url_for('transactions_api.get_transactions') headers = self.create_headers(user=self.user) response = self.request_endpoint('GET', url, headers, status.HTTP_200_OK) self.assertListEqual( json.loads(response.data.decode('utf-8'))['transactions'], list( map(snake_to_camel_case_dict, [ self.transaction.serialize(), other_transaction.serialize() ])))
def test_get_today_withdraws(self): """get_today_withdraws: check if only current date withdraws are returned. """ # given value = Decimal("5.00") transactions = [ TransactionFactory(transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=value), TransactionFactory(transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=value), TransactionFactory(transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime(2020, 12, 19), value=value) ] account = self.create_account(transactions=transactions) # when current_total = get_today_withdraws(account.id) # then self.assertEqual(2 * value, current_total)
def test_get_transactions_no_filters(self): """get_transactions: check if all account transactions are returned when no filter is provided. """ # given number_transactions = 2 account = self.create_account( balance=Decimal("20.00"), transactions=TransactionFactory.create_batch(number_transactions)) # when query = get_transactions(account.id) # then self.assertEqual(number_transactions, query.count())
def test_confirm_change_of_datetime_and_date_field(self): transaction = TransactionFactory() original_date = transaction.date original_timestamp = transaction.timestamp data = { "id": transaction.id, "date": "2021-01-01", "timestamp_0": "2021-01-01", "timestamp_1": "12:30:00", "currency": "USD", "shop": transaction.shop.id, "total": 0, "_confirm_change": True, "csrfmiddlewaretoken": "fake token", "_continue": True, } response = self.client.post( f"/admin/market/transaction/{transaction.id}/change/", data ) # Ensure not redirected (confirmation page does not redirect) self.assertEqual(response.status_code, 200) expected_templates = [ "admin/market/transaction/change_confirmation.html", "admin/market/change_confirmation.html", "admin/change_confirmation.html", ] self.assertEqual(response.template_name, expected_templates) self._assertSubmitHtml( rendered_content=response.rendered_content, save_action="_continue" ) # Hasn't changed item yet transaction.refresh_from_db() self.assertEqual(transaction.date, original_date) self.assertEqual(transaction.timestamp, original_timestamp) # Selecting to "Yes, I'm sure" on the confirmation page # Would post to the same endpoint del data["_confirm_change"] response = self.client.post( f"/admin/market/transaction/{transaction.id}/change/", data ) # will show the change page for this transaction self.assertEqual(response.status_code, 302) self.assertEqual( response.url, f"/admin/market/transaction/{transaction.id}/change/" ) # Should not be the confirmation page, we already confirmed change self.assertNotEqual(response.templates, expected_templates) self.assertEqual(Transaction.objects.count(), 1) transaction.refresh_from_db() self.assertEqual(str(transaction.date), "2021-01-01") self.assertEqual(str(transaction.timestamp.date()), "2021-01-01") self.assertEqual(str(transaction.timestamp.time()), "12:30:00")
def test_get_statement(self): """get: check if statement is received for a valid account""" # given number_transactions = 5 account = self.create_account( transactions=TransactionFactory.create_batch(number_transactions) ) # when response = self.app.test_client().get( f'/accounts/statement/{account.id}', ) response_data = json.loads(response.data) # then self.assert200(response) self.assertEqual(len(response_data['transactions']), len(account.transactions)) self.assertEqual(response_data['id'], account.id)
def test_withdraw(self, mock_withdraws): """withdraw: check if withdraw operation is successfully executed.""" # given mock_withdraws.return_value = Decimal("20.00") transaction = TransactionFactory( transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=Decimal("10.00"), ) account = self.create_account(balance=Decimal("50.00"), transactions=[transaction], daily_withdraw_limit=Decimal("30.00")) # when withdraw(transaction) # then self.assertEqual(account.balance, Decimal("40.00"))
def test_can_confirm_for_models_with_validator_on_model_field( self, _mock_clean): # ItemSale.currency has a validator on it item = ItemFactory() transaction = TransactionFactory() data = { "transaction": transaction.id, "item": item.id, "quantity": 1, "currency": "USD", "total": 10.00, "_confirm_add": True, "_save": True, } response = self.client.post(reverse("admin:market_itemsale_add"), data) # Should not have been added yet self.assertEqual(ItemSale.objects.count(), 0) # Ensure not redirected (confirmation page does not redirect) self.assertEqual(response.status_code, 200) expected_templates = [ "admin/market/itemsale/change_confirmation.html", "admin/market/change_confirmation.html", "admin/change_confirmation.html", ] self.assertEqual(response.template_name, expected_templates) self._assertSubmitHtml(rendered_content=response.rendered_content) # Confirmation page would not have the _confirm_add sent on submit del data["_confirm_add"] # Selecting to "Yes, I'm sure" on the confirmation page # Would post to the same endpoint response = self.client.post(reverse("admin:market_itemsale_add"), data) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, "/admin/market/itemsale/") self.assertEqual(ItemSale.objects.count(), 1) # Ensure that the date and timestamp saved correctly item_sale = ItemSale.objects.first() self.assertEqual(item_sale.transaction, transaction) self.assertEqual(item_sale.item, item) self.assertEqual(item_sale.currency, "USD")
def test_withdraw_insuficient_funds(self, mock_withdraws): """withdraw: check if exception is raised when there's no enough funds. """ # given mock_withdraws.return_value = Decimal("0.00") account = self.create_account(balance=Decimal("20.00"), daily_withdraw_limit=Decimal("30.00")) transaction = TransactionFactory( transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=Decimal("30.00"), account=account) # when with self.assertRaises(ApiException) as error_context: withdraw(transaction) # then exception = error_context.exception self.assertEqual(exception.errors, AccountFailures.insufficiente_funds)
def test_withdraw_blocked_acount(self, mock_withdraws): """withdraw: check if exception is raised when trying to take money from a blocked account. """ # given mock_withdraws.return_value = Decimal("0.00") account = self.create_account(daily_withdraw_limit=Decimal("30.00"), active_flag=False) transaction = TransactionFactory( transaction_type=TransactionTypeEnum.withdraw, transaction_date=datetime.today(), value=Decimal("1.00"), account=account) # when with self.assertRaises(ApiException) as error_context: withdraw(transaction) # then exception = error_context.exception self.assertEqual(exception.errors, AccountFailures.blocked_account)
def test_should_delete_transactions_belonging_to_it(self): institution = TransactionFactory.create().institution institution.delete() self.assertEqual(Institution.query.count(), 0) self.assertEqual(Transaction.query.count(), 0)
def transaction_factory(session): yield TransactionFactory(session)