Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 12 additions & 0 deletions problem_builder/public/js/review_blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Binary file added problem_builder/static/test/swoop-bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added problem_builder/static/test/swoop-step1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added problem_builder/static/test/swoop-step2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 99 additions & 31 deletions problem_builder/tests/integration/test_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -52,6 +54,40 @@ def get_submissions(self, key, limit=1):
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
Expand All @@ -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()

Expand Down Expand Up @@ -128,12 +167,21 @@ def _assert_cell_contents(self, cell, expected_visible_text, expected_screen_rea
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)
Expand All @@ -148,24 +196,11 @@ def test_empty_dashboard(self):
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)
Expand All @@ -191,6 +226,52 @@ def test_dashboard(self):
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
Expand All @@ -200,11 +281,6 @@ def test_dashboard_alternative(self):
* 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')
Expand Down Expand Up @@ -233,17 +309,13 @@ def test_dashboard_alternative(self):
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)
Expand All @@ -267,15 +339,11 @@ def test_dashboard_exclude_questions(self):
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)
Expand Down
Binary file added screenshots/baseline/dashboard-image-overlay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/baseline/dashboard-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.