Commit e01af341 by Omar Khan

Merge pull request #107 from open-craft/omar/report-download

Fix dashboard report image download
parents 594f1f28 0ef0a747
......@@ -4,7 +4,7 @@ machine:
dependencies:
override:
- "pip install -U pip wheel setuptools"
- "pip install -e git://github.com/edx/xblock-sdk.git@22c1b2f173919bef22f2d9d9295ec5396d02dffd#egg=xblock-sdk"
- "pip install -e git://github.com/edx/xblock-sdk.git@bddf9f4a2c6e4df28a411c8f632cc2250170ae9d#egg=xblock-sdk"
- "pip install -r requirements.txt"
- "pip install -r $VIRTUAL_ENV/src/xblock-sdk/requirements/base.txt"
- "pip install -r $VIRTUAL_ENV/src/xblock-sdk/requirements/test.txt"
......
......@@ -8,6 +8,18 @@ function ExportBase(runtime, element, initData) {
var generateDataUriFromImageURL = function(imgURL) {
// Given the URL to an image, IF the image has already been cached by the browser,
// returns a data: URI with the contents of the image (image will be converted to PNG)
// Expand relative urls and urls without an explicit protocol into absolute urls
var a = document.createElement('a');
a.href = imgURL;
imgURL = a.href;
// If the image is from another domain, just return its URL. We can't
// create a data URL from cross-domain images:
// https://html.spec.whatwg.org/multipage/scripting.html#dom-canvas-todataurl
if (a.origin !== window.location.origin)
return imgURL;
var img = new Image();
img.src = imgURL;
if (!img.complete)
......
......@@ -17,6 +17,8 @@
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
#
import json
from functools import wraps
from textwrap import dedent
from mock import Mock, patch
from .base_test import ProblemBuilderBaseTest
......@@ -52,6 +54,40 @@ class MockSubmissionsAPI(object):
return []
def check_dashboard_and_report(fixture, set_mentoring_values=True, **kwargs):
"""
Decorator for dashboard test methods.
- Sets up the given fixture
- Runs the decorated test
- Clicks the download link
- Opens the report
- Runs the decorated test again against the report
Any extra keyword arguments are passed to the dashboard XBlock.
"""
def wrapper(test):
@wraps(test)
def wrapped(test_case):
test_case._install_fixture(fixture)
if kwargs:
dashboard = test_case.vertical.get_child('test-scenario.pb-dashboard.d0.u0')
for key, value in kwargs.items():
setattr(dashboard, key, value)
dashboard.save()
if set_mentoring_values:
test_case._set_mentoring_values()
test_case.go_to_view('student_view')
test(test_case)
download_link = test_case.browser.find_element_by_css_selector('.report-download-link')
download_link.click()
test_case.browser.get(download_link.get_attribute('href'))
test_case.assertRegexpMatches(test_case.browser.current_url, r'^data:text/html;base64,')
test(test_case)
return wrapped
return wrapper
class TestDashboardBlock(ProblemBuilderBaseTest):
"""
Test the Student View of a dashboard XBlock linked to some problem builder blocks
......@@ -75,6 +111,9 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
/>
""")
# Clean up screenshots if the tests pass
cleanup_on_success = True
def setUp(self):
super(TestDashboardBlock, self).setUp()
......@@ -128,12 +167,21 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
def _format_sr_text(self, visible_text):
return "Score: {value}".format(value=visible_text)
def _set_mentoring_values(self):
pbs = self.browser.find_elements_by_css_selector('.mentoring')
for pb in pbs:
mcqs = pb.find_elements_by_css_selector('fieldset.choices')
for idx, mcq in enumerate(mcqs):
choices = mcq.find_elements_by_css_selector('.choices .choice label')
choices[idx].click()
self.click_submit(pb)
@check_dashboard_and_report(SIMPLE_DASHBOARD, set_mentoring_values=False)
def test_empty_dashboard(self):
"""
Test that when the student has not submitted any question answers, we still see
the dashboard, and its lists all the MCQ questions in the way we expect.
"""
self._install_fixture(self.SIMPLE_DASHBOARD)
dashboard = self.browser.find_element_by_css_selector('.pb-dashboard')
step_headers = dashboard.find_elements_by_css_selector('thead')
self.assertEqual(len(step_headers), 3)
......@@ -148,24 +196,11 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
cell = mcq.find_element_by_css_selector('td:last-child')
self._assert_cell_contents(cell, '', 'No value yet')
def _set_mentoring_values(self):
pbs = self.browser.find_elements_by_css_selector('.mentoring')
for pb in pbs:
mcqs = pb.find_elements_by_css_selector('fieldset.choices')
for idx, mcq in enumerate(mcqs):
choices = mcq.find_elements_by_css_selector('.choices .choice label')
choices[idx].click()
self.click_submit(pb)
@check_dashboard_and_report(SIMPLE_DASHBOARD)
def test_dashboard(self):
"""
Submit an answer to each MCQ, then check that the dashboard reflects those answers.
"""
self._install_fixture(self.SIMPLE_DASHBOARD)
self._set_mentoring_values()
# Reload the page:
self.go_to_view("student_view")
dashboard = self.browser.find_element_by_css_selector('.pb-dashboard')
headers = dashboard.find_elements_by_class_name('report-header')
self.assertEqual(len(headers), 0)
......@@ -191,6 +226,52 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
expected_average = {0: "2", 1: "3", 2: "1"}[step_num]
self._assert_cell_contents(right_col, expected_average, self._format_sr_text(expected_average))
@check_dashboard_and_report(SIMPLE_DASHBOARD, visual_rules=json.dumps({
'background': '/static/test/swoop-bg.png',
}))
def test_dashboard_image(self):
"""
Test that the dashboard image is displayed correctly, both on the page
and it the report. We allow minor differences here as the report
screenshot is not a perfect match.
"""
self.assertScreenshot('.pb-dashboard-visual svg', 'dashboard-image', threshold=100)
@check_dashboard_and_report(SIMPLE_DASHBOARD, visual_rules=json.dumps({
'background': ('//raw.githubusercontent.com/open-craft/problem-builder/omar/report-download/'
'problem_builder/static/test/swoop-bg.png'),
}))
def test_dashboard_image_cross_domain(self):
"""
Test that cross-domain dashboard images are displayed correctly. We
allow minor differences here as the report screenshot is not a perfect
match.
"""
self.assertScreenshot('.pb-dashboard-visual svg', 'dashboard-image', threshold=100)
@check_dashboard_and_report(
SIMPLE_DASHBOARD,
visual_rules=json.dumps({
'background': '/static/test/swoop-bg.png',
'images': [
'/static/test/swoop-step1.png',
'/static/test/swoop-step2.png',
],
}),
color_rules='\n'.join([
'0: grey',
'x <= 2: #aa2626',
'x <= 3: #e7ce76',
'#84b077',
]),
)
def test_dashboard_image_overlay(self):
"""
Test that image overlays are displayed correctly on the dashboard.
"""
self.assertScreenshot('.pb-dashboard-visual svg', 'dashboard-image-overlay', threshold=100)
@check_dashboard_and_report(ALTERNATIVE_DASHBOARD)
def test_dashboard_alternative(self):
"""
Submit an answer to each MCQ, then check that the dashboard reflects those answers with alternative
......@@ -200,11 +281,6 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
* Numerical values are not shown
* Include HTML header and footer snippets
"""
self._install_fixture(self.ALTERNATIVE_DASHBOARD)
self._set_mentoring_values()
# Reload the page:
self.go_to_view("student_view")
dashboard = self.browser.find_element_by_css_selector('.pb-dashboard')
header_p = dashboard.find_element_by_id('header-paragraph')
self.assertEquals(header_p.text, 'Header')
......@@ -233,17 +309,13 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
self.assertEqual(left_col.text, average_labels[step_num])
right_col = avg_row.find_element_by_css_selector('.value')
expected_average = {0: "2", 1: "3", 2: "1"}[step_num]
self._assert_cell_contents(right_col, '', self._format_sr_text(expected_average))
self._assert_cell_contents(right_col, '', self._format_sr_text(expected_average))
@check_dashboard_and_report(HIDE_QUESTIONS_DASHBOARD)
def test_dashboard_exclude_questions(self):
"""
Submit an answer to each MCQ, then check that the dashboard ignores questions it is configured to ignore
"""
self._install_fixture(self.HIDE_QUESTIONS_DASHBOARD)
self._set_mentoring_values()
# Reload the page:
self.go_to_view("student_view")
dashboard = self.browser.find_element_by_css_selector('.pb-dashboard')
steps = dashboard.find_elements_by_css_selector('tbody')
self.assertEqual(len(steps), 3)
......@@ -267,15 +339,11 @@ class TestDashboardBlock(ProblemBuilderBaseTest):
expected_average = {0: "1", 1: "3", 2: "1"}[step_num]
self._assert_cell_contents(right_col, expected_average, self._format_sr_text(expected_average))
@check_dashboard_and_report(MALFORMED_HIDE_QUESTIONS_DASHBOARD)
def test_dashboard_malformed_exclude_questions(self):
"""
Submit an answer to each MCQ, then check that the dashboard ignores questions it is configured to ignore
"""
self._install_fixture(self.MALFORMED_HIDE_QUESTIONS_DASHBOARD)
self._set_mentoring_values()
# Reload the page:
self.go_to_view("student_view")
dashboard = self.browser.find_element_by_css_selector('.pb-dashboard')
steps = dashboard.find_elements_by_css_selector('tbody')
self.assertEqual(len(steps), 3)
......
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