Commit 7d7201fb by Xavier Antoviaque

Merge pull request #2 from open-craft/dragonfi/add-various-utils

Add resource loading utils
parents 8a30a7bd 8da5d62c
<explanation>This is an even simpler xml template.</explanation>
This is a simple django template example.
This template can make use of the following context variables:
Name: {{name}}
List: {{items|safe}}
It can also do some fancy things with them:
Default value if name is empty: {{name|default:"Default Name"}}
Length of the list: {{items|length}}
Items of the list:{% for item in items %} {{item}}{% endfor %}
<example>
<title>This is a simple xml template.</title>
<arguments>
<url_name>{{url_name}}</url_name>
</arguments>
</example>
import unittest
from xblockutils.resources import ResourceLoader
expected_string = u"""\
This is a simple django template example.
This template can make use of the following context variables:
Name: {{name}}
List: {{items|safe}}
It can also do some fancy things with them:
Default value if name is empty: {{name|default:"Default Name"}}
Length of the list: {{items|length}}
Items of the list:{% for item in items %} {{item}}{% endfor %}
"""
example_context = {
"name": "This is a fine name",
"items": [1, 2, 3, 4, "a", "b", "c"],
}
expected_filled_template = u"""\
This is a simple django template example.
This template can make use of the following context variables:
Name: This is a fine name
List: [1, 2, 3, 4, 'a', 'b', 'c']
It can also do some fancy things with them:
Default value if name is empty: This is a fine name
Length of the list: 7
Items of the list: 1 2 3 4 a b c
"""
example_id = "example-unique-id"
expected_filled_js_template = u"""\
<script type='text/template' id='example-unique-id'>
{}
</script>\
""".format(expected_filled_template)
another_template = u"""\
<explanation>This is an even simpler xml template.</explanation>
"""
simple_template = u"""\
<example>
<title>This is a simple xml template.</title>
<arguments>
<url_name>simple_template</url_name>
</arguments>
</example>
"""
expected_scenarios_with_identifiers = [
("another_template", "Another Template", another_template),
("simple_template", "Simple Template", simple_template),
]
expected_scenarios = [(t, c) for (i, t, c) in expected_scenarios_with_identifiers]
class TestResourceLoader(unittest.TestCase):
def test_load_unicode(self):
s = ResourceLoader(__name__).load_unicode("data/simple_django_template.txt")
self.assertEquals(s, expected_string)
def test_load_unicode_from_another_module(self):
s = ResourceLoader("tests.unit.data").load_unicode("simple_django_template.txt")
self.assertEquals(s, expected_string)
def test_render_template(self):
loader = ResourceLoader(__name__)
s = loader.render_template("data/simple_django_template.txt", example_context)
self.assertEquals(s, expected_filled_template)
def test_render_js_template(self):
loader = ResourceLoader(__name__)
s = loader.render_js_template("data/simple_django_template.txt", example_id, example_context)
self.assertEquals(s, expected_filled_js_template)
def test_load_scenarios(self):
loader = ResourceLoader(__name__)
scenarios = loader.load_scenarios_from_path("data")
self.assertEquals(scenarios, expected_scenarios)
def test_load_scenarios_with_identifiers(self):
loader = ResourceLoader(__name__)
scenarios = loader.load_scenarios_from_path("data", include_identifier=True)
self.assertEquals(scenarios, expected_scenarios_with_identifiers)
......@@ -11,6 +11,8 @@ from selenium.webdriver.support.ui import WebDriverWait
from workbench import scenarios
from workbench.test.selenium_test import SeleniumTest
from .resources import ResourceLoader
class SeleniumBaseTest(SeleniumTest):
module_name = None
......@@ -30,18 +32,14 @@ class SeleniumBaseTest(SeleniumTest):
raise NotImplementedError("Overwrite cls.default_css_selector in your derived class.")
return self.default_css_selector
@property
def scenario_path(self):
base_dir = os.path.dirname(os.path.realpath(sys.modules[self._module_name].__file__))
return os.path.join(base_dir, self.relative_scenario_path)
def setUp(self):
super(SeleniumBaseTest, self).setUp()
# Use test scenarios
self.browser.get(self.live_server_url) # Needed to load tests once
scenarios.SCENARIOS.clear()
scenarios_list = self._load_scenarios_from_path(self.scenario_path)
loader = ResourceLoader(self._module_name)
scenarios_list = loader.load_scenarios_from_path(self.relative_scenario_path, include_identifier=True)
for identifier, title, xml in scenarios_list:
scenarios.add_xml_scenario(identifier, title, xml)
self.addCleanup(scenarios.remove_scenario, identifier)
......@@ -82,31 +80,3 @@ class SeleniumBaseTest(SeleniumTest):
time.sleep(1)
block = self.browser.find_element_by_css_selector(css_selector)
return block
def _load_resource(self, resource_path):
"""
Gets the content of a resource
"""
resource_content = pkg_resources.resource_string(self._module_name, resource_path)
return unicode(resource_content)
def _render_template(self, template_path, context={}):
"""
Evaluate a template by resource path, applying the provided context
"""
template_str = self._load_resource(template_path)
template = Template(template_str)
return template.render(Context(context))
def _load_scenarios_from_path(self, xml_path):
list_of_scenarios = []
if os.path.isdir(xml_path):
for template in os.listdir(xml_path):
if not template.endswith('.xml'):
continue
identifier = template[:-4]
title = identifier.replace('_', ' ').title()
template_path = os.path.join(self.relative_scenario_path, template)
scenario = unicode(self._render_template(template_path, {"url_name": identifier}))
list_of_scenarios.append((identifier, title, scenario))
return list_of_scenarios
......@@ -15,9 +15,9 @@ class PublishEventMixin(object):
except KeyError as e:
return {'result': 'error', 'message': 'Missing event_type in JSON data'}
return self.publish_event_from_python(event_type, data)
return self.publish_event_from_dict(event_type, data)
def publish_event_from_python(self, event_type, data):
def publish_event_from_dict(self, event_type, data):
for key, value in self.additional_publish_event_data.items():
if key in data:
return {'result': 'error', 'message': 'Key should not be in publish_event data: {}'.format(key)}
......
import os
import sys
import pkg_resources
from django.template import Context, Template
class ResourceLoader(object):
"""Loads resources relative to the module named by the module_name parameter."""
def __init__(self, module_name):
self.module_name = module_name
def load_unicode(self, resource_path):
"""
Gets the content of a resource
"""
resource_content = pkg_resources.resource_string(self.module_name, resource_path)
return unicode(resource_content)
def render_template(self, template_path, context={}):
"""
Evaluate a template by resource path, applying the provided context
"""
template_str = self.load_unicode(template_path)
template = Template(template_str)
return template.render(Context(context))
def render_js_template(self, template_path, element_id, context={}):
"""
Render a js template.
"""
return u"<script type='text/template' id='{}'>\n{}\n</script>".format(
element_id,
self.render_template(template_path, context)
)
def load_scenarios_from_path(self, relative_scenario_dir, include_identifier=False):
"""
Returns an array of (title, xmlcontent) from files contained in a specified directory,
formatted as expected for the return value of the workbench_scenarios() method.
If `include_identifier` is True, returns an array of (identifier, title, xmlcontent).
"""
base_dir = os.path.dirname(os.path.realpath(sys.modules[self.module_name].__file__))
scenario_dir = os.path.join(base_dir, relative_scenario_dir)
scenarios = []
if os.path.isdir(scenario_dir):
for template in os.listdir(scenario_dir):
if not template.endswith('.xml'):
continue
identifier = template[:-4]
title = identifier.replace('_', ' ').title()
template_path = os.path.join(relative_scenario_dir, template)
scenario = unicode(self.render_template(template_path, {"url_name": identifier}))
if not include_identifier:
scenarios.append((title, scenario))
else:
scenarios.append((identifier, title, scenario))
return scenarios
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