Commit 362da63d by Braden MacDonald

Fix unit tests

parent c08357d0
......@@ -10,7 +10,7 @@ install:
- "python setup.py sdist"
- "pip install dist/xblock-drag-and-drop-v2-0.1.tar.gz"
script:
- pep8 drag_and_drop_v2 --max-line-length=120
- pep8 drag_and_drop_v2 tests --max-line-length=120
- python run_tests.py
notifications:
email: false
......
......@@ -4,21 +4,21 @@ DEFAULT_DATA = {
"zones": [
{
"index": 1,
"width": 200,
"id": "zone-1",
"title": _("Zone 1"),
"height": 100,
"x": "120",
"y": "200",
"id": "zone-1"
"x": 160,
"y": 30,
"width": 196,
"height": 178,
},
{
"index": 2,
"width": 200,
"id": "zone-2",
"title": _("Zone 2"),
"height": 100,
"x": "120",
"y": "360",
"id": "zone-2"
"x": 86,
"y": 210,
"width": 340,
"height": 140,
}
],
"items": [
......@@ -31,10 +31,6 @@ DEFAULT_DATA = {
"zone": "Zone 1",
"backgroundImage": "",
"id": 0,
"size": {
"width": "190px",
"height": "auto"
}
},
{
"displayName": "2",
......@@ -45,10 +41,6 @@ DEFAULT_DATA = {
"zone": "Zone 2",
"backgroundImage": "",
"id": 1,
"size": {
"width": "190px",
"height": "auto"
}
},
{
"displayName": "X",
......@@ -59,14 +51,10 @@ DEFAULT_DATA = {
"zone": "none",
"backgroundImage": "",
"id": 2,
"size": {
"width": "100px",
"height": "100px"
}
},
],
"feedback": {
"start": _("Intro Feed"),
"finish": _("Final Feed")
"start": _("Drag the items onto the image above."),
"finish": _("Good work! You have completed this drag and drop exercise.")
},
}
......@@ -350,7 +350,7 @@ class DragAndDropBlock(XBlock):
return {
'items': item_state,
'finished': is_finished,
'overall_feedback': self.data['feedback']['finished' if is_finished else 'start'],
'overall_feedback': self.data['feedback']['finish' if is_finished else 'start'],
}
def _get_item_state(self):
......
......@@ -302,8 +302,6 @@ function DragAndDropBlock(runtime, element, configuration) {
var itemProperties = {
value: item.id,
drag_disabled: Boolean(item_user_state || state.finished),
width: item.size.width,
height: item.size.height,
class_name: item_user_state && ('input' in item_user_state || item_user_state.correct_input) ? 'fade': undefined,
input: input,
content_html: item.backgroundImage ? '<img src="' + item.backgroundImage + '"/>' : item.displayName
......
......@@ -6,6 +6,7 @@ This script is required to run our selenium tests inside the xblock-sdk workbenc
because the workbench SDK's settings file is not inside any python module.
"""
import logging
import os
import sys
import workbench
......@@ -21,6 +22,9 @@ if __name__ == "__main__":
# Configure a range of ports in case the default port of 8081 is in use
os.environ.setdefault("DJANGO_LIVE_TEST_SERVER_ADDRESS", "localhost:8081-8099")
# Silence too verbose Django logging
logging.disable(logging.DEBUG)
try:
os.mkdir('var')
except OSError:
......
{
"title": "DnDv2 XBlock with HTML instructions",
"show_title": false,
"question_text": "Solve this <strong>drag-and-drop</strong> problem.",
"show_question_header": false,
"target_img_expanded_url": "/expanded/url/to/drag_and_drop_v2/public/img/triangle.png",
"item_background_color": "white",
"item_text_color": "#000080",
"initial_feedback": "HTML <strong>Intro</strong> Feed",
"display_zone_labels": false,
"zones": [
{
"index": 1,
"width": 200,
"title": "Zone <i>1</i>",
"x": 100,
"y": 200,
"width": 200,
"height": 100,
"y": "200",
"x": "100",
"id": "zone-1"
},
{
"index": 2,
"width": 200,
"title": "Zone <b>2</b>",
"height": 100,
"y": 0,
"x": 0,
"y": 0,
"width": 200,
"height": 100,
"id": "zone-2"
}
],
"items": [
{
"displayName": "<b>1</b>",
"backgroundImage": "",
"id": 0,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": false
},
{
"displayName": "<i>2</i>",
"backgroundImage": "",
"id": 1,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": true
},
{
"displayName": "X",
"backgroundImage": "",
"id": 2,
"size": {
"width": "100px",
"height": "100px"
},
"inputOptions": false
},
{
"displayName": "",
"backgroundImage": "http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg",
"backgroundImage": "http://placehold.it/100x300",
"id": 3,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": false
}
],
"state": {
"items": {},
"finished": false
},
"feedback": {
"start": "Intro Feed"
},
"targetImg": "http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png",
"title": "Drag and Drop",
"show_title": true,
"question_text": "",
"show_question_header": true
]
}
......@@ -5,8 +5,8 @@
"width": 200,
"title": "Zone <i>1</i>",
"height": 100,
"y": "200",
"x": "100",
"y": 200,
"x": 100,
"id": "zone-1"
},
{
......@@ -19,6 +19,7 @@
"id": "zone-2"
}
],
"items": [
{
"displayName": "<b>1</b>",
......@@ -28,11 +29,7 @@
},
"zone": "Zone <i>1</i>",
"backgroundImage": "",
"id": 0,
"size": {
"width": "190px",
"height": "auto"
}
"id": 0
},
{
"displayName": "<i>2</i>",
......@@ -43,10 +40,6 @@
"zone": "Zone <b>2</b>",
"backgroundImage": "",
"id": 1,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": {
"value": 100,
"margin": 5
......@@ -60,11 +53,7 @@
},
"zone": "none",
"backgroundImage": "",
"id": 2,
"size": {
"width": "100px",
"height": "100px"
}
"id": 2
},
{
"displayName": "",
......@@ -73,21 +62,12 @@
"correct": ""
},
"zone": "none",
"backgroundImage": "http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg",
"id": 3,
"size": {
"width": "190px",
"height": "auto"
}
"backgroundImage": "http://placehold.it/100x300",
"id": 3
}
],
"state": {
"items": {},
"finished": true
},
"feedback": {
"start": "Intro Feed",
"finish": "Final <b>Feed</b>"
},
"targetImg": "http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png"
"start": "HTML <strong>Intro</strong> Feed",
"finish": "Final <strong>feedback</strong>!"
}
}
{
"display_name": "DnDv2 XBlock with HTML instructions",
"show_title": false,
"question_text": "Solve this <strong>drag-and-drop</strong> problem.",
"show_question_header": false,
"weight": 1,
"item_background_color": "white",
"item_text_color": "#000080"
}
{
"title": "Drag and Drop",
"show_title": true,
"question_text": "",
"show_question_header": true,
"target_img_expanded_url": "http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png",
"item_background_color": null,
"item_text_color": null,
"initial_feedback": "Intro Feed",
"display_zone_labels": false,
"zones": [
{
"index": 1,
"title": "Zone 1",
"id": "zone-1",
"height": 100,
"y": "200",
"x": "100",
"width": 200
"y": "200",
"width": 200,
"height": 100,
"id": "zone-1"
},
{
"index": 2,
"title": "Zone 2",
"id": "zone-2",
"height": 100,
"y": 0,
"x": 0,
"width": 200
"y": 0,
"width": 200,
"height": 100,
"id": "zone-2"
}
],
"items": [
{
"displayName": "1",
"backgroundImage": "",
"id": 0,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": false
"inputOptions": false,
"size": {"height": "auto", "width": "190px"}
},
{
"displayName": "2",
"backgroundImage": "",
"id": 1,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": true
"inputOptions": true,
"size": {"height": "auto", "width": "190px"}
},
{
"displayName": "X",
"backgroundImage": "",
"id": 2,
"size": {
"width": "100px",
"height": "100px"
},
"inputOptions": false
"inputOptions": false,
"size": {"height": "100px", "width": "100px"}
},
{
"displayName": "",
"backgroundImage": "http://i1.kym-cdn.com/entries/icons/square/000/006/151/tumblr_lltzgnHi5F1qzib3wo1_400.jpg",
"id": 3,
"size": {
"width": "190px",
"height": "auto"
},
"inputOptions": false
"inputOptions": false,
"size": {"height": "auto", "width": "190px"}
}
],
"state": {
"items": {},
"finished": false
},
"feedback": {
"start": "Intro Feed"
},
"targetImg": "http://i0.kym-cdn.com/photos/images/newsfeed/000/030/404/1260585284155.png",
"title": "Drag and Drop",
"show_title": true,
"question_text": "",
"show_question_header": true
]
}
{
"title": "DnDv2 XBlock with plain text instructions",
"show_title": true,
"question_text": "Can you solve this drag-and-drop problem?",
"show_question_header": true,
"target_img_expanded_url": "http://placehold.it/800x600",
"item_background_color": null,
"item_text_color": null,
"initial_feedback": "This is the initial feedback.",
"display_zone_labels": false,
"zones": [
{
"index": 1,
"title": "Zone 1",
"y": 123,
"x": 234,
"width": 345,
"height": 456,
"id": "zone-1"
},
{
"index": 2,
"title": "Zone 2",
"y": 20,
"x": 10,
"width": 30,
"height": 40,
"id": "zone-2"
}
],
"items": [
{
"displayName": "1",
"backgroundImage": "",
"id": 0,
"inputOptions": false
},
{
"displayName": "2",
"backgroundImage": "",
"id": 1,
"inputOptions": true
},
{
"displayName": "X",
"backgroundImage": "",
"id": 2,
"inputOptions": false
},
{
"displayName": "",
"backgroundImage": "http://placehold.it/200x100",
"id": 3,
"inputOptions": false
}
]
}
{
"zones": [
{
"index": 1,
"title": "Zone 1",
"y": 123,
"x": 234,
"width": 345,
"height": 456,
"id": "zone-1"
},
{
"index": 2,
"title": "Zone 2",
"y": 20,
"x": 10,
"width": 30,
"height": 40,
"id": "zone-2"
}
],
"items": [
{
"displayName": "1",
"feedback": {
"incorrect": "No 1",
"correct": "Yes 1"
},
"zone": "Zone 1",
"backgroundImage": "",
"id": 0
},
{
"displayName": "2",
"feedback": {
"incorrect": "No 2",
"correct": "Yes 2"
},
"zone": "Zone 2",
"backgroundImage": "",
"id": 1,
"inputOptions": {
"value": 100,
"margin": 5
}
},
{
"displayName": "X",
"feedback": {
"incorrect": "",
"correct": ""
},
"zone": "none",
"backgroundImage": "",
"id": 2
},
{
"displayName": "",
"feedback": {
"incorrect": "",
"correct": ""
},
"zone": "none",
"backgroundImage": "http://placehold.it/200x100",
"id": 3
}
],
"feedback": {
"start": "This is the initial feedback.",
"finish": "This is the final feedback."
},
"targetImg": "http://placehold.it/800x600",
"displayLabels": false
}
{
"display_name": "DnDv2 XBlock with plain text instructions",
"show_title": true,
"question_text": "Can you solve this drag-and-drop problem?",
"show_question_header": true,
"weight": 1,
"item_background_color": "",
"item_text_color": ""
}
import json
import unittest
from mock import Mock
from nose.tools import assert_true, assert_false, assert_in
from .utils import (
make_block,
load_resource,
TestCaseMixin,
)
class BaseDragAndDropAjaxFixture(TestCaseMixin):
ZONE_1 = None
ZONE_2 = None
FEEDBACK = {
0: {"correct": None, "incorrect": None},
1: {"correct": None, "incorrect": None},
2: {"correct": None, "incorrect": None}
}
FINAL_FEEDBACK = None
FOLDER = None
def setUp(self):
self.patch_workbench()
self.block = make_block()
initial_settings = self.initial_settings()
for field in initial_settings:
setattr(self.block, field, initial_settings[field])
self.block.data = self.initial_data()
@classmethod
def initial_data(cls):
return json.loads(load_resource('data/{}/data.json'.format(cls.FOLDER)))
@classmethod
def initial_settings(cls):
return json.loads(load_resource('data/{}/settings.json'.format(cls.FOLDER)))
@classmethod
def expected_configuration(cls):
return json.loads(load_resource('data/{}/config_out.json'.format(cls.FOLDER)))
@classmethod
def initial_feedback(cls):
""" The initial overall_feedback value """
return cls.expected_configuration()["initial_feedback"]
def test_get_configuration(self):
self.assertEqual(self.expected_configuration(), self.block.get_configuration())
def test_do_attempt_wrong_with_feedback(self):
item_id, zone_id = 0, self.ZONE_2
data = {"val": item_id, "zone": zone_id, "x_percent": "33%", "y_percent": "11%"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"overall_feedback": None,
"finished": False,
"correct": False,
"correct_location": False,
"feedback": self.FEEDBACK[item_id]["incorrect"]
})
def test_do_attempt_wrong_without_feedback(self):
item_id, zone_id = 2, self.ZONE_1
data = {"val": item_id, "zone": zone_id, "x_percent": "33%", "y_percent": "11%"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"overall_feedback": None,
"finished": False,
"correct": False,
"correct_location": False,
"feedback": self.FEEDBACK[item_id]["incorrect"]
})
def test_do_attempt_correct(self):
item_id, zone_id = 0, self.ZONE_1
data = {"val": item_id, "zone": zone_id, "x_percent": "33%", "y_percent": "11%"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"overall_feedback": None,
"finished": False,
"correct": True,
"correct_location": True,
"feedback": self.FEEDBACK[item_id]["correct"]
})
def test_do_attempt_with_input(self):
data = {"val": 1, "zone": self.ZONE_2, "x_percent": "0%", "y_percent": "85%"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"finished": False,
"correct": False,
"correct_location": True,
"feedback": None,
"overall_feedback": None,
})
expected_state = {
'items': {
"1": {"x_percent": "0%", "y_percent": "85%", "correct_input": False},
},
'finished': False,
'overall_feedback': self.initial_feedback(),
}
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
data = {"val": 1, "input": "250"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"finished": False,
"correct": False,
"correct_location": True,
"feedback": self.FEEDBACK[1]['incorrect'],
"overall_feedback": None
})
expected_state = {
'items': {
"1": {"x_percent": "0%", "y_percent": "85%", "input": "250", "correct_input": False},
},
'finished': False,
'overall_feedback': self.initial_feedback(),
}
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
data = {"val": 1, "input": "103"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"finished": False,
"correct": True,
"correct_location": True,
"feedback": self.FEEDBACK[1]['correct'],
"overall_feedback": None,
})
expected_state = {
'items': {
"1": {"x_percent": "0%", "y_percent": "85%", "input": "103", "correct_input": True},
},
'finished': False,
'overall_feedback': self.initial_feedback(),
}
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
def test_grading(self):
published_grades = []
def mock_publish(self, event, params):
if event == 'grade':
published_grades.append(params)
self.block.runtime.publish = mock_publish
self.call_handler('do_attempt', {
"val": 0, "zone": self.ZONE_1, "y_percent": "11%", "x_percent": "33%"
})
self.assertEqual(1, len(published_grades))
self.assertEqual({'value': 0.5, 'max_value': 1}, published_grades[-1])
self.call_handler('do_attempt', {
"val": 1, "zone": self.ZONE_2, "y_percent": "90%", "x_percent": "42%"
})
self.assertEqual(2, len(published_grades))
self.assertEqual({'value': 0.5, 'max_value': 1}, published_grades[-1])
self.call_handler('do_attempt', {"val": 1, "input": "99"})
self.assertEqual(3, len(published_grades))
self.assertEqual({'value': 1, 'max_value': 1}, published_grades[-1])
def test_do_attempt_final(self):
data = {"val": 0, "zone": self.ZONE_1, "x_percent": "33%", "y_percent": "11%"}
self.call_handler('do_attempt', data)
expected_state = {
"items": {
"0": {"x_percent": "33%", "y_percent": "11%", "correct_input": True}
},
"finished": False,
'overall_feedback': self.initial_feedback(),
}
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
data = {"val": 1, "zone": self.ZONE_2, "x_percent": "22%", "y_percent": "22%"}
res = self.call_handler('do_attempt', data)
data = {"val": 1, "input": "99"}
res = self.call_handler('do_attempt', data)
self.assertEqual(res, {
"overall_feedback": self.FINAL_FEEDBACK,
"finished": True,
"correct": True,
"correct_location": True,
"feedback": self.FEEDBACK[1]["correct"]
})
expected_state = {
"items": {
"0": {"x_percent": "33%", "y_percent": "11%", "correct_input": True},
"1": {"x_percent": "22%", "y_percent": "22%", "input": "99", "correct_input": True}
},
"finished": True,
'overall_feedback': self.FINAL_FEEDBACK,
}
self.assertEqual(expected_state, self.call_handler('get_user_state', method="GET"))
class TestDragAndDropHtmlData(BaseDragAndDropAjaxFixture, unittest.TestCase):
FOLDER = "html"
ZONE_1 = "Zone <i>1</i>"
ZONE_2 = "Zone <b>2</b>"
FEEDBACK = {
0: {"correct": "Yes <b>1</b>", "incorrect": "No <b>1</b>"},
1: {"correct": "Yes <i>2</i>", "incorrect": "No <i>2</i>"},
2: {"correct": "", "incorrect": ""}
}
FINAL_FEEDBACK = "Final <strong>feedback</strong>!"
class TestDragAndDropPlainData(BaseDragAndDropAjaxFixture, unittest.TestCase):
FOLDER = "plain"
ZONE_1 = "Zone 1"
ZONE_2 = "Zone 2"
FEEDBACK = {
0: {"correct": "Yes 1", "incorrect": "No 1"},
1: {"correct": "Yes 2", "incorrect": "No 2"},
2: {"correct": "", "incorrect": ""}
}
FINAL_FEEDBACK = "This is the final feedback."
class TestOldDataFormat(TestDragAndDropPlainData):
"""
Make sure we can work with the slightly-older format for 'data' field values.
"""
FOLDER = "old"
FINAL_FEEDBACK = "Final Feed"
import unittest
from .utils import (
DEFAULT_START_FEEDBACK,
DEFAULT_FINISH_FEEDBACK,
make_request,
make_block,
TestCaseMixin,
)
class BasicTests(TestCaseMixin, unittest.TestCase):
""" Basic unit tests for the Drag and Drop block, using its default settings """
def setUp(self):
self.block = make_block()
self.patch_workbench()
def test_templates_contents(self):
context = {}
student_fragment = self.block.runtime.render(self.block, 'student_view', context)
self.assertIn('<section class="xblock--drag-and-drop">', student_fragment.content)
self.assertIn('Loading drag and drop exercise.', student_fragment.content)
def test_get_configuration(self):
"""
Test the get_configuration() method.
The result of this method is passed to the block's JavaScript during initialization.
"""
config = self.block.get_configuration()
zones = config.pop("zones")
items = config.pop("items")
self.assertEqual(config, {
"display_zone_labels": False,
"title": "Drag and Drop",
"show_title": True,
"question_text": "",
"show_question_header": True,
"target_img_expanded_url": '/expanded/url/to/drag_and_drop_v2/public/img/triangle.png',
"item_background_color": None,
"item_text_color": None,
"initial_feedback": DEFAULT_START_FEEDBACK,
})
self.assertEqual(zones, [
{
"index": 1,
"title": "Zone 1",
"id": "zone-1",
"x": 160,
"y": 30,
"width": 196,
"height": 178,
},
{
"index": 2,
"title": "Zone 2",
"id": "zone-2",
"x": 86,
"y": 210,
"width": 340,
"height": 140,
}
])
# Items should contain no answer data:
self.assertEqual(items, [
{"id": 0, "displayName": "1", "backgroundImage": "", "inputOptions": False},
{"id": 1, "displayName": "2", "backgroundImage": "", "inputOptions": False},
{"id": 2, "displayName": "X", "backgroundImage": "", "inputOptions": False},
])
def test_ajax_solve_and_reset(self):
# Check assumptions / initial conditions:
self.assertFalse(self.block.completed)
def assert_user_state_empty():
self.assertEqual(self.block.item_state, {})
self.assertEqual(self.call_handler("get_user_state"), {
'items': {},
'finished': False,
'overall_feedback': DEFAULT_START_FEEDBACK,
})
assert_user_state_empty()
# Drag both items into the correct spot:
data = {"val": 0, "zone": "Zone 1", "x_percent": "33%", "y_percent": "11%"}
self.call_handler('do_attempt', data)
data = {"val": 1, "zone": "Zone 2", "x_percent": "67%", "y_percent": "80%"}
self.call_handler('do_attempt', data)
# Check the result:
self.assertTrue(self.block.completed)
self.assertEqual(self.block.item_state, {
'0': {'x_percent': '33%', 'y_percent': '11%'},
'1': {'x_percent': '67%', 'y_percent': '80%'},
})
self.assertEqual(self.call_handler('get_user_state'), {
'items': {
'0': {'x_percent': '33%', 'y_percent': '11%', 'correct_input': True},
'1': {'x_percent': '67%', 'y_percent': '80%', 'correct_input': True},
},
'finished': True,
'overall_feedback': DEFAULT_FINISH_FEEDBACK,
})
# Reset to initial conditions
self.call_handler('reset', {})
self.assertTrue(self.block.completed)
assert_user_state_empty()
def test_studio_submit(self):
body = {
'display_name': "Test Drag & Drop",
'show_title': False,
'question_text': "Question Drag & Drop",
'show_question_header': False,
'item_background_color': 'cornflowerblue',
'item_text_color': 'coral',
'weight': '5',
'data': {
'foo': 1
},
}
res = self.call_handler('studio_submit', body)
self.assertEqual(res, {'result': 'success'})
self.assertEqual(self.block.show_title, False)
self.assertEqual(self.block.display_name, "Test Drag & Drop")
self.assertEqual(self.block.question_text, "Question Drag & Drop")
self.assertEqual(self.block.show_question_header, False)
self.assertEqual(self.block.item_background_color, "cornflowerblue")
self.assertEqual(self.block.item_text_color, "coral")
self.assertEqual(self.block.weight, 5)
self.assertEqual(self.block.data, {'foo': 1})
def test_expand_static_url(self):
""" Test the expand_static_url handler needed in Studio when changing the image """
res = self.call_handler('expand_static_url', '/static/blah.png')
self.assertEqual(res, {'url': '/course/test-course/assets/blah.png'})
def test_image_url(self):
""" Ensure that the default image and custom URLs are both expanded by the runtime """
self.assertEqual(self.block.data.get("targetImg"), None)
self.assertEqual(
self.block.get_configuration()["target_img_expanded_url"],
'/expanded/url/to/drag_and_drop_v2/public/img/triangle.png',
)
self.block.data["targetImg"] = "/static/foo.png"
self.assertEqual(
self.block.get_configuration()["target_img_expanded_url"],
'/course/test-course/assets/foo.png',
)
import json
import pkg_resources
import re
from mock import patch
from webob import Request
from workbench.runtime import WorkbenchRuntime
from xblock.fields import ScopeIds
from xblock.runtime import KvsFieldData, DictKeyValueStore
import drag_and_drop_v2
DEFAULT_START_FEEDBACK = "Drag the items onto the image above."
DEFAULT_FINISH_FEEDBACK = "Good work! You have completed this drag and drop exercise."
def make_request(data, method='POST'):
""" Make a webob JSON Request """
request = Request.blank('/')
request.method = 'POST'
request.body = json.dumps(data).encode('utf-8') if data is not None else ""
request.method = method
return request
def make_block():
""" Instantiate a DragAndDropBlock XBlock inside a WorkbenchRuntime """
block_type = 'drag_and_drop_v2'
key_store = DictKeyValueStore()
field_data = KvsFieldData(key_store)
runtime = WorkbenchRuntime()
def_id = runtime.id_generator.create_definition(block_type)
usage_id = runtime.id_generator.create_usage(def_id)
scope_ids = ScopeIds('user', block_type, def_id, usage_id)
return drag_and_drop_v2.DragAndDropBlock(runtime, field_data, scope_ids=scope_ids)
def load_resource(resource_path):
......@@ -7,3 +41,32 @@ def load_resource(resource_path):
"""
resource_content = pkg_resources.resource_string(__name__, resource_path)
return unicode(resource_content)
class TestCaseMixin(object):
""" Helpful mixins for unittest TestCase subclasses """
maxDiff = None
def patch_workbench(self):
self.apply_patch(
'workbench.runtime.WorkbenchRuntime.local_resource_url',
lambda _, _block, path: '/expanded/url/to/drag_and_drop_v2/' + path
)
self.apply_patch(
'workbench.runtime.WorkbenchRuntime.replace_urls',
lambda _, html: re.sub(r'"/static/([^"]*)"', r'"/course/test-course/assets/\1"', html),
create=True,
)
def apply_patch(self, *args, **kwargs):
new_patch = patch(*args, **kwargs)
mock = new_patch.start()
self.addCleanup(new_patch.stop)
return mock
def call_handler(self, handler_name, data=None, expect_json=True, method='POST'):
response = self.block.handle(handler_name, make_request(data, method=method))
if expect_json:
self.assertEqual(response.status_code, 200)
return json.loads(response.body)
return response
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