Commit e270196f by Don Mitchell

Merge pull request #5419 from edx/split/acceptance_split

Get acceptance tests to run on split
parents 76a52acf 4f795f82
......@@ -60,10 +60,10 @@ def i_click_on_error_dialog(step):
))
# we don't know the actual ID of the vertical. So just check that we did go to a
# vertical page in the course (there should only be one).
vertical_usage_key = world.scenario_dict['COURSE'].id.make_usage_key("vertical", None)
vertical_usage_key = world.scenario_dict['COURSE'].id.make_usage_key("vertical", "test")
vertical_url = reverse_usage_url('container_handler', vertical_usage_key)
# Remove the trailing "/None" from the URL - we don't know the course ID, so we just want to
# check that we visited a vertical URL.
if vertical_url.endswith("/None"):
if vertical_url.endswith("/test") or vertical_url.endswith("@test"):
vertical_url = vertical_url[:-5]
assert_equal(1, world.browser.url.count(vertical_url))
......@@ -150,7 +150,7 @@ def i_see_new_course_image(_step):
images = world.css_find(img_css)
assert len(images) == 1
img = images[0]
expected_src = '/c4x/MITx/999/asset/image.jpg'
expected_src = 'image.jpg'
# Don't worry about the domain in the URL
success_func = lambda _: img['src'].endswith(expected_src)
......@@ -160,8 +160,8 @@ def i_see_new_course_image(_step):
@step('the image URL should be present in the field')
def image_url_present(_step):
field_css = '#course-image-url'
expected_value = '/c4x/MITx/999/asset/image.jpg'
assert world.css_value(field_css) == expected_value
expected_value = 'image.jpg'
assert world.css_value(field_css).endswith(expected_value)
############### HELPER METHODS ####################
......
......@@ -60,22 +60,22 @@ Feature: CMS.Course updates
And I go to the course updates page
When I add a new update with the text "<img src='/static/my_img.jpg'/>"
# Can only do partial text matches because of the quotes with in quotes (and regexp step matching).
Then I should see the update "/c4x/MITx/999/asset/my_img.jpg"
Then I should see the asset update to "my_img.jpg"
And I change the update from "/static/my_img.jpg" to "<img src='/static/modified.jpg'/>"
Then I should see the update "/c4x/MITx/999/asset/modified.jpg"
Then I should see the asset update to "modified.jpg"
And when I reload the page
Then I should see the update "/c4x/MITx/999/asset/modified.jpg"
Then I should see the asset update to "modified.jpg"
Scenario: Static links are rewritten when previewing handouts
Given I have opened a new course in Studio
And I go to the course updates page
When I modify the handout to "<ol><img src='/static/my_img.jpg'/></ol>"
# Can only do partial text matches because of the quotes with in quotes (and regexp step matching).
Then I see the handout "/c4x/MITx/999/asset/my_img.jpg"
Then I see the handout image link "my_img.jpg"
And I change the handout from "/static/my_img.jpg" to "<img src='/static/modified.jpg'/>"
Then I see the handout "/c4x/MITx/999/asset/modified.jpg"
Then I see the handout image link "modified.jpg"
And when I reload the page
Then I see the handout "/c4x/MITx/999/asset/modified.jpg"
Then I see the handout image link "modified.jpg"
Scenario: Users cannot save handouts with bad html until edit or update it properly
Given I have opened a new course in Studio
......
......@@ -29,6 +29,14 @@ def check_update(_step, text):
assert_in(text, update_html)
@step(u'I should see the asset update to "([^"]*)"$')
def check_asset_update(_step, asset_file):
update_css = 'div.update-contents'
update_html = world.css_find(update_css).html
asset_key = world.scenario_dict['COURSE'].id.make_asset_key(asset_type='asset', path=asset_file)
assert_in(unicode(asset_key), update_html)
@step(u'I should not see the update "([^"]*)"$')
def check_no_update(_step, text):
update_css = 'div.update-contents'
......@@ -90,6 +98,14 @@ def check_handout(_step, handout):
assert_in(handout, world.css_html(handout_css))
@step(u'I see the handout image link "([^"]*)"$')
def check_handout_image_link(_step, image_file):
handout_css = 'div.handouts-content'
handout_html = world.css_html(handout_css)
asset_key = world.scenario_dict['COURSE'].id.make_asset_key(asset_type='asset', path=image_file)
assert_in(unicode(asset_key), handout_html)
@step(u'I see the handout error text')
def check_handout_error(_step):
handout_error_css = 'div#handout_error'
......
......@@ -61,20 +61,14 @@ def change_assignment_name(step, old_name, new_name):
index = get_type_index(old_name)
f = world.css_find(name_id)[index]
assert_not_equal(index, -1)
for count in range(len(old_name)):
for __ in xrange(len(old_name)):
f._element.send_keys(Keys.END, Keys.BACK_SPACE)
f._element.send_keys(new_name)
@step(u'I go back to the main course page')
def main_course_page(step):
course_name = world.scenario_dict['COURSE'].display_name.replace(' ', '_')
course_key = SlashSeparatedCourseKey(
world.scenario_dict['COURSE'].org,
world.scenario_dict['COURSE'].number,
course_name
)
main_page_link = reverse_course_url('course_handler', course_key)
main_page_link = reverse_course_url('course_handler', world.scenario_dict['COURSE'].id)
world.visit(main_page_link)
assert_in('Course Outline', world.css_text('h1.page-header'))
......
......@@ -185,7 +185,13 @@ def open_course_with_locked(step, lock_state):
@step(u'Then the asset is (viewable|protected)$')
def view_asset(_step, status):
url = django_url('/c4x/MITx/999/asset/asset.html')
asset_loc = world.scenario_dict['COURSE'].id.make_asset_key(asset_type='asset', path='asset.html')
svr_loc = django_url()
asset_url = unicode(asset_loc)
divider = '/'
if asset_url[0] == '/':
divider = ''
url = '{}{}{}'.format(svr_loc, divider, asset_url)
if status == 'viewable':
expected_text = 'test file'
else:
......
......@@ -81,6 +81,8 @@ def click_the_link_with_the_text_group1(step, linktext):
@step('I should see that the path is "([^"]*)"$')
def i_should_see_that_the_path_is(step, path):
if 'COURSE' in world.scenario_dict:
path = path.format(world.scenario_dict['COURSE'].id)
assert world.url_equals(path), (
"path should be {!r} but is {!r}".format(path, world.browser.url)
)
......@@ -185,6 +187,8 @@ def dialogs_are_closed(step):
@step(u'visit the url "([^"]*)"')
def visit_url(step, url):
if 'COURSE' in world.scenario_dict:
url = url.format(world.scenario_dict['COURSE'].id)
world.browser.visit(lettuce.django.django_url(url))
......
......@@ -13,7 +13,6 @@ from functools import wraps
from pymongo.errors import AutoReconnect
from xmodule.exceptions import HeartbeatFailure
from xmodule.modulestore.split_mongo import BlockKey
from datetime import tzinfo
import datetime
import pytz
......
......@@ -2,9 +2,9 @@ Instructions for creating js/tinymce.full.min.js
1. Ensure that the dependencies (NodeJS, Jake, and other dependencies) are installed. If necessary,
install them per the directions on https://github.com/tinymce/tinymce/tree/4.0.20.
2. Unzip edx-platform/vendor_extra/tinymce/jake_package.zip into this directory (so that Jakefile.js resides in this directory).
2. Unzip edx-platform/vendor_extra/tinymce/JakePackage.zip into this directory (so that Jakefile.js resides in this directory).
3. Run the following command in the tinymce directory:
jake minify bundle[themes:modern,plugins:image,link,codemirror,paste,table,textcolor]
jake minify bundle[themes:modern,plugins:image,link,codemirror,paste,table,textcolor,media]
4. Cleanup by deleting the Unversioned files that were created from unzipping jake_package.zip.
Instructions for updating tinymce to a newer version:
......
tinymce.PluginManager.add("link", function(e) {
function t(t) {
return function() {
var n = e.settings.link_list;
"string" == typeof n ? tinymce.util.XHR.send({
url: n,
success: function(e) {
t(tinymce.util.JSON.parse(e))
}
}) : t(n)
}
}
function n(t) {
function n(e) {
var t = f.find("#text");
(!t.value() || e.lastControl && t.value() == e.lastControl.text()) && t.value(e.control.text()), f.find("#href").value(e.control.value())
}
function l() {
var n = [{
text: "None",
value: ""
}];
return tinymce.each(t, function(t) {
n.push({
text: t.text || t.title,
value: e.convertURL(t.value || t.url, "href"),
menu: t.menu
})
}), n
}
function i(t) {
var n = [{
text: "None",
value: ""
}];
return tinymce.each(e.settings.rel_list, function(e) {
n.push({
text: e.text || e.title,
value: e.value,
selected: t === e.value
})
}), n
}
function r(t) {
var n = [];
return e.settings.target_list || (n.push({
text: "None",
value: ""
}), n.push({
text: "New window",
value: "_blank"
})), tinymce.each(e.settings.target_list, function(e) {
n.push({
text: e.text || e.title,
value: e.value,
selected: t === e.value
})
}), n
}
function a(t) {
var l = [];
return tinymce.each(e.dom.select("a:not([href])"), function(e) {
var n = e.name || e.id;
n && l.push({
text: n,
value: "#" + n,
selected: -1 != t.indexOf("#" + n)
})
}), l.length ? (l.unshift({
text: "None",
value: ""
}), {
name: "anchor",
type: "listbox",
label: "Anchors",
values: l,
onselect: n
}) : void 0
}
function o() {
h && h.value(e.convertURL(this.value(), "href")), !c && 0 === x.text.length && k && this.parent().parent().find("#text")[0].value(this.value())
}
var u, s, c, f, d, h, v, g, x = {},
m = e.selection,
p = e.dom;
u = m.getNode(), s = p.getParent(u, "a[href]");
var k = !0;
if (/</.test(m.getContent())) k = !1;
else if (s) {
var y, b = s.childNodes;
if (0 === b.length) k = !1;
else
for (y = b.length - 1; y >= 0; y--)
if (3 != b[y].nodeType) {
k = !1;
break
}
}
x.text = c = s ? s.innerText || s.textContent : m.getContent({
format: "text"
}), x.href = s ? p.getAttrib(s, "href") : "", x.target = s ? p.getAttrib(s, "target") : e.settings.default_link_target || "", x.rel = s ? p.getAttrib(s, "rel") : "", e.fire('EditLink', x), k && (d = {
name: "text",
type: "textbox",
size: 40,
label: "Text to display",
onchange: function() {
x.text = this.value()
}
}), t && (h = {
type: "listbox",
label: "Link list",
values: l(),
onselect: n,
value: e.convertURL(x.href, "href"),
onPostRender: function() {
h = this
}
}), e.settings.target_list !== !1 && (g = {
name: "target",
type: "listbox",
label: "Target",
values: r(x.target)
}), e.settings.rel_list && (v = {
name: "rel",
type: "listbox",
label: "Rel",
values: i(x.rel)
}), f = e.windowManager.open({
title: "Insert link",
data: x,
body: [{
name: "href",
type: "filepicker",
filetype: "file",
size: 40,
autofocus: !0,
label: "Url",
onchange: o,
onkeyup: o
},
d, a(x.href), h, v, g
],
onSubmit: function(t) {
function n(t, n) {
var l = e.selection.getRng();
window.setTimeout(function() {
e.windowManager.confirm(t, function(t) {
e.selection.setRng(l), n(t)
})
}, 0)
}
function l() {
s ? (e.focus(), k && i.text != c && (s.innerText = i.text), p.setAttribs(s, {
href: r,
target: i.target ? i.target : null,
rel: i.rel ? i.rel : null
}), m.select(s), e.undoManager.add()) : k ? e.insertContent(p.createHTML("a", {
href: r,
target: i.target ? i.target : null,
rel: i.rel ? i.rel : null
}, p.encode(i.text))) : e.execCommand("mceInsertLink", !1, {
href: r,
target: i.target,
rel: i.rel ? i.rel : null
})
}
var i = t.data;
e.fire('SaveLink', i);
var r = i.href;
/* EDX - Change the email address detection, which mistakenly detected Split asset keys as email addresses.
Instead, if the link has a "@" sign *and* a colon, do not consider it an email address. */
return r ? r.indexOf("@") > 0 && -1 == r.indexOf("//") && -1 == r.indexOf(":") ? void n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?", function(e) {
e && (r = "mailto:" + r), l()
}) : /^\s*www\./i.test(r) ? void n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?", function(e) {
e && (r = "http://" + r), l()
}) : void l() : void e.execCommand("unlink")
}
})
}
e.addButton("link", {
icon: "link",
tooltip: "Insert/edit link",
shortcut: "Ctrl+K",
onclick: t(n),
stateSelector: "a[href]"
}), e.addButton("unlink", {
icon: "unlink",
tooltip: "Remove link",
cmd: "unlink",
stateSelector: "a[href]"
}), e.addShortcut("Ctrl+K", "", t(n)), this.showDialog = n, e.addMenuItem("link", {
icon: "link",
text: "Insert link",
shortcut: "Ctrl+K",
onclick: t(n),
stateSelector: "a[href]",
context: "insert",
prependToContext: !0
})
});
tinymce.PluginManager.add("link",function(e){function t(t){return function(){var n=e.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function n(t){function n(e){var t=f.find("#text");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),f.find("#href").value(e.control.value())}function l(){var n=[{text:"None",value:""}];return tinymce.each(t,function(t){n.push({text:t.text||t.title,value:e.convertURL(t.value||t.url,"href"),menu:t.menu})}),n}function i(t){var n=[{text:"None",value:""}];return tinymce.each(e.settings.rel_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function r(t){var n=[];return e.settings.target_list||(n.push({text:"None",value:""}),n.push({text:"New window",value:"_blank"})),tinymce.each(e.settings.target_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function a(t){var l=[];return tinymce.each(e.dom.select("a:not([href])"),function(e){var n=e.name||e.id;n&&l.push({text:n,value:"#"+n,selected:-1!=t.indexOf("#"+n)})}),l.length?(l.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:l,onselect:n}):void 0}function o(){h&&h.value(e.convertURL(this.value(),"href")),!c&&0===x.text.length&&k&&this.parent().parent().find("#text")[0].value(this.value())}var u,s,c,f,d,h,v,g,x={},m=e.selection,p=e.dom;u=m.getNode(),s=p.getParent(u,"a[href]");var k=!0;if(/</.test(m.getContent()))k=!1;else if(s){var y,b=s.childNodes;if(0===b.length)k=!1;else for(y=b.length-1;y>=0;y--)if(3!=b[y].nodeType){k=!1;break}}x.text=c=s?s.innerText||s.textContent:m.getContent({format:"text"}),x.href=s?p.getAttrib(s,"href"):"",x.target=s?p.getAttrib(s,"target"):e.settings.default_link_target||"",x.rel=s?p.getAttrib(s,"rel"):"",e.fire('EditLink', x),k&&(d={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){x.text=this.value()}}),t&&(h={type:"listbox",label:"Link list",values:l(),onselect:n,value:e.convertURL(x.href,"href"),onPostRender:function(){h=this}}),e.settings.target_list!==!1&&(g={name:"target",type:"listbox",label:"Target",values:r(x.target)}),e.settings.rel_list&&(v={name:"rel",type:"listbox",label:"Rel",values:i(x.rel)}),f=e.windowManager.open({title:"Insert link",data:x,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:o,onkeyup:o},d,a(x.href),h,v,g],onSubmit:function(t){function n(t,n){var l=e.selection.getRng();window.setTimeout(function(){e.windowManager.confirm(t,function(t){e.selection.setRng(l),n(t)})},0)}function l(){s?(e.focus(),k&&i.text!=c&&(s.innerText=i.text),p.setAttribs(s,{href:r,target:i.target?i.target:null,rel:i.rel?i.rel:null}),m.select(s),e.undoManager.add()):k?e.insertContent(p.createHTML("a",{href:r,target:i.target?i.target:null,rel:i.rel?i.rel:null},p.encode(i.text))):e.execCommand("mceInsertLink",!1,{href:r,target:i.target,rel:i.rel?i.rel:null})}var i=t.data;e.fire('SaveLink', i);var r=i.href;return r?r.indexOf("@")>0&&-1==r.indexOf("//")&&-1==r.indexOf("mailto:")?void n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(e){e&&(r="mailto:"+r),l()}):/^\s*www\./i.test(r)?void n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(e){e&&(r="http://"+r),l()}):void l():void e.execCommand("unlink")}})}e.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]"}),e.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),e.addShortcut("Ctrl+K","",t(n)),this.showDialog=n,e.addMenuItem("link",{icon:"link",text:"Insert link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]",context:"insert",prependToContext:!0})});
\ No newline at end of file
tinymce.PluginManager.add("link",function(e){function t(t){return function(){var n=e.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function n(t){function n(e){var t=f.find("#text");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),f.find("#href").value(e.control.value())}function l(){var n=[{text:"None",value:""}];return tinymce.each(t,function(t){n.push({text:t.text||t.title,value:e.convertURL(t.value||t.url,"href"),menu:t.menu})}),n}function i(t){var n=[{text:"None",value:""}];return tinymce.each(e.settings.rel_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function r(t){var n=[];return e.settings.target_list||(n.push({text:"None",value:""}),n.push({text:"New window",value:"_blank"})),tinymce.each(e.settings.target_list,function(e){n.push({text:e.text||e.title,value:e.value,selected:t===e.value})}),n}function a(t){var l=[];return tinymce.each(e.dom.select("a:not([href])"),function(e){var n=e.name||e.id;n&&l.push({text:n,value:"#"+n,selected:-1!=t.indexOf("#"+n)})}),l.length?(l.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:l,onselect:n}):void 0}function o(){h&&h.value(e.convertURL(this.value(),"href")),!c&&0===x.text.length&&k&&this.parent().parent().find("#text")[0].value(this.value())}var u,s,c,f,d,h,v,g,x={},m=e.selection,p=e.dom;u=m.getNode(),s=p.getParent(u,"a[href]");var k=!0;if(/</.test(m.getContent()))k=!1;else if(s){var y,b=s.childNodes;if(0===b.length)k=!1;else for(y=b.length-1;y>=0;y--)if(3!=b[y].nodeType){k=!1;break}}x.text=c=s?s.innerText||s.textContent:m.getContent({format:"text"}),x.href=s?p.getAttrib(s,"href"):"",x.target=s?p.getAttrib(s,"target"):e.settings.default_link_target||"",x.rel=s?p.getAttrib(s,"rel"):"",e.fire("EditLink",x),k&&(d={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){x.text=this.value()}}),t&&(h={type:"listbox",label:"Link list",values:l(),onselect:n,value:e.convertURL(x.href,"href"),onPostRender:function(){h=this}}),e.settings.target_list!==!1&&(g={name:"target",type:"listbox",label:"Target",values:r(x.target)}),e.settings.rel_list&&(v={name:"rel",type:"listbox",label:"Rel",values:i(x.rel)}),f=e.windowManager.open({title:"Insert link",data:x,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:o,onkeyup:o},d,a(x.href),h,v,g],onSubmit:function(t){function n(t,n){var l=e.selection.getRng();window.setTimeout(function(){e.windowManager.confirm(t,function(t){e.selection.setRng(l),n(t)})},0)}function l(){s?(e.focus(),k&&i.text!=c&&(s.innerText=i.text),p.setAttribs(s,{href:r,target:i.target?i.target:null,rel:i.rel?i.rel:null}),m.select(s),e.undoManager.add()):k?e.insertContent(p.createHTML("a",{href:r,target:i.target?i.target:null,rel:i.rel?i.rel:null},p.encode(i.text))):e.execCommand("mceInsertLink",!1,{href:r,target:i.target,rel:i.rel?i.rel:null})}var i=t.data;e.fire("SaveLink",i);var r=i.href;return r?r.indexOf("@")>0&&-1==r.indexOf("//")&&-1==r.indexOf(":")?void n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(e){e&&(r="mailto:"+r),l()}):/^\s*www\./i.test(r)?void n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(e){e&&(r="http://"+r),l()}):void l():void e.execCommand("unlink")}})}e.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]"}),e.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),e.addShortcut("Ctrl+K","",t(n)),this.showDialog=n,e.addMenuItem("link",{icon:"link",text:"Insert link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]",context:"insert",prependToContext:!0})});
\ No newline at end of file
......@@ -3,22 +3,20 @@
from lettuce import world, step
from lettuce.django import django_url
from course_modes.models import CourseMode
from nose.tools import assert_equal
UPSELL_LINK_CSS = '.message-upsell a.action-upgrade[href*="edx/999/Certificates"]'
def create_cert_course():
world.clear_courses()
org = 'edx'
number = '999'
name = 'Certificates'
course_id = '{org}/{number}/{name}'.format(
org=org, number=number, name=name)
world.scenario_dict['course_id'] = course_id
world.scenario_dict['COURSE'] = world.CourseFactory.create(
org=org, number=number, display_name=name)
world.scenario_dict['course_id'] = world.scenario_dict['COURSE'].id
world.UPSELL_LINK_CSS = u'.message-upsell a.action-upgrade[href*="{}"]'.format(
world.scenario_dict['course_id']
)
honor_mode = world.CourseModeFactory.create(
course_id=world.scenario_dict['course_id'],
......@@ -28,7 +26,7 @@ def create_cert_course():
)
verfied_mode = world.CourseModeFactory.create(
course_id=course_id,
course_id=world.scenario_dict['course_id'],
mode_slug='verified',
mode_display_name='verified cert course',
min_price=16,
......@@ -38,8 +36,7 @@ def create_cert_course():
def register():
url = 'courses/{org}/{number}/{name}/about'.format(
org='edx', number='999', name='Certificates')
url = u'courses/{}/about'.format(world.scenario_dict['course_id'])
world.browser.visit(django_url(url))
world.css_click('section.intro a.register')
......@@ -147,7 +144,7 @@ def approve_my_photo(step, name):
# HACK: for now don't bother clicking the approve button for
# id_photo, because it is sending you back to Step 1.
# Come back and figure it out later. JZ Aug 29 2013
if name=='face':
if name == 'face':
world.css_click(button_css[name])
# Make sure you didn't advance the carousel
......@@ -234,27 +231,27 @@ def navigate_to_my_dashboard(step):
@step(u'I see the course on my dashboard')
def see_the_course_on_my_dashboard(step):
course_link_css = 'section.my-courses a[href*="edx/999/Certificates"]'
course_link_css = u'section.my-courses a[href*="{}"]'.format(world.scenario_dict['course_id'])
assert world.is_css_present(course_link_css)
@step(u'I see the upsell link on my dashboard')
def see_upsell_link_on_my_dashboard(step):
course_link_css = UPSELL_LINK_CSS
course_link_css = world.UPSELL_LINK_CSS
assert world.is_css_present(course_link_css)
@step(u'I do not see the upsell link on my dashboard')
def see_upsell_link_on_my_dashboard(step):
course_link_css = UPSELL_LINK_CSS
def see_no_upsell_link(step):
course_link_css = world.UPSELL_LINK_CSS
assert world.is_css_not_present(course_link_css)
@step(u'I select the upsell link on my dashboard')
def see_upsell_link_on_my_dashboard(step):
def select_upsell_link_on_my_dashboard(step):
# expand the upsell section
world.css_click('.message-upsell')
course_link_css = UPSELL_LINK_CSS
course_link_css = world.UPSELL_LINK_CSS
# click the actual link
world.css_click(course_link_css)
......@@ -267,7 +264,7 @@ def see_that_i_am_on_the_verified_track(step):
@step(u'I leave the flow and return$')
def leave_the_flow_and_return(step):
world.visit('verify_student/verified/edx/999/Certificates/')
world.visit(u'verify_student/verified/{}/'.format(world.scenario_dict['course_id']))
@step(u'I am at the verified page$')
......
......@@ -11,7 +11,6 @@ from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from student.models import CourseEnrollment
from xmodule.modulestore.django import modulestore
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.course_module import CourseDescriptor
from courseware.courses import get_course_by_id
from xmodule import seq_module, vertical_module
......
......@@ -7,6 +7,7 @@ from nose.tools import assert_in, assert_true # pylint: disable=no-name-in-modu
from common import i_am_registered_for_the_course, visit_scenario_item
from problems_setup import add_problem_to_course, answer_problem
@steps
class ConditionalSteps(object):
COURSE_NUM = 'test_course'
......
......@@ -5,10 +5,10 @@ Feature: LMS.Events
Scenario Outline: An event is emitted for each request
Given: I am registered for the course "6.002x"
And I visit the url "<url>"
Then a "<url>" server event is emitted
Then a course url "<url>" event is emitted
Examples:
| url |
| /dashboard |
| /courses/edx/6.002x/Test_Course/info |
| /courses/edx/6.002x/Test_Course/courseware |
| url |
| /dashboard |
| /courses/{}/info |
| /courses/{}/courseware |
......@@ -36,6 +36,11 @@ def reset_between_outline_scenarios(_scenario, order, outline, reasons_to_fail):
world.event_collection.drop()
@step(r'[aA]n? course url "(.*)" event is emitted$')
def course_url_event_is_emitted(_step, url_regex):
event_type = url_regex.format(world.scenario_dict['COURSE'].id)
n_events_are_emitted(_step, 1, event_type, "server")
@step(r'([aA]n?|\d+) "(.*)" (server|browser) events? is emitted$')
def n_events_are_emitted(_step, count, event_type, event_source):
......
......@@ -34,8 +34,8 @@ Feature: LMS.Login in as a registered user
And The course "6.002x" exists
And I am registered for the course "6.002x"
And I am not logged in
And I visit the url "/courses/edx/6.002x/Test_Course/courseware"
And I should see that the path is "/accounts/login?next=/courses/edx/6.002x/Test_Course/courseware"
And I visit the url "/courses/{}/courseware"
And I should see that the path is "/accounts/login?next=/courses/{}/courseware"
When I submit my credentials on the login form
And I wait for "2" seconds
Then the page title should contain "6.002x Courseware"
......
......@@ -44,7 +44,7 @@ Feature: LMS.LTI component
Scenario: Graded LTI component in LMS is correctly works
Given the course has correct LTI credentials with registered Instructor
And the course has an LTI component with correct fields:
| open_in_a_new_page | weight | is_graded | has_score |
| open_in_a_new_page | weight | graded | has_score |
| False | 10 | True | True |
And I submit answer to LTI 1 question
And I click on the "Progress" tab
......@@ -71,7 +71,7 @@ Feature: LMS.LTI component
Scenario: Graded LTI component in LMS is correctly works with beta testers
Given the course has correct LTI credentials with registered BetaTester
And the course has an LTI component with correct fields:
| open_in_a_new_page | weight | is_graded | has_score |
| open_in_a_new_page | weight | graded | has_score |
| False | 10 | True | True |
And I submit answer to LTI 1 question
And I click on the "Progress" tab
......@@ -82,7 +82,7 @@ Feature: LMS.LTI component
Scenario: Graded LTI component in LMS is correctly works with LTI2v0 PUT callback
Given the course has correct LTI credentials with registered Instructor
And the course has an LTI component with correct fields:
| open_in_a_new_page | weight | is_graded | has_score |
| open_in_a_new_page | weight | graded | has_score |
| False | 10 | True | True |
And I submit answer to LTI 2 question
And I click on the "Progress" tab
......@@ -101,7 +101,7 @@ Feature: LMS.LTI component
Scenario: Graded LTI component in LMS is correctly works with LTI2v0 PUT delete callback
Given the course has correct LTI credentials with registered Instructor
And the course has an LTI component with correct fields:
| open_in_a_new_page | weight | is_graded | has_score |
| open_in_a_new_page | weight | graded | has_score |
| False | 10 | True | True |
And I submit answer to LTI 2 question
And I visit the LTI component
......
......@@ -13,7 +13,7 @@ from courseware.tests.factories import InstructorFactory, BetaTesterFactory
from courseware.access import has_access
from student.tests.factories import UserFactory
from common import course_id, visit_scenario_item
from common import visit_scenario_item
@step('I view the LTI and error is shown$')
......@@ -29,7 +29,7 @@ def lti_is_not_rendered(_step):
def check_lti_iframe_content(text):
#inside iframe test content is presented
# inside iframe test content is presented
location = world.scenario_dict['LTI'].location.html_id()
iframe_name = 'ltiFrame-' + location
with world.browser.get_iframe(iframe_name) as iframe:
......@@ -95,7 +95,7 @@ def incorrect_lti_is_rendered(_step):
assert not world.is_css_present('.link_lti_new_window', wait_time=0)
assert not world.is_css_present('.error_message', wait_time=0)
#inside iframe test content is presented
# inside iframe test content is presented
check_lti_iframe_content("Wrong LTI signature")
......@@ -119,7 +119,7 @@ def set_incorrect_lti_passport(_step):
i_am_registered_for_the_course(coursenum, metadata)
@step('the course has an LTI component with (.*) fields(?:\:)?$') #, new_page is(.*), is_graded is(.*)
@step('the course has an LTI component with (.*) fields(?:\:)?$') # , new_page is(.*), graded is(.*)
def add_correct_lti_to_course(_step, fields):
category = 'lti'
metadata = {
......@@ -176,7 +176,6 @@ def create_course_for_lti(course, metadata):
},
]
}
metadata.update(grading_policy)
# Create the course
# We always use the same org and display name,
......@@ -186,17 +185,7 @@ def create_course_for_lti(course, metadata):
number=course,
display_name='Test Course',
metadata=metadata,
grading_policy={
"GRADER": [
{
"type": "Homework",
"min_count": 1,
"drop_count": 0,
"short_label": "HW",
"weight": weight
},
]
},
grading_policy=grading_policy,
)
# Add a section to the course to contain problems
......@@ -248,7 +237,7 @@ def check_lti_popup(parent_window):
assert len(world.browser.windows) != 1
for window in world.browser.windows:
world.browser.switch_to_window(window) # Switch to a different window (the pop-up)
world.browser.switch_to_window(window) # Switch to a different window (the pop-up)
# Check if this is the one we want by comparing the url
url = world.browser.url
basename = os.path.basename(url)
......@@ -260,8 +249,8 @@ def check_lti_popup(parent_window):
assert result == u'This is LTI tool. Success.'
world.browser.driver.close() # Close the pop-up window
world.browser.switch_to_window(parent_window) # Switch to the main window again
world.browser.driver.close() # Close the pop-up window
world.browser.switch_to_window(parent_window) # Switch to the main window again
def click_and_check_lti_popup():
......@@ -314,7 +303,7 @@ def see_value_in_the_gradebook(_step, label, text):
for i, element in enumerate(table_headers):
if element.text.strip() == label:
index = i
break;
break
assert_true(world.css_has_text('{0} tbody td'.format(table_selector), text, index=index))
......
......@@ -2,10 +2,9 @@
# pylint: disable=W0621
from lettuce import world, step
from common import course_id, course_location
from common import course_location
from problems_setup import PROBLEM_DICT
from nose.tools import assert_in
from opaque_keys.edx.locations import SlashSeparatedCourseKey
@step(u'I am viewing a course with multiple sections')
......@@ -149,9 +148,9 @@ def create_course():
def create_user_and_visit_course():
world.register_by_course_key(SlashSeparatedCourseKey('edx', '999', 'Test_Course'))
world.register_by_course_key(world.scenario_dict['COURSE'].id)
world.log_in()
world.visit('/courses/edx/999/Test_Course/courseware/')
world.visit(u'/courses/{}/courseware/'.format(world.scenario_dict['COURSE'].id))
def add_problem_to_course_section(parent_location, display_name):
......
......@@ -6,10 +6,8 @@ Steps for problem.feature lettuce tests
# pylint: disable=W0621
from lettuce import world, step
from lettuce.django import django_url
from common import i_am_registered_for_the_course, visit_scenario_item
from problems_setup import PROBLEM_DICT, answer_problem, problem_has_answer, add_problem_to_course
from nose.tools import assert_equal
def _view_problem(step, problem_type, problem_settings=None):
......
# pylint: disable=C0111
# pylint: disable=W0621
#EVERY PROBLEM TYPE MUST HAVE THE FOLLOWING:
# EVERY PROBLEM TYPE MUST HAVE THE FOLLOWING:
# -Section in Dictionary containing:
# -factory
# -kwargs
......@@ -187,7 +187,9 @@ def answer_problem(course, problem_type, correctness):
section_loc = section_location(course)
if problem_type == "drop down":
select_name = "input_i4x-{0.org}-{0.course}-problem-drop_down_2_1".format(section_loc)
select_name = "input_{}_2_1".format(
section_loc.course_key.make_usage_key('problem', 'drop_down').html_id()
)
option_text = 'Option 2' if correctness == 'correct' else 'Option 3'
world.select_option(select_name, option_text)
......@@ -263,8 +265,9 @@ def answer_problem(course, problem_type, correctness):
offset = 25 if correctness == "correct" else -25
def try_click():
image_selector = "#imageinput_i4x-{0.org}-{0.course}-problem-image_2_1".format(section_loc)
input_selector = "#input_i4x-{0.org}-{0.course}-problem-image_2_1".format(section_loc)
problem_html_loc = section_loc.course_key.make_usage_key('problem', 'image').html_id()
image_selector = "#imageinput_{}_2_1".format(problem_html_loc)
input_selector = "#input_{}_2_1".format(problem_html_loc)
world.browser.execute_script('$("body").on("click", function(event) {console.log(event);})')
......@@ -385,16 +388,15 @@ def inputfield(course, problem_type, choice=None, input_num=1):
section_loc = section_location(course)
ptype = problem_type.replace(" ", "_")
# this is necessary due to naming requirement for this problem type
if problem_type in ("radio_text", "checkbox_text"):
selector_template = "input#i4x-{org}-{course}-problem-{ptype}_2_{input}"
selector_template = "input#{}_2_{input}"
else:
selector_template = "input#input_i4x-{org}-{course}-problem-{ptype}_2_{input}"
selector_template = "input#input_{}_2_{input}"
sel = selector_template.format(
org=section_loc.org,
course=section_loc.course,
ptype=problem_type.replace(" ", "_"),
section_loc.course_key.make_usage_key('problem', ptype).html_id(),
input=input_num,
)
......
......@@ -7,7 +7,7 @@ Define steps for bulk email acceptance test.
from lettuce import world, step
from lettuce.django import mail
from nose.tools import assert_in, assert_true, assert_equal # pylint: disable=E0611
from nose.tools import assert_in, assert_equal # pylint: disable=E0611
from django.core.management import call_command
from django.conf import settings
......@@ -115,8 +115,9 @@ def when_i_send_an_email(step, recipient): # pylint: disable=unused-argument
call_command('loaddata', 'course_email_template.json')
# Go to the email section of the instructor dash
world.visit('/courses/edx/888/Bulk_Email_Test_Course')
world.css_click('a[href="/courses/edx/888/Bulk_Email_Test_Course/instructor"]')
url = '/courses/{}'.format(world.bulk_email_course_key)
world.visit(url)
world.css_click('a[href="{}/instructor"]'.format(url))
world.css_click('a[data-section="send_email"]')
# Select the recipient
......
......@@ -7,7 +7,6 @@ Define common steps for instructor dashboard acceptance tests.
from __future__ import absolute_import
from django.conf import settings
from lettuce import world, step
from mock import patch
from nose.tools import assert_in # pylint: disable=E0611
......@@ -75,8 +74,8 @@ def i_am_staff_or_instructor(step, role): # pylint: disable=unused-argument
def go_to_section(section_name):
# section name should be one of
# course_info, membership, student_admin, data_download, analytics, send_email
world.visit('/courses/edx/999/Test_Course')
world.css_click('a[href="/courses/edx/999/Test_Course/instructor"]')
world.visit(u'/courses/{}'.format(world.course_key))
world.css_click(u'a[href="/courses/{}/instructor"]'.format(world.course_key))
world.css_click('a[data-section="{0}"]'.format(section_name))
......
......@@ -9,7 +9,7 @@ acceptance tests.
from lettuce import world, step
from nose.tools import assert_in, assert_regexp_matches # pylint: disable=E0611
from terrain.steps import reload_the_page
from splinter.request_handler.request_handler import RequestHandler
from django.utils import http
@step(u'I see a table of student profiles')
......@@ -60,11 +60,11 @@ Graded sections:
subgrader=<class 'xmodule.graders.AssignmentFormatGrader'>, type=Midterm Exam, category=Midterm Exam, weight=0.3
subgrader=<class 'xmodule.graders.AssignmentFormatGrader'>, type=Final Exam, category=Final Exam, weight=0.4
-----------------------------------------------------------------------------
Listing grading context for course edx/999/Test_Course
Listing grading context for course {}
graded sections:
[]
all descriptors:
length=0"""
length=0""".format(world.course_key)
assert_in(expected_config, world.css_text('#data-grade-config-text'))
......@@ -74,7 +74,8 @@ def find_grade_report_csv_link(step): # pylint: disable=unused-argument
reload_the_page(step)
world.wait_for_visible('#report-downloads-table')
# Find table and assert a .csv file is present
expected_file_regexp = 'edx_999_Test_Course_grade_report_\d{4}-\d{2}-\d{2}-\d{4}\.csv'
quoted_id = http.urlquote(world.course_key).replace('/', '_')
expected_file_regexp = quoted_id + '_grade_report_\d{4}-\d{2}-\d{2}-\d{4}\.csv'
assert_regexp_matches(
world.css_html('#report-downloads-table'), expected_file_regexp,
msg="Expected grade report filename was not found."
......
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