Commit 1b8ce00b by E. Kolpakov

Tests for multiple blocks on page

parent b67d97be
{
"zones": [
{
"index": 1,
"width": 200,
"title": "Zone 51",
"height": 100,
"y": "400",
"x": "200",
"id": "zone-51"
},
{
"index": 2,
"width": 200,
"title": "Zone 52",
"height": 100,
"y": "200",
"x": "100",
"id": "zone-52"
}
],
"items": [
{
"displayName": "Item 1",
"feedback": {
"incorrect": "Incorrect 1",
"correct": "Correct 1"
},
"zone": "Zone 51",
"backgroundImage": "",
"id": 10
},
{
"displayName": "Item 2",
"feedback": {
"incorrect": "Incorrect 2",
"correct": "Correct 2"
},
"zone": "Zone 52",
"backgroundImage": "",
"id": 20,
"inputOptions": {
"value": 100,
"margin": 5
}
},
{
"displayName": "X",
"feedback": {
"incorrect": "No Zone for this",
"correct": ""
},
"zone": "none",
"backgroundImage": "",
"id": 30
}
],
"feedback": {
"start": "Some Intro Feed",
"finish": "Some Final Feed"
}
}
from selenium.webdriver import ActionChains from selenium.webdriver import ActionChains
from .test_base import BaseIntegrationTest from .test_base import BaseIntegrationTest
from ..utils import load_resource
class ItemDefinition(object): class ItemDefinition(object):
...@@ -12,38 +13,16 @@ class ItemDefinition(object): ...@@ -12,38 +13,16 @@ class ItemDefinition(object):
self.input = input_value self.input = input_value
class InteractionTestFixture(object): class InteractionTestBase(object):
"""
Verifying Drag and Drop XBlock rendering against default data - if default data changes this would probably broke
"""
PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2'
items_map = {
0: ItemDefinition(0, 'Zone 1', "Yes, it's a 1", "No, 1 does not belong here"),
1: ItemDefinition(1, 'Zone 2', "Yes, it's a 2", "No, 2 does not belong here"),
2: ItemDefinition(2, None, "", "You silly, there are no zones for X")
}
all_zones = ['Zone 1', 'Zone 2']
feedback = {
"intro": "Drag the items onto the image above.",
"final": "Good work! You have completed this drag and drop exercise."
}
def _get_scenario_xml(self): # pylint: disable=no-self-use
return "<vertical_demo><drag-and-drop-v2/></vertical_demo>"
@classmethod @classmethod
def _get_correct_item_for_zone(cls): def _get_correct_item_for_zone(cls, items_map):
return { return {
item_key: definition for item_key, definition in cls.items_map.items() item_key: definition for item_key, definition in items_map.items()
if definition.zone_id is not None if definition.zone_id is not None
} }
def setUp(self): def setUp(self):
super(InteractionTestFixture, self).setUp() super(InteractionTestBase, self).setUp()
scenario_xml = self._get_scenario_xml() scenario_xml = self._get_scenario_xml()
self._add_scenario(self.PAGE_ID, self.PAGE_TITLE, scenario_xml) self._add_scenario(self.PAGE_ID, self.PAGE_TITLE, scenario_xml)
...@@ -70,25 +49,32 @@ class InteractionTestFixture(object): ...@@ -70,25 +49,32 @@ class InteractionTestFixture(object):
element.find_element_by_class_name('input').send_keys(value) element.find_element_by_class_name('input').send_keys(value)
element.find_element_by_class_name('submit-input').click() element.find_element_by_class_name('submit-input').click()
def get_feedback_popup(self):
return self._page.find_element_by_css_selector(".popup-content")
def get_reset_button(self):
return self._page.find_element_by_css_selector('.reset-button')
def drag_item_to_zone(self, item_value, zone_id): def drag_item_to_zone(self, item_value, zone_id):
element = self._get_item_by_value(item_value) element = self._get_item_by_value(item_value)
target = self._get_zone_by_id(zone_id) target = self._get_zone_by_id(zone_id)
action_chains = ActionChains(self.browser) action_chains = ActionChains(self.browser)
action_chains.drag_and_drop(element, target).perform() action_chains.drag_and_drop(element, target).perform()
def test_item_positive_feedback_on_good_move(self): def parameterized_item_positive_feedback_on_good_move(self, items_map, scroll_down=100):
# Scroll drop zones into view to make sure Selenium can successfully drop items # Scroll drop zones into view to make sure Selenium can successfully drop items
self.scroll_down(pixels=100) self.scroll_down(pixels=scroll_down)
for definition in self._get_correct_item_for_zone().values(): for definition in self._get_correct_item_for_zone(items_map).values():
if not definition.input: if not definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) self.drag_item_to_zone(definition.item_id, definition.zone_id)
feedback_popup = self._page.find_element_by_css_selector(".popup-content") feedback_popup = self.get_feedback_popup()
self.wait_until_html_in(definition.feedback_positive, feedback_popup) self.wait_until_html_in(definition.feedback_positive, feedback_popup)
def test_item_positive_feedback_on_good_input(self): def parameterized_item_positive_feedback_on_good_input(self, items_map, scroll_down=100):
feedback_popup = self._page.find_element_by_css_selector(".popup-content") self.scroll_down(pixels=scroll_down)
for definition in self._get_correct_item_for_zone().values(): feedback_popup = self.get_feedback_popup()
for definition in self._get_correct_item_for_zone(items_map).values():
if definition.input: if definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) self.drag_item_to_zone(definition.item_id, definition.zone_id)
self._send_input(definition.item_id, definition.input) self._send_input(definition.item_id, definition.input)
...@@ -96,26 +82,26 @@ class InteractionTestFixture(object): ...@@ -96,26 +82,26 @@ class InteractionTestFixture(object):
self.wait_until_has_class('correct', input_div) self.wait_until_has_class('correct', input_div)
self.wait_until_html_in(definition.feedback_positive, feedback_popup) self.wait_until_html_in(definition.feedback_positive, feedback_popup)
def test_item_negative_feedback_on_bad_move(self): def parameterized_item_negative_feedback_on_bad_move(self, items_map, all_zones, scroll_down=100):
feedback_popup = self._page.find_element_by_css_selector(".popup-content") feedback_popup = self.get_feedback_popup()
# Scroll drop zones into view to make sure Selenium can successfully drop items # Scroll drop zones into view to make sure Selenium can successfully drop items
self.scroll_down(pixels=100) self.scroll_down(pixels=scroll_down)
for definition in self.items_map.values(): for definition in items_map.values():
for zone in self.all_zones: for zone in all_zones:
if zone == definition.zone_id: if zone == definition.zone_id:
continue continue
self.drag_item_to_zone(definition.item_id, zone) self.drag_item_to_zone(definition.item_id, zone)
self.wait_until_html_in(definition.feedback_negative, feedback_popup) self.wait_until_html_in(definition.feedback_negative, feedback_popup)
def test_item_positive_feedback_on_bad_input(self): def parameterized_item_positive_feedback_on_bad_input(self, items_map, scroll_down=100):
feedback_popup = self._page.find_element_by_css_selector(".popup-content") feedback_popup = self.get_feedback_popup()
# Scroll drop zones into view to make sure Selenium can successfully drop items # Scroll drop zones into view to make sure Selenium can successfully drop items
self.scroll_down(pixels=100) self.scroll_down(pixels=scroll_down)
for definition in self._get_correct_item_for_zone().values(): for definition in self._get_correct_item_for_zone(items_map).values():
if definition.input: if definition.input:
self.drag_item_to_zone(definition.item_id, definition.zone_id) self.drag_item_to_zone(definition.item_id, definition.zone_id)
self._send_input(definition.item_id, '1999999') self._send_input(definition.item_id, '1999999')
...@@ -123,11 +109,11 @@ class InteractionTestFixture(object): ...@@ -123,11 +109,11 @@ class InteractionTestFixture(object):
self.wait_until_has_class('incorrect', input_div) self.wait_until_has_class('incorrect', input_div)
self.wait_until_html_in(definition.feedback_negative, feedback_popup) self.wait_until_html_in(definition.feedback_negative, feedback_popup)
def test_final_feedback_and_reset(self): def parameterized_final_feedback_and_reset(self, items_map, feedback, scroll_down=100):
feedback_message = self._get_feedback_message() feedback_message = self._get_feedback_message()
self.assertEqual(self.get_element_html(feedback_message), self.feedback['intro']) # precondition check self.assertEqual(self.get_element_html(feedback_message), feedback['intro']) # precondition check
items = self._get_correct_item_for_zone() items = self._get_correct_item_for_zone(items_map)
def get_locations(): def get_locations():
return {item_id: self._get_item_by_value(item_id).location for item_id in items.keys()} return {item_id: self._get_item_by_value(item_id).location for item_id in items.keys()}
...@@ -135,7 +121,7 @@ class InteractionTestFixture(object): ...@@ -135,7 +121,7 @@ class InteractionTestFixture(object):
initial_locations = get_locations() initial_locations = get_locations()
# Scroll drop zones into view to make sure Selenium can successfully drop items # Scroll drop zones into view to make sure Selenium can successfully drop items
self.scroll_down(pixels=100) self.scroll_down(pixels=scroll_down)
for item_key, definition in items.items(): for item_key, definition in items.items():
self.drag_item_to_zone(item_key, definition.zone_id) self.drag_item_to_zone(item_key, definition.zone_id)
...@@ -144,21 +130,60 @@ class InteractionTestFixture(object): ...@@ -144,21 +130,60 @@ class InteractionTestFixture(object):
input_div = self._get_input_div_by_value(item_key) input_div = self._get_input_div_by_value(item_key)
self.wait_until_has_class('correct', input_div) self.wait_until_has_class('correct', input_div)
self.wait_until_html_in(self.feedback['final'], self._get_feedback_message()) self.wait_until_html_in(feedback['final'], self._get_feedback_message())
# Scroll "Reset exercise" button into view to make sure Selenium can successfully click it # Scroll "Reset exercise" button into view to make sure Selenium can successfully click it
self.scroll_down(pixels=250) self.scroll_down(pixels=scroll_down+150)
reset = self._page.find_element_by_css_selector('.reset-button') reset = self.get_reset_button()
reset.click() reset.click()
self.wait_until_html_in(self.feedback['intro'], self._get_feedback_message()) self.wait_until_html_in(feedback['intro'], self._get_feedback_message())
locations_after_reset = get_locations() locations_after_reset = get_locations()
for item_key in items.keys(): for item_key in items.keys():
self.assertDictEqual(locations_after_reset[item_key], initial_locations[item_key]) self.assertDictEqual(locations_after_reset[item_key], initial_locations[item_key])
class InteractionTestFixture(InteractionTestBase):
"""
Verifying Drag and Drop XBlock rendering against default data - if default data changes this would probably broke
"""
PAGE_TITLE = 'Drag and Drop v2'
PAGE_ID = 'drag_and_drop_v2'
items_map = {
0: ItemDefinition(0, 'Zone 1', "Yes, it's a 1", "No, 1 does not belong here"),
1: ItemDefinition(1, 'Zone 2', "Yes, it's a 2", "No, 2 does not belong here"),
2: ItemDefinition(2, None, "", "You silly, there are no zones for X")
}
all_zones = ['Zone 1', 'Zone 2']
feedback = {
"intro": "Drag the items onto the image above.",
"final": "Good work! You have completed this drag and drop exercise."
}
def _get_scenario_xml(self): # pylint: disable=no-self-use
return "<vertical_demo><drag-and-drop-v2/></vertical_demo>"
def test_item_positive_feedback_on_good_move(self):
self.parameterized_item_positive_feedback_on_good_move(self.items_map)
def test_item_positive_feedback_on_good_input(self):
self.parameterized_item_positive_feedback_on_good_input(self.items_map)
def test_item_negative_feedback_on_bad_move(self):
self.parameterized_item_negative_feedback_on_bad_move(self.items_map, self.all_zones)
def test_item_positive_feedback_on_bad_input(self):
self.parameterized_item_positive_feedback_on_bad_input(self.items_map)
def test_final_feedback_and_reset(self):
self.parameterized_final_feedback_and_reset(self.items_map, self.feedback)
class CustomDataInteractionTest(InteractionTestFixture, BaseIntegrationTest): class CustomDataInteractionTest(InteractionTestFixture, BaseIntegrationTest):
items_map = { items_map = {
0: ItemDefinition(0, 'Zone 1', "Yes 1", "No 1"), 0: ItemDefinition(0, 'Zone 1', "Yes 1", "No 1"),
...@@ -193,3 +218,78 @@ class CustomHtmlDataInteractionTest(InteractionTestFixture, BaseIntegrationTest) ...@@ -193,3 +218,78 @@ class CustomHtmlDataInteractionTest(InteractionTestFixture, BaseIntegrationTest)
def _get_scenario_xml(self): def _get_scenario_xml(self):
return self._get_custom_scenario_xml("integration/data/test_html_data.json") return self._get_custom_scenario_xml("integration/data/test_html_data.json")
class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
PAGE_TITLE = 'Drag and Drop v2 Multiple Blocks'
PAGE_ID = 'drag_and_drop_v2_multi'
BLOCK1_DATA_FILE = "integration/data/test_data.json"
BLOCK2_DATA_FILE = "integration/data/test_data_other.json"
item_maps = {
'block1': {
0: ItemDefinition(0, 'Zone 1', "Yes 1", "No 1"),
1: ItemDefinition(1, 'Zone 2', "Yes 2", "No 2", "102"),
2: ItemDefinition(2, None, "", "No Zone for this")
},
'block2': {
10: ItemDefinition(10, 'Zone 51', "Correct 1", "Incorrect 1"),
20: ItemDefinition(20, 'Zone 52', "Correct 2", "Incorrect 2", "102"),
30: ItemDefinition(30, None, "", "No Zone for this")
},
}
all_zones = {
'block1': ['Zone 1', 'Zone 2'],
'block2': ['Zone 51', 'Zone 52']
}
feedback = {
'block1': {"intro": "Other Intro Feed", "final": "Other Final Feed"},
'block2': {"intro": "Some Intro Feed", "final": "Some Final Feed"},
}
def _get_scenario_xml(self):
blocks_xml = "\n".join([
"<drag-and-drop-v2 data='{data}'/>".format(data=load_resource(filename))
for filename in (self.BLOCK1_DATA_FILE, self.BLOCK2_DATA_FILE)
])
return "<vertical_demo>{dnd_blocks}</vertical_demo>".format(dnd_blocks=blocks_xml)
def _switch_to_block(self, idx):
self._page = self.browser.find_elements_by_css_selector(self.default_css_selector)[idx]
self.scroll_down(0)
def test_item_positive_feedback_on_good_move(self):
self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_good_move(self.item_maps['block1'])
self._switch_to_block(1)
self.parameterized_item_positive_feedback_on_good_move(self.item_maps['block2'], scroll_down=900)
def test_item_positive_feedback_on_good_input(self):
self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_good_input(self.item_maps['block1'])
self._switch_to_block(1)
self.parameterized_item_positive_feedback_on_good_input(self.item_maps['block2'], scroll_down=900)
def test_item_negative_feedback_on_bad_move(self):
self._switch_to_block(0)
self.parameterized_item_negative_feedback_on_bad_move(self.item_maps['block1'], self.all_zones['block1'])
self._switch_to_block(1)
self.parameterized_item_negative_feedback_on_bad_move(
self.item_maps['block2'], self.all_zones['block2'], scroll_down=900
)
def test_item_positive_feedback_on_bad_input(self):
self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_bad_input(self.item_maps['block1'])
self._switch_to_block(1)
self.parameterized_item_positive_feedback_on_bad_input(self.item_maps['block2'], scroll_down=900)
def test_final_feedback_and_reset(self):
self._switch_to_block(0)
self.parameterized_final_feedback_and_reset(self.item_maps['block1'], self.feedback['block1'])
self._switch_to_block(1)
self.parameterized_final_feedback_and_reset(self.item_maps['block2'], self.feedback['block2'], scroll_down=900)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment