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