Merge pull request #7923 from edx/christina/show-notes

Tags Tab in Student Notes
This commit is contained in:
Christina Roberts
2015-05-14 12:30:38 -04:00
22 changed files with 662 additions and 96 deletions

View File

@@ -34,9 +34,9 @@ class NoteChild(PageObject):
return None
class EdxNotesPageGroup(NoteChild):
class EdxNotesChapterGroup(NoteChild):
"""
Helper class that works with note groups on Note page of the course.
Helper class that works with chapter (section) grouping of notes in the Course Structure view on the Note page.
"""
BODY_SELECTOR = ".note-group"
@@ -51,18 +51,16 @@ class EdxNotesPageGroup(NoteChild):
@property
def children(self):
children = self.q(css=self._bounded_selector('.note-section'))
return [EdxNotesPageSection(self.browser, child.get_attribute("id")) for child in children]
return [EdxNotesSubsectionGroup(self.browser, child.get_attribute("id")) for child in children]
class EdxNotesPageSection(NoteChild):
class EdxNotesGroupMixin(object):
"""
Helper class that works with note sections on Note page of the course.
Helper mixin that works with note groups (used for subsection and tag groupings).
"""
BODY_SELECTOR = ".note-section"
@property
def title(self):
return self._get_element_text(".course-subtitle")
return self._get_element_text(self.TITLE_SELECTOR)
@property
def children(self):
@@ -74,12 +72,49 @@ class EdxNotesPageSection(NoteChild):
return [section.text for section in self.children]
class EdxNotesSubsectionGroup(NoteChild, EdxNotesGroupMixin):
"""
Helper class that works with subsection grouping of notes in the Course Structure view on the Note page.
"""
BODY_SELECTOR = ".note-section"
TITLE_SELECTOR = ".course-subtitle"
class EdxNotesTagsGroup(NoteChild, EdxNotesGroupMixin):
"""
Helper class that works with tags grouping of notes in the Tags view on the Note page.
"""
BODY_SELECTOR = ".note-group"
TITLE_SELECTOR = ".tags-title"
def scrolled_to_top(self, group_index):
"""
Returns True if the group with supplied group)index is scrolled near the top of the page
(expects 10 px padding).
The group_index must be supplied because JQuery must be used to get this information, and it
does not have access to the bounded selector.
"""
title_selector = "$('" + self.TITLE_SELECTOR + "')[" + str(group_index) + "]"
top_script = "return " + title_selector + ".getBoundingClientRect().top;"
EmptyPromise(
lambda: 8 < self.browser.execute_script(top_script) < 12,
"Expected tag title '{}' to scroll to top, but was at location {}".format(
self.title, self.browser.execute_script(top_script)
)
).fulfill()
# Now also verify that focus has moved to this title (for screen readers):
active_script = "return " + title_selector + " === document.activeElement;"
return self.browser.execute_script(active_script)
class EdxNotesPageItem(NoteChild):
"""
Helper class that works with note items on Note page of the course.
"""
BODY_SELECTOR = ".note"
UNIT_LINK_SELECTOR = "a.reference-unit-link"
TAG_SELECTOR = "a.reference-tags"
def go_to_unit(self, unit_page=None):
self.q(css=self._bounded_selector(self.UNIT_LINK_SELECTOR)).click()
@@ -102,6 +137,18 @@ class EdxNotesPageItem(NoteChild):
def time_updated(self):
return self._get_element_text(".reference-updated-date")
@property
def tags(self):
""" The tags associated with this note. """
tag_links = self.q(css=self._bounded_selector(self.TAG_SELECTOR))
if len(tag_links) == 0:
return None
return[tag_link.text for tag_link in tag_links]
def go_to_tag(self, tag_name):
""" Clicks a tag associated with the note to change to the tags view (and scroll to the tag group). """
self.q(css=self._bounded_selector(self.TAG_SELECTOR)).filter(lambda el: tag_name in el.text).click()
class EdxNotesPageView(PageObject):
"""
@@ -174,7 +221,17 @@ class CourseStructureView(EdxNotesPageView):
BODY_SELECTOR = "#structure-panel"
TAB_SELECTOR = ".tab#view-course-structure"
CHILD_SELECTOR = ".note-group"
CHILD_CLASS = EdxNotesPageGroup
CHILD_CLASS = EdxNotesChapterGroup
class TagsView(EdxNotesPageView):
"""
Helper class for Tags view.
"""
BODY_SELECTOR = "#tags-panel"
TAB_SELECTOR = ".tab#view-tags"
CHILD_SELECTOR = ".note-group"
CHILD_CLASS = EdxNotesTagsGroup
class SearchResultsView(EdxNotesPageView):
@@ -193,6 +250,7 @@ class EdxNotesPage(CoursePage):
MAPPING = {
"recent": RecentActivityView,
"structure": CourseStructureView,
"tags": TagsView,
"search": SearchResultsView,
}
@@ -210,9 +268,9 @@ class EdxNotesPage(CoursePage):
self.current_view = self.MAPPING[tab_name](self.browser)
self.current_view.visit()
def close_tab(self, tab_name):
def close_tab(self):
"""
Closes the tab `tab_name(str)`.
Closes the current view.
"""
self.current_view.close()
self.current_view = self.MAPPING["recent"](self.browser)
@@ -267,20 +325,28 @@ class EdxNotesPage(CoursePage):
return [EdxNotesPageItem(self.browser, child.get_attribute("id")) for child in children]
@property
def groups(self):
def chapter_groups(self):
"""
Returns all groups on the page.
Returns all chapter groups on the page.
"""
children = self.q(css='.note-group')
return [EdxNotesPageGroup(self.browser, child.get_attribute("id")) for child in children]
return [EdxNotesChapterGroup(self.browser, child.get_attribute("id")) for child in children]
@property
def sections(self):
def subsection_groups(self):
"""
Returns all sections on the page.
Returns all subsection groups on the page.
"""
children = self.q(css='.note-section')
return [EdxNotesPageSection(self.browser, child.get_attribute("id")) for child in children]
return [EdxNotesSubsectionGroup(self.browser, child.get_attribute("id")) for child in children]
@property
def tag_groups(self):
"""
Returns all tag groups on the page.
"""
children = self.q(css='.note-group')
return [EdxNotesTagsGroup(self.browser, child.get_attribute("id")) for child in children]
class EdxNotesPageNoContent(CoursePage):

View File

@@ -340,7 +340,11 @@ class EdxNotesPageTest(EdxNotesTestMixin):
self.edxnotes_fixture.create_notes(notes_list)
self.edxnotes_fixture.install()
def _add_default_notes(self):
def _add_default_notes(self, tags=None):
"""
Creates 5 test notes. If tags are not specified, will populate the notes with some test tag data.
If tags are specified, they will be used for each of the 3 notes that have tags.
"""
xblocks = self.course_fixture.get_nested_xblocks(category="html")
self._add_notes([
Note(
@@ -358,6 +362,7 @@ class EdxNotesPageTest(EdxNotesTestMixin):
text="",
quote=u"Annotate this text",
updated=datetime(2012, 1, 1, 1, 1, 1, 1).isoformat(),
tags=["Review", "cool"] if tags is None else tags
),
Note(
usage_id=xblocks[0].locator,
@@ -367,6 +372,7 @@ class EdxNotesPageTest(EdxNotesTestMixin):
quote="Annotate this text",
updated=datetime(2013, 1, 1, 1, 1, 1, 1).isoformat(),
ranges=[Range(startOffset=0, endOffset=18)],
tags=["Cool", "TODO"] if tags is None else tags
),
Note(
usage_id=xblocks[3].locator,
@@ -375,6 +381,7 @@ class EdxNotesPageTest(EdxNotesTestMixin):
text="Fourth note",
quote="",
updated=datetime(2014, 1, 1, 1, 1, 1, 1).isoformat(),
tags=["review"] if tags is None else tags
),
Note(
usage_id=xblocks[1].locator,
@@ -386,23 +393,28 @@ class EdxNotesPageTest(EdxNotesTestMixin):
),
])
def assertNoteContent(self, item, text=None, quote=None, unit_name=None, time_updated=None):
if item.text is not None:
self.assertEqual(text, item.text)
else:
self.assertIsNone(text)
def assertNoteContent(self, item, text=None, quote=None, unit_name=None, time_updated=None, tags=None):
""" Verifies the expected properties of the note. """
self.assertEqual(text, item.text)
if item.quote is not None:
self.assertIn(quote, item.quote)
else:
self.assertIsNone(quote)
self.assertEqual(unit_name, item.unit_name)
self.assertEqual(time_updated, item.time_updated)
self.assertEqual(tags, item.tags)
def assertGroupContent(self, item, title=None, subtitles=None):
def assertChapterContent(self, item, title=None, subtitles=None):
"""
Verifies the expected title and subsection titles (subtitles) for the given chapter.
"""
self.assertEqual(item.title, title)
self.assertEqual(item.subtitles, subtitles)
def assertSectionContent(self, item, title=None, notes=None):
def assertGroupContent(self, item, title=None, notes=None):
"""
Verifies the expected title and child notes for the given group.
"""
self.assertEqual(item.title, title)
self.assertEqual(item.notes, notes)
@@ -444,7 +456,8 @@ class EdxNotesPageTest(EdxNotesTestMixin):
notes[1],
text=u"Fourth note",
unit_name="Test Unit 3",
time_updated="Jan 01, 2014 at 01:01 UTC"
time_updated="Jan 01, 2014 at 01:01 UTC",
tags=["review"]
)
self.assertNoteContent(
@@ -452,14 +465,16 @@ class EdxNotesPageTest(EdxNotesTestMixin):
quote="Annotate this text",
text=u"Third note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2013 at 01:01 UTC"
time_updated="Jan 01, 2013 at 01:01 UTC",
tags=["Cool", "TODO"]
)
self.assertNoteContent(
notes[3],
quote=u"Annotate this text",
unit_name="Test Unit 2",
time_updated="Jan 01, 2012 at 01:01 UTC"
time_updated="Jan 01, 2012 at 01:01 UTC",
tags=["Review", "cool"]
)
self.assertNoteContent(
@@ -483,19 +498,19 @@ class EdxNotesPageTest(EdxNotesTestMixin):
self.notes_page.visit().switch_to_tab("structure")
notes = self.notes_page.notes
groups = self.notes_page.groups
sections = self.notes_page.sections
groups = self.notes_page.chapter_groups
sections = self.notes_page.subsection_groups
self.assertEqual(len(notes), 5)
self.assertEqual(len(groups), 2)
self.assertEqual(len(sections), 3)
self.assertGroupContent(
self.assertChapterContent(
groups[0],
title=u"Test Section 1",
subtitles=[u"Test Subsection 1", u"Test Subsection 2"]
)
self.assertSectionContent(
self.assertGroupContent(
sections[0],
title=u"Test Subsection 1",
notes=[u"Fifth note", u"Third note", None]
@@ -514,17 +529,19 @@ class EdxNotesPageTest(EdxNotesTestMixin):
quote=u"Annotate this text",
text=u"Third note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2013 at 01:01 UTC"
time_updated="Jan 01, 2013 at 01:01 UTC",
tags=["Cool", "TODO"]
)
self.assertNoteContent(
notes[2],
quote=u"Annotate this text",
unit_name="Test Unit 2",
time_updated="Jan 01, 2012 at 01:01 UTC"
time_updated="Jan 01, 2012 at 01:01 UTC",
tags=["Review", "cool"]
)
self.assertSectionContent(
self.assertGroupContent(
sections[1],
title=u"Test Subsection 2",
notes=[u"Fourth note"]
@@ -534,16 +551,17 @@ class EdxNotesPageTest(EdxNotesTestMixin):
notes[3],
text=u"Fourth note",
unit_name="Test Unit 3",
time_updated="Jan 01, 2014 at 01:01 UTC"
time_updated="Jan 01, 2014 at 01:01 UTC",
tags=["review"]
)
self.assertGroupContent(
self.assertChapterContent(
groups[1],
title=u"Test Section 2",
subtitles=[u"Test Subsection 3"],
)
self.assertSectionContent(
self.assertGroupContent(
sections[2],
title=u"Test Subsection 3",
notes=[u"First note"]
@@ -557,6 +575,108 @@ class EdxNotesPageTest(EdxNotesTestMixin):
time_updated="Jan 01, 2011 at 01:01 UTC"
)
def test_tags_view(self):
"""
Scenario: User can view all notes by associated tags.
Given I have a course with 5 notes and I am viewing the Notes page
When I switch to the "Tags" view
Then I see 4 tag groups
And I see correct content in the notes and groups
"""
self._add_default_notes()
self.notes_page.visit().switch_to_tab("tags")
notes = self.notes_page.notes
groups = self.notes_page.tag_groups
self.assertEqual(len(notes), 7)
self.assertEqual(len(groups), 4)
# Tag group "cool"
self.assertGroupContent(
groups[0],
title=u"cool (2)",
notes=[u"Third note", None]
)
self.assertNoteContent(
notes[0],
quote=u"Annotate this text",
text=u"Third note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2013 at 01:01 UTC",
tags=["Cool", "TODO"]
)
self.assertNoteContent(
notes[1],
quote=u"Annotate this text",
unit_name="Test Unit 2",
time_updated="Jan 01, 2012 at 01:01 UTC",
tags=["Review", "cool"]
)
# Tag group "review"
self.assertGroupContent(
groups[1],
title=u"review (2)",
notes=[u"Fourth note", None]
)
self.assertNoteContent(
notes[2],
text=u"Fourth note",
unit_name="Test Unit 3",
time_updated="Jan 01, 2014 at 01:01 UTC",
tags=["review"]
)
self.assertNoteContent(
notes[3],
quote=u"Annotate this text",
unit_name="Test Unit 2",
time_updated="Jan 01, 2012 at 01:01 UTC",
tags=["Review", "cool"]
)
# Tag group "todo"
self.assertGroupContent(
groups[2],
title=u"todo (1)",
notes=["Third note"]
)
self.assertNoteContent(
notes[4],
quote=u"Annotate this text",
text=u"Third note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2013 at 01:01 UTC",
tags=["Cool", "TODO"]
)
# Notes with no tags
self.assertGroupContent(
groups[3],
title=u"[no tags] (2)",
notes=["Fifth note", "First note"]
)
self.assertNoteContent(
notes[5],
quote=u"Annotate this text",
text=u"Fifth note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2015 at 01:01 UTC"
)
self.assertNoteContent(
notes[6],
quote=u"Annotate this text",
text=u"First note",
unit_name="Test Unit 4",
time_updated="Jan 01, 2011 at 01:01 UTC"
)
def test_easy_access_from_notes_page(self):
"""
Scenario: Ensure that the link to the Unit works correctly.
@@ -618,14 +738,102 @@ class EdxNotesPageTest(EdxNotesTestMixin):
# Error message disappears
self.assertFalse(self.notes_page.is_error_visible)
self.assertIn(u"Search Results", self.notes_page.tabs)
self.assertEqual(len(self.notes_page.notes), 4)
notes = self.notes_page.notes
self.assertEqual(len(notes), 4)
self.assertNoteContent(
notes[0],
quote=u"Annotate this text",
text=u"Fifth note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2015 at 01:01 UTC"
)
self.assertNoteContent(
notes[1],
text=u"Fourth note",
unit_name="Test Unit 3",
time_updated="Jan 01, 2014 at 01:01 UTC",
tags=["review"]
)
self.assertNoteContent(
notes[2],
quote="Annotate this text",
text=u"Third note",
unit_name="Test Unit 1",
time_updated="Jan 01, 2013 at 01:01 UTC",
tags=["Cool", "TODO"]
)
self.assertNoteContent(
notes[3],
quote=u"Annotate this text",
text=u"First note",
unit_name="Test Unit 4",
time_updated="Jan 01, 2011 at 01:01 UTC"
)
def test_scroll_to_tag_recent_activity(self):
"""
Scenario: Can scroll to a tag group from the Recent Activity view (default view)
Given I have a course with 5 notes and I open the Notes page
When I click on a tag associated with a note
Then the Tags view tab gets focus and I scroll to the section of notes associated with that tag
"""
self._add_default_notes(["apple", "banana", "kiwi", "pear", "pumpkin", "squash", "zucchini"])
self.notes_page.visit()
self._scroll_to_tag_and_verify("pear", 3)
def test_scroll_to_tag_course_structure(self):
"""
Scenario: Can scroll to a tag group from the Course Structure view
Given I have a course with 5 notes and I open the Notes page and select the Course Structure view
When I click on a tag associated with a note
Then the Tags view tab gets focus and I scroll to the section of notes associated with that tag
"""
self._add_default_notes(["apple", "banana", "kiwi", "pear", "pumpkin", "squash", "zucchini"])
self.notes_page.visit().switch_to_tab("structure")
self._scroll_to_tag_and_verify("squash", 5)
def test_scroll_to_tag_search(self):
"""
Scenario: Can scroll to a tag group from the Search Results view
Given I have a course with 5 notes and I open the Notes page and perform a search
Then the Search view tab opens and gets focus
And when I click on a tag associated with a note
Then the Tags view tab gets focus and I scroll to the section of notes associated with that tag
"""
self._add_default_notes(["apple", "banana", "kiwi", "pear", "pumpkin", "squash", "zucchini"])
self.notes_page.visit().search("note")
self._scroll_to_tag_and_verify("pumpkin", 4)
def test_scroll_to_tag_from_tag_view(self):
"""
Scenario: Can scroll to a tag group from the Tags view
Given I have a course with 5 notes and I open the Notes page and select the Tag view
When I click on a tag associated with a note
Then I scroll to the section of notes associated with that tag
"""
self._add_default_notes(["apple", "banana", "kiwi", "pear", "pumpkin", "squash", "zucchini"])
self.notes_page.visit().switch_to_tab("tags")
self._scroll_to_tag_and_verify("kiwi", 2)
def _scroll_to_tag_and_verify(self, tag_name, group_index):
""" Helper method for all scroll to tag tests """
self.notes_page.notes[1].go_to_tag(tag_name)
# Because all the notes (with tags) have the same tags, they will end up ordered alphabetically.
pear_group = self.notes_page.tag_groups[group_index]
self.assertEqual(tag_name + " (3)", pear_group.title)
self.assertTrue(pear_group.scrolled_to_top(group_index))
def test_tabs_behaves_correctly(self):
"""
Scenario: Tabs behaves correctly.
Given I have a course with 5 notes
When I open Notes page
Then I see only "Recent Activity" and "Location in Course" tabs
Then I see only "Recent Activity", "Location in Course", and "Tags" tabs
When I run the search with "note" query
And I see that "Search Results" tab appears with 4 notes found
Then I switch to "Recent Activity" tab
@@ -643,24 +851,24 @@ class EdxNotesPageTest(EdxNotesTestMixin):
self.notes_page.visit()
# We're on Recent Activity tab.
self.assertEqual(len(self.notes_page.tabs), 2)
self.assertEqual([u"Recent Activity", u"Location in Course"], self.notes_page.tabs)
self.assertEqual(len(self.notes_page.tabs), 3)
self.assertEqual([u"Recent Activity", u"Location in Course", u"Tags"], self.notes_page.tabs)
self.notes_page.search("note")
# We're on Search Results tab
self.assertEqual(len(self.notes_page.tabs), 3)
self.assertEqual(len(self.notes_page.tabs), 4)
self.assertIn(u"Search Results", self.notes_page.tabs)
self.assertEqual(len(self.notes_page.notes), 4)
# We can switch on Recent Activity tab and back.
self.notes_page.switch_to_tab("recent")
self.assertEqual(len(self.notes_page.notes), 5)
self.notes_page.switch_to_tab("structure")
self.assertEqual(len(self.notes_page.groups), 2)
self.assertEqual(len(self.notes_page.chapter_groups), 2)
self.assertEqual(len(self.notes_page.notes), 5)
self.notes_page.switch_to_tab("search")
self.assertEqual(len(self.notes_page.notes), 4)
# Can close search results page
self.notes_page.close_tab("search")
self.assertEqual(len(self.notes_page.tabs), 2)
self.notes_page.close_tab()
self.assertEqual(len(self.notes_page.tabs), 3)
self.assertNotIn(u"Search Results", self.notes_page.tabs)
self.assertEqual(len(self.notes_page.notes), 5)