From 103a825d51531adcd1787c0fb80312a84538c45a Mon Sep 17 00:00:00 2001 From: DawoudSheraz <dawoud.sheraz@arbisoft.com> Date: Tue, 6 Aug 2019 14:57:12 +0500 Subject: [PATCH] added DnD submission deadline acceptance tests --- common/test/acceptance/pages/lms/problem.py | 55 +++++++++ .../acceptance/tests/lms/test_lms_problems.py | 114 +++++++++++++++++- 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/common/test/acceptance/pages/lms/problem.py b/common/test/acceptance/pages/lms/problem.py index 3efa916ba48..6ee2cf9c381 100644 --- a/common/test/acceptance/pages/lms/problem.py +++ b/common/test/acceptance/pages/lms/problem.py @@ -4,6 +4,7 @@ Problem Page. from __future__ import absolute_import from bok_choy.page_object import PageObject +from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys from common.test.acceptance.pages.common.utils import click_css @@ -575,3 +576,57 @@ class ProblemPage(PageObject): Checks for the presence of the locator """ return self.q(css=selector).present + + +class DragAndDropPage(PageObject): + """ + View for a Drag & Drop problem. + """ + + url = None + + def is_browser_on_page(self): + return self.q(css='.xblock-student_view').present + + def is_submit_disabled(self): + """ + Checks if the submit button is disabled for Drag & Drop problem. + """ + disabled_attr = self.q(css='.submit-answer-button').attrs('disabled')[0] + return disabled_attr == 'true' + + def is_present(self, selector): + """ + Checks for the presence of the locator. + """ + return self.q(css=selector).present + + def is_submit_button_present(self): + """ + Verifies if the submit button is present for DnD problems + with assessment mode. + """ + return self.is_present('.submit-answer-button') + + def _get_item_by_value(self, item_value): + """ + Get the item that will be placed onto a zone. + """ + return self.q(xpath=(".//div[@data-value='{item_id}']".format(item_id=item_value)))[0] + + def _get_zone_by_id(self, zone_id): + """ + Get zone where the item will be placed. + """ + zones_container = self.browser.find_element_by_css_selector('.target') + return zones_container.find_elements_by_xpath(".//div[@data-uid='{zone_id}']".format(zone_id=zone_id))[0] + + def drag_item_to_zone(self, item_value, zone_id): + """ + Drag item to desired zone using mouse interaction. + """ + element = self._get_item_by_value(item_value) + target = self._get_zone_by_id(zone_id) + action_chains = ActionChains(self.browser) + action_chains.drag_and_drop(element, target).perform() + self.wait_for_ajax() diff --git a/common/test/acceptance/tests/lms/test_lms_problems.py b/common/test/acceptance/tests/lms/test_lms_problems.py index 9deeb06ae25..f3b1dd7a4be 100644 --- a/common/test/acceptance/tests/lms/test_lms_problems.py +++ b/common/test/acceptance/tests/lms/test_lms_problems.py @@ -5,6 +5,7 @@ Bok choy acceptance tests for problems in the LMS from __future__ import absolute_import import time +from datetime import datetime, timedelta from textwrap import dedent import ddt @@ -13,7 +14,7 @@ from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureD from common.test.acceptance.pages.common.auto_auth import AutoAuthPage from common.test.acceptance.pages.lms.courseware import CoursewarePage from common.test.acceptance.pages.lms.login_and_register import CombinedLoginAndRegisterPage -from common.test.acceptance.pages.lms.problem import ProblemPage +from common.test.acceptance.pages.lms.problem import ProblemPage, DragAndDropPage from common.test.acceptance.tests.helpers import EventsTestMixin, UniqueCourseTest from openedx.core.lib.tests import attr @@ -1087,3 +1088,114 @@ class FormulaProblemRandomizeTest(ProblemsTest): self.assertTrue(problem_page.is_reset_button_present()) problem_page.click_reset() self.assertEqual(problem_page.get_numerical_input_value, '') + + +@ddt.ddt +class DragAndDropXblockWithMixinsTest(UniqueCourseTest): + """ + Test Suite to verify various behaviors of DragAndDrop Xblock on the LMS. + """ + + def setUp(self): + super(DragAndDropXblockWithMixinsTest, self).setUp() + + self.username = "test_student_{uuid}".format(uuid=self.unique_id[0:8]) + self.email = "{username}@example.com".format(username=self.username) + self.password = "keep it secret; keep it safe." + self.courseware_page = CoursewarePage(self.browser, self.course_id) + + # Install a course with a hierarchy and problems + self.course_fixture = CourseFixture( + self.course_info['org'], self.course_info['number'], + self.course_info['run'], self.course_info['display_name'], + start_date=datetime.now() + timedelta(days=10) + ) + self.browser.set_window_size(1024, 1024) + + def setup_sequential(self, metadata): + """ + Setup a sequential with DnD problem, alongwith the metadata provided. + + This method will allow to customize the sequential, such as changing the + due date for individual tests. + """ + problem = self.get_problem() + sequential = self.get_sequential(metadata=metadata) + self.course_fixture.add_children( + XBlockFixtureDesc('chapter', 'Test Section').add_children( + sequential.add_children(problem) + ) + ).install() + + # Auto-auth register for the course. + AutoAuthPage( + self.browser, + username=self.username, + email=self.email, + password=self.password, + course_id=self.course_id, + staff=True + ).visit() + + def format_date(self, date_value): + """ + Get the date in isoformat as this is required format to add date data + in the sequential. + """ + return date_value.isoformat() + + def get_problem(self): + """ + Creating a DnD problem with assessment mode + """ + return XBlockFixtureDesc('drag-and-drop-v2', 'DnD', metadata={'mode': "assessment"}) + + def get_sequential(self, metadata=None): + return XBlockFixtureDesc('sequential', 'Test Subsection', metadata=metadata) + + @ddt.data( + (datetime.now(), True), + (datetime.now() - timedelta(days=1), True), + (datetime.now() + timedelta(days=1), False) + ) + @ddt.unpack + def test_submit_button_status_with_due_date(self, due_date, is_button_disabled): + """ + Scenario: Test that DnD submit button will be enabled if section is not past due. + + Given I have a sequential in instructor-paced course + And a DnD problem with assessment mode is present in the sequential + When I visit the problem + Then the submit button should be present + And button should be disabled as some item needs to be on a zone + When I drag an item to a zone + Then submit button will be enabled if due date has not passed, else disabled + """ + problem_page = DragAndDropPage(self.browser) + self.setup_sequential(metadata={'due': self.format_date(due_date)}) + self.courseware_page.visit() + self.assertTrue(problem_page.is_submit_button_present()) + self.assertTrue(problem_page.is_submit_disabled()) + problem_page.drag_item_to_zone(0, 'middle') + self.assertEqual(is_button_disabled, problem_page.is_submit_disabled()) + + def test_submit_button_when_pacing_change_self_paced(self): + """ + Scenario: For a self-paced course, the submit button of DnD problems will be + be enabled, regardless of the subsection due date. + + Given a DnD problem in a subsection with past due date + And the course is instructor-paced + Then the submit button will remain disabled after initial drag + When the pacing is changed to self-paced + Then the submit button is not disabled anymore + """ + problem_page = DragAndDropPage(self.browser) + self.setup_sequential(metadata={'due': self.format_date(datetime.now())}) + self.courseware_page.visit() + problem_page.drag_item_to_zone(0, 'middle') + self.assertTrue(problem_page.is_submit_disabled()) + self.course_fixture.add_course_details({'self_paced': True}) + self.course_fixture.configure_course() + self.courseware_page.visit() + self.assertFalse(problem_page.is_submit_disabled()) -- GitLab