Commit f0b0ec0c by Braden MacDonald

Partial implementation of new integration tests

parent 159bf51b
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 200 200" width="200px" height="200px" xml:space="preserve">
<style type="text/css">
.st0{fill:#FBB03B;stroke:#000000;stroke-miterlimit:10;}
.st1{font-family:'Helvetica';}
.st2{font-size:24px;}
</style>
<rect class="st0" width="200" height="200"/>
<text transform="matrix(1 0 0 1 34.6152 104.5322)" class="st1 st2">200 x 200px</text>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 400 300" width="400px" height="300px" xml:space="preserve">
<style type="text/css">
.st0{fill:#8CC63F;stroke:#000000;stroke-miterlimit:10;}
.st1{font-family:'Helvetica';}
.st2{font-size:48px;}
</style>
<rect class="st0" width="400" height="300"/>
<text transform="matrix(1 0 0 1 71 160)" class="st1 st2">400 x 300px</text>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 500 500" width="500px" height="500px" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#999999;}
.st2{fill:#F2F2F2;}
.st3{font-family:'Helvetica-Bold';}
.st4{font-size:24px;}
.st5{letter-spacing:-1;}
</style>
<g id="Layer_2">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="1.127" y1="250" x2="500" y2="250">
<stop offset="0" style="stop-color:#CCE0F4"/>
<stop offset="1" style="stop-color:#005B97"/>
</linearGradient>
<rect x="0" class="st0" width="500" height="500"/>
</g>
<g id="Layer_1">
<rect x="0" y="200" class="st1" width="250" height="100"/>
<rect x="0" y="400" class="st1" width="375" height="100"/>
<rect x="0" class="st1" width="166.7" height="100"/>
<text transform="matrix(1 0 0 1 36 58)" class="st2 st3 st4">&lt;- 1/3 -&gt;</text>
<text transform="matrix(1 0 0 1 74 260)"><tspan x="0" y="0" class="st2 st3 st4">&lt;-</tspan><tspan x="22" y="0" class="st2 st3 st4"> </tspan><tspan x="29.2" y="0" class="st2 st3 st4">50% -</tspan><tspan x="91.9" y="0" class="st2 st3 st4 st5">&gt;</tspan></text>
<text transform="matrix(1 0 0 1 150 455)"><tspan x="0" y="0" class="st2 st3 st4">&lt;-</tspan><tspan x="22" y="0" class="st2 st3 st4"> </tspan><tspan x="29.2" y="0" class="st2 st3 st4">75% -</tspan><tspan x="91.9" y="0" class="st2 st3 st4 st5">&gt;</tspan></text>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1600 900" width="1600px" height="900px" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#999999;}
.st2{fill:#F2F2F2;}
.st3{font-family:'Helvetica-Bold';}
.st4{font-size:60px;}
.st5{letter-spacing:1;}
.st6{letter-spacing:-3;}
</style>
<g id="Layer_2">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="1.127" y1="450" x2="1600" y2="450">
<stop offset="0" style="stop-color:#CCE0F4"/>
<stop offset="1" style="stop-color:#005B97"/>
</linearGradient>
<rect x="0" class="st0" width="1600" height="900"/>
</g>
<g id="Layer_1">
<rect y="350" class="st1" width="800" height="200"/>
<rect x="0" y="700" class="st1" width="1200" height="200"/>
<rect x="0" class="st1" width="533.33" height="200"/>
<text transform="matrix(1 0 0 1 145 115)" class="st2 st3 st4">&lt;- 1/3 -&gt;</text>
<text transform="matrix(1 0 0 1 288 462)"><tspan x="0" y="0" class="st2 st3 st4">&lt;-</tspan><tspan x="55" y="0" class="st2 st3 st4 st5"> </tspan><tspan x="72.9" y="0" class="st2 st3 st4">50% -</tspan><tspan x="229.6" y="0" class="st2 st3 st4 st6">&gt;</tspan></text>
<text transform="matrix(1 0 0 1 486 821)"><tspan x="0" y="0" class="st2 st3 st4">&lt;-</tspan><tspan x="55" y="0" class="st2 st3 st4 st5"> </tspan><tspan x="72.9" y="0" class="st2 st3 st4">75% -</tspan><tspan x="229.6" y="0" class="st2 st3 st4 st6">&gt;</tspan></text>
</g>
</svg>
{
{% if img == "wide" %}
"targetImg": "{{img_wide_url}}",
"zones": [
{"index": 1, "title": "Zone 1/3", "width": 533, "height": 200, "x": "0", "y": "0", "id": "zone-1"},
{"index": 2, "title": "Zone 50%", "width": 800, "height": 200, "x": "0", "y": "350", "id": "zone-2"},
{"index": 3, "title": "Zone 75%", "width": 1200, "height": 200, "x": "0", "y": "700", "id": "zone-3"}
],
{% else %}
"targetImg": "{{img_square_url}}",
"zones": [
{"index": 1, "title": "Zone 1/3", "width": 166, "height": 100, "x": "0", "y": "0", "id": "zone-1"},
{"index": 2, "title": "Zone 50%", "width": 250, "height": 100, "x": "0", "y": "200", "id": "zone-2"},
{"index": 3, "title": "Zone 75%", "width": 375, "height": 100, "x": "0", "y": "400", "id": "zone-3"}
],
{% endif %}
"displayBorders": true,
"items": [
{
"displayName": "Auto",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 1/3",
"imageURL": "",
"id": 0
},
{
"displayName": "Auto with long text that should wrap because draggables are give a maximum width",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 1/3",
"imageURL": "",
"id": 1
},
{
"displayName": "33.3%",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 1/3",
"imageURL": "",
"id": 2,
"widthPercent": 33.3
},
{
"displayName": "50%",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 50%",
"imageURL": "",
"id": 3,
"widthPercent": 50
},
{
"displayName": "75%",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 75%",
"imageURL": "",
"id": 4,
"widthPercent": 75
},
{
"displayName": "IMG 400x300",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 50%",
"imageURL": "{{img_400x300_url}}",
"id": 5,
},
{
"displayName": "IMG 200x200",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 50%",
"imageURL": "{{img_200x200_url}}",
"id": 6,
},
{
"displayName": "IMG 400x300",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 50%",
"imageURL": "{{img_400x300_url}}",
"id": 7,
"widthPercent": 50
},
{
"displayName": "IMG 200x200",
"feedback": {"incorrect": "", "correct": ""},
"zone": "Zone 50%",
"imageURL": "{{img_200x200_url}}",
"id": 8,
"widthPercent": 50
}
],
"feedback": {"start": "Some Intro Feedback", "finish": "Some Final Feedback"}
}
...@@ -297,6 +297,11 @@ class InteractionTestBase(object): ...@@ -297,6 +297,11 @@ class InteractionTestBase(object):
self.assertTrue(dialog_modal_overlay.is_displayed()) self.assertTrue(dialog_modal_overlay.is_displayed())
self.assertTrue(dialog_modal.is_displayed()) self.assertTrue(dialog_modal.is_displayed())
def _switch_to_block(self, idx):
""" Only needed if ther eare multiple blocks on the page. """
self._page = self.browser.find_elements_by_css_selector(self.default_css_selector)[idx]
self.scroll_down(0)
class BasicInteractionTest(InteractionTestBase): class BasicInteractionTest(InteractionTestBase):
""" """
...@@ -447,10 +452,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest): ...@@ -447,10 +452,6 @@ class MultipleBlocksDataInteraction(InteractionTestBase, BaseIntegrationTest):
return "<vertical_demo>{dnd_blocks}</vertical_demo>".format(dnd_blocks=blocks_xml) 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): def test_item_positive_feedback_on_good_move(self):
self._switch_to_block(0) self._switch_to_block(0)
self.parameterized_item_positive_feedback_on_good_move(self.item_maps['block1']) self.parameterized_item_positive_feedback_on_good_move(self.item_maps['block1'])
......
from __future__ import division
import base64
from collections import namedtuple
import os.path
from xblockutils.resources import ResourceLoader
from .test_base import BaseIntegrationTest
from .test_interaction import InteractionTestBase
loader = ResourceLoader(__name__)
def _svg_to_data_uri(path):
""" Convert an SVG image (by path) to a data URI """
data_path = os.path.dirname(__file__) + "/data/"
with open(data_path + path, "rb") as svg_fh:
encoded = base64.b64encode(svg_fh.read())
return "data:image/svg+xml;base64,{}".format(encoded)
Expectation = namedtuple('Expectation', [
'item_id', 'zone_id', 'width_percent', 'wh_ratio',
])
Expectation.__new__.__defaults__ = (None,) * len(Expectation._fields) # pylint: disable=protected-access
ZONE_33 = "Zone 1/3" # Title of top zone in each image used in these tests (33% width)
ZONE_50 = "Zone 50%"
ZONE_75 = "Zone 75%"
AUTO_MAX_WIDTH = 29 # Maximum width (as % of the parent container) for items with automatic sizing
class SizingTests(InteractionTestBase, BaseIntegrationTest):
"""
Tests that cover features like draggable blocks with automatic sizes vs. specified sizes,
different background image ratios, and responsive behavior.
Tip: To see how these tests work, throw in an 'import time; time.sleep(200)' at the start of
one of the tests, so you can check it out in the selenium browser window that opens.
"""
PAGE_TITLE = 'Drag and Drop v2 Sizing'
PAGE_ID = 'drag_and_drop_v2_sizing'
@staticmethod
def _get_scenario_xml():
"""
Set up the test scenario:
* An upper dndv2 xblock with a wide image (1600x900 SVG)
(on desktop and mobile, this background image will always fill the available width
and should have the same width as the item bank above)
* A lower dndv2 xblock with a small square image (500x500 SVG)
(on desktop, the square image is not as wide as the item bank, but on mobile it
may take up the whole width of the screen)
"""
params = {
"img": "wide",
"img_wide_url": _svg_to_data_uri('dnd-bg-wide.svg'),
"img_square_url": _svg_to_data_uri('dnd-bg-square.svg'),
"img_400x300_url": _svg_to_data_uri('400x300.svg'),
"img_200x200_url": _svg_to_data_uri('200x200.svg'),
}
upper_block = "<drag-and-drop-v2 data='{data}'/>".format(
data=loader.render_django_template("data/test_sizing_template.json", params)
)
params["img"] = "square"
lower_block = "<drag-and-drop-v2 data='{data}'/>".format(
data=loader.render_django_template("data/test_sizing_template.json", params)
)
return "<vertical_demo>{}\n{}</vertical_demo>".format(upper_block, lower_block)
def test_wide_image(self):
expectations = [
# The text 'Auto' with no fixed size specified should be 5-20% wide
Expectation(item_id=0, zone_id=ZONE_33, width_percent=[5, 20]),
# The long text with no fixed size specified should be wrapped at the maximum width
Expectation(item_id=1, zone_id=ZONE_33, width_percent=AUTO_MAX_WIDTH),
# The text items that specify specific widths as a percentage of the background image:
Expectation(item_id=2, zone_id=ZONE_33, width_percent=33.3),
Expectation(item_id=3, zone_id=ZONE_33, width_percent=50),
Expectation(item_id=4, zone_id=ZONE_33, width_percent=75),
]
self._check_sizes(0, expectations)
def _check_sizes(self, block_index, expectations):
""" Test the actual dimensions that each draggable has, in the bank and when placed """
# Check assumptions - the container wrapping this XBlock should be 770px wide
self._switch_to_block(block_index)
self.assertEqual(self._page.size["width"], 770) # self._page is the .xblock--drag-and-drop div
target_img = self._page.find_element_by_css_selector('.target-img')
target_img_width = target_img.size["width"]
self.assertEqual(target_img_width, 755)
item_bank = self._page.find_element_by_css_selector('.item-bank')
item_bank_width = item_bank.size["width"]
self.assertEqual(item_bank_width, 755)
# Test each element, before it is placed.
for expect in expectations:
item_unplaced = self._get_item_by_value(expect.item_id)
if expect.width_percent is not None:
width_percent = item_unplaced.size["width"] / item_bank_width * 100
if isinstance(expect.width_percent, list):
min_expected, max_expected = expect.width_percent
msg = "Unplaced item {} should have width of {}% - {}%. Actual: {:.2f}%".format(
expect.item_id, min_expected, max_expected, width_percent
)
self.assertGreaterEqual(width_percent, min_expected, msg)
self.assertLessEqual(width_percent, max_expected, msg)
else:
self.assertAlmostEqual(
width_percent, expect.width_percent, delta=1,
msg="Unplaced item {} should have width of ~{}% (+/- 1%). Actual: {:.2f}%".format(
expect.item_id, expect.width_percent, width_percent
)
)
# Test each element, after it it placed.
for expect in expectations:
self.place_item(expect.item_id, expect.zone_id)
item_placed = self._get_placed_item_by_value(expect.item_id)
if expect.width_percent is not None:
width_percent = item_placed.size["width"] / target_img_width * 100
if isinstance(expect.width_percent, list):
min_expected, max_expected = expect.width_percent
msg = "Placed item {} should have width of {}% - {}%. Actual: {:.2f}%".format(
expect.item_id, min_expected, max_expected, width_percent
)
self.assertGreaterEqual(width_percent, min_expected, msg)
self.assertLessEqual(width_percent, max_expected, msg)
else:
self.assertAlmostEqual(
width_percent, expect.width_percent, delta=1,
msg="Placed item {} should have width of ~{}% (+/- 1%). Actual: {:.2f}%".format(
expect.item_id, expect.width_percent, width_percent
)
)
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