Files
edx-platform/lms/djangoapps/instructor/tests/test_ecommerce.py
2019-12-30 12:25:38 -05:00

412 lines
17 KiB
Python

"""
Unit tests for Ecommerce feature flag in new instructor dashboard.
"""
import datetime
import pytz
import six
from django.urls import reverse
from six import text_type
from course_modes.models import CourseMode
from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin
from shoppingcart.models import Coupon, CourseRegistrationCode
from student.roles import CourseFinanceAdminRole
from student.tests.factories import AdminFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
class TestECommerceDashboardViews(SiteMixin, SharedModuleStoreTestCase):
"""
Check for E-commerce view on the new instructor dashboard
"""
@classmethod
def setUpClass(cls):
super(TestECommerceDashboardViews, cls).setUpClass()
cls.course = CourseFactory.create()
# URL for instructor dash
cls.url = reverse('instructor_dashboard', kwargs={'course_id': text_type(cls.course.id)})
cls.ecommerce_link = '<button type="button" class="btn-link e-commerce" data-section="e-commerce">E-Commerce</button>'
def setUp(self):
super(TestECommerceDashboardViews, self).setUp()
# Create instructor account
self.instructor = AdminFactory.create()
self.client.login(username=self.instructor.username, password="test")
mode = CourseMode(
course_id=text_type(self.course.id), mode_slug='honor',
mode_display_name='honor', min_price=10, currency='usd'
)
mode.save()
CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
def test_pass_e_commerce_tab_in_instructor_dashboard(self):
"""
Test Pass E-commerce Tab is in the Instructor Dashboard
"""
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
# Coupons should show up for White Label sites with priced honor modes.
self.assertContains(response, 'Coupon Code List')
def test_reports_section_under_e_commerce_tab(self):
"""
Test reports section, under E-commerce Tab, is in the Instructor Dashboard
"""
self.use_site(site=self.site_other)
self.client.login(username=self.instructor.username, password="test")
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
self.assertContains(response, 'Create Enrollment Report')
def test_reports_section_not_under_e_commerce_tab(self):
"""
Test reports section, under E-commerce Tab, should not be available in the Instructor Dashboard with default
value
"""
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
self.assertNotContains(response, 'Create Enrollment Report')
def test_user_has_finance_admin_rights_in_e_commerce_tab(self):
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
# Order/Invoice sales csv button text should render in e-commerce page
self.assertContains(response, 'Total Credit Card Purchases')
self.assertContains(response, 'Download All Credit Card Purchases')
self.assertContains(response, 'Download All Invoices')
# removing the course finance_admin role of login user
CourseFinanceAdminRole(self.course.id).remove_users(self.instructor)
# Order/Invoice sales csv button text should not be visible in e-commerce page if the user is not finance admin
url = reverse('instructor_dashboard', kwargs={'course_id': text_type(self.course.id)})
response = self.client.post(url)
self.assertNotContains(response, 'Download All Invoices')
def test_user_view_course_price(self):
"""
test to check if the user views the set price button and price in
the instructor dashboard
"""
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
# Total amount html should render in e-commerce page, total amount will be 0
course_honor_mode = CourseMode.mode_for_course(self.course.id, 'honor')
price = course_honor_mode.min_price
self.assertContains(response, 'Course price per seat: <span>$' + str(price) + '</span>')
self.assertNotContains(response, '+ Set Price</a></span>')
# removing the course finance_admin role of login user
CourseFinanceAdminRole(self.course.id).remove_users(self.instructor)
# total amount should not be visible in e-commerce page if the user is not finance admin
url = reverse('instructor_dashboard', kwargs={'course_id': text_type(self.course.id)})
response = self.client.get(url)
self.assertNotContains(response, '+ Set Price</a></span>')
def test_update_course_price_check(self):
price = 200
# course B
course2 = CourseFactory.create(org='EDX', display_name='test_course', number='100')
mode = CourseMode(
course_id=text_type(course2.id), mode_slug='honor',
mode_display_name='honor', min_price=30, currency='usd'
)
mode.save()
# course A update
CourseMode.objects.filter(course_id=self.course.id).update(min_price=price)
set_course_price_url = reverse('set_course_mode_price', kwargs={'course_id': text_type(self.course.id)})
data = {'course_price': price, 'currency': 'usd'}
response = self.client.post(set_course_price_url, data)
self.assertContains(response, 'CourseMode price updated successfully')
# Course A updated total amount should be visible in e-commerce page if the user is finance admin
url = reverse('instructor_dashboard', kwargs={'course_id': text_type(self.course.id)})
response = self.client.get(url)
self.assertContains(response, 'Course price per seat: <span>$' + str(price) + '</span>')
def test_user_admin_set_course_price(self):
"""
test to set the course price related functionality.
test al the scenarios for setting a new course price
"""
set_course_price_url = reverse('set_course_mode_price', kwargs={'course_id': text_type(self.course.id)})
data = {'course_price': '12%', 'currency': 'usd'}
# Value Error course price should be a numeric value
response = self.client.post(set_course_price_url, data)
self.assertContains(response, "Please Enter the numeric value for the course price", status_code=400)
# validation check passes and course price is successfully added
data['course_price'] = 100
response = self.client.post(set_course_price_url, data)
self.assertContains(response, "CourseMode price updated successfully")
course_honor_mode = CourseMode.objects.get(mode_slug='honor')
course_honor_mode.delete()
# Course Mode not exist with mode slug honor
response = self.client.post(set_course_price_url, data)
self.assertContains(
response,
u"CourseMode with the mode slug({mode_slug}) DoesNotExist".format(mode_slug='honor'),
status_code=400,
)
def test_add_coupon(self):
"""
Test Add Coupon Scenarios. Handle all the HttpResponses return by add_coupon view
"""
# URL for add_coupon
add_coupon_url = reverse('add_coupon', kwargs={'course_id': text_type(self.course.id)})
expiration_date = datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=2)
data = {
'code': 'A2314', 'course_id': text_type(self.course.id),
'description': 'ADSADASDSAD', 'created_by': self.instructor, 'discount': 5,
'expiration_date': '{month}/{day}/{year}'.format(
month=expiration_date.month, day=expiration_date.day, year=expiration_date.year
)
}
response = self.client.post(add_coupon_url, data)
self.assertContains(
response,
u"coupon with the coupon code ({code}) added successfully".format(code=data['code']),
)
#now add the coupon with the wrong value in the expiration_date
# server will through the ValueError Exception in the expiration_date field
data = {
'code': '213454', 'course_id': text_type(self.course.id),
'description': 'ADSADASDSAD', 'created_by': self.instructor, 'discount': 5,
'expiration_date': expiration_date.strftime('"%d/%m/%Y')
}
response = self.client.post(add_coupon_url, data)
self.assertContains(
response,
"Please enter the date in this format i-e month/day/year",
status_code=400,
)
data = {
'code': 'A2314', 'course_id': text_type(self.course.id),
'description': 'asdsasda', 'created_by': self.instructor, 'discount': 99
}
response = self.client.post(add_coupon_url, data)
self.assertContains(
response,
u"coupon with the coupon code ({code}) already exist".format(code='A2314'),
status_code=400,
)
response = self.client.post(self.url)
self.assertContains(response, '<td>ADSADASDSAD</td>')
self.assertContains(response, '<td>A2314</td>')
self.assertNotContains(response, '<td>111</td>')
data = {
'code': 'A2345314', 'course_id': text_type(self.course.id),
'description': 'asdsasda', 'created_by': self.instructor, 'discount': 199
}
response = self.client.post(add_coupon_url, data)
self.assertContains(
response,
"Please Enter the Coupon Discount Value Less than or Equal to 100",
status_code=400,
)
data['discount'] = '25%'
response = self.client.post(add_coupon_url, data=data)
self.assertContains(response, 'Please Enter the Integer Value for Coupon Discount', status_code=400)
course_registration = CourseRegistrationCode(
code='Vs23Ws4j', course_id=text_type(self.course.id), created_by=self.instructor,
mode_slug='honor'
)
course_registration.save()
data['code'] = 'Vs23Ws4j'
response = self.client.post(add_coupon_url, data)
msg = u"The code ({code}) that you have tried to define is already in use as a registration code"
self.assertContains(response, msg.format(code=data['code']), status_code=400)
def test_delete_coupon(self):
"""
Test Delete Coupon Scenarios. Handle all the HttpResponses return by remove_coupon view
"""
coupon = Coupon(
code='AS452', description='asdsadsa', course_id=text_type(self.course.id),
percentage_discount=10, created_by=self.instructor
)
coupon.save()
response = self.client.post(self.url)
self.assertContains(response, '<td>AS452</td>')
# URL for remove_coupon
delete_coupon_url = reverse('remove_coupon', kwargs={'course_id': text_type(self.course.id)})
response = self.client.post(delete_coupon_url, {'id': coupon.id})
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) updated successfully'.format(coupon_id=coupon.id),
)
coupon.is_active = False
coupon.save()
response = self.client.post(delete_coupon_url, {'id': coupon.id})
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) is already inactive'.format(coupon_id=coupon.id),
status_code=400,
)
response = self.client.post(delete_coupon_url, {'id': 24454})
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=24454),
status_code=400,
)
response = self.client.post(delete_coupon_url, {'id': ''})
self.assertContains(response, 'coupon id is None', status_code=400)
def test_get_coupon_info(self):
"""
Test Edit Coupon Info Scenarios. Handle all the HttpResponses return by edit_coupon_info view
"""
coupon = Coupon(
code='AS452', description='asdsadsa', course_id=text_type(self.course.id),
percentage_discount=10, created_by=self.instructor,
expiration_date=datetime.datetime.now(pytz.UTC) + datetime.timedelta(days=2)
)
coupon.save()
# URL for edit_coupon_info
edit_url = reverse('get_coupon_info', kwargs={'course_id': text_type(self.course.id)})
response = self.client.post(edit_url, {'id': coupon.id})
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) updated successfully'.format(coupon_id=coupon.id),
)
self.assertContains(response, coupon.display_expiry_date)
response = self.client.post(edit_url, {'id': 444444})
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=444444),
status_code=400,
)
response = self.client.post(edit_url, {'id': ''})
self.assertContains(response, 'coupon id not found"', status_code=400)
coupon.is_active = False
coupon.save()
response = self.client.post(edit_url, {'id': coupon.id})
self.assertContains(
response,
u"coupon with the coupon id ({coupon_id}) is already inactive".format(coupon_id=coupon.id),
status_code=400,
)
def test_update_coupon(self):
"""
Test Update Coupon Info Scenarios. Handle all the HttpResponses return by update_coupon view
"""
coupon = Coupon(
code='AS452', description='asdsadsa', course_id=text_type(self.course.id),
percentage_discount=10, created_by=self.instructor
)
coupon.save()
response = self.client.post(self.url)
self.assertContains(response, '<td>AS452</td>')
data = {
'coupon_id': coupon.id, 'code': 'AS452', 'discount': '10', 'description': 'updated_description',
'course_id': text_type(coupon.course_id)
}
# URL for update_coupon
update_coupon_url = reverse('update_coupon', kwargs={'course_id': text_type(self.course.id)})
response = self.client.post(update_coupon_url, data=data)
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) updated Successfully'.format(coupon_id=coupon.id),
)
response = self.client.post(self.url)
self.assertContains(response, '<td>updated_description</td>')
data['coupon_id'] = 1000 # Coupon Not Exist with this ID
response = self.client.post(update_coupon_url, data=data)
self.assertContains(
response,
u'coupon with the coupon id ({coupon_id}) DoesNotExist'.format(coupon_id=1000),
status_code=400,
)
data['coupon_id'] = '' # Coupon id is not provided
response = self.client.post(update_coupon_url, data=data)
self.assertContains(response, 'coupon id not found', status_code=400)
def test_verified_course(self):
"""Verify the e-commerce panel shows up for verified courses as well, without Coupons """
# Change honor mode to verified.
original_mode = CourseMode.objects.get(course_id=self.course.id, mode_slug='honor')
original_mode.delete()
new_mode = CourseMode(
course_id=six.text_type(self.course.id), mode_slug='verified',
mode_display_name='verified', min_price=10, currency='usd'
)
new_mode.save()
# Get the response value, ensure the Coupon section is not included.
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
# Coupons should show up for White Label sites with priced honor modes.
self.assertNotContains(response, 'Coupons List')
def test_coupon_code_section_not_under_e_commerce_tab(self):
"""
Test Coupon Creation UI, under E-commerce Tab, should not be available in the Instructor Dashboard with
e-commerce course
"""
# Setup e-commerce course
CourseMode.objects.filter(course_id=self.course.id).update(sku='test_sku')
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
self.assertNotContains(response, 'Coupon Code List')
def test_enrollment_codes_section_not_under_e_commerce_tab(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should not be available in the Instructor Dashboard with
e-commerce course
"""
# Setup e-commerce course
CourseMode.objects.filter(course_id=self.course.id).update(sku='test_sku')
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
self.assertNotContains(response, '<h3 class="hd hd-3">Enrollment Codes</h3>')
def test_enrollment_codes_section_visible_for_non_ecommerce_course(self):
"""
Test Enrollment Codes UI, under E-commerce Tab, should be available in the Instructor Dashboard with non
e-commerce course
"""
response = self.client.get(self.url)
self.assertContains(response, self.ecommerce_link)
self.assertContains(response, '<h3 class="hd hd-3">Enrollment Codes</h3>')