Merge pull request #11363 from edx/notes-pagination

Notes pagination
This commit is contained in:
Muzaffar yousaf
2016-03-10 17:26:54 +05:00
41 changed files with 2053 additions and 589 deletions

View File

@@ -63,3 +63,8 @@ class PaginatedUIMixin(object):
def is_enabled(self, css):
"""Return whether the given element is not disabled."""
return 'is-disabled' not in self.q(css=css).attrs('class')[0]
@property
def footer_visible(self):
""" Return True if footer is visible else False"""
return self.q(css='.pagination.bottom').visible

View File

@@ -1,6 +1,7 @@
from bok_choy.page_object import PageObject, PageLoadError, unguarded
from bok_choy.promise import BrokenPromise, EmptyPromise
from .course_page import CoursePage
from ..common.paging import PaginatedUIMixin
from ...tests.helpers import disable_animations
from selenium.webdriver.common.action_chains import ActionChains
@@ -114,7 +115,7 @@ class EdxNotesPageItem(NoteChild):
"""
BODY_SELECTOR = ".note"
UNIT_LINK_SELECTOR = "a.reference-unit-link"
TAG_SELECTOR = "a.reference-tags"
TAG_SELECTOR = "span.reference-tags"
def go_to_unit(self, unit_page=None):
self.q(css=self._bounded_selector(self.UNIT_LINK_SELECTOR)).click()
@@ -242,7 +243,7 @@ class SearchResultsView(EdxNotesPageView):
TAB_SELECTOR = ".tab#view-search-results"
class EdxNotesPage(CoursePage):
class EdxNotesPage(CoursePage, PaginatedUIMixin):
"""
EdxNotes page.
"""
@@ -348,6 +349,10 @@ class EdxNotesPage(CoursePage):
children = self.q(css='.note-group')
return [EdxNotesTagsGroup(self.browser, child.get_attribute("id")) for child in children]
def count(self):
""" Returns the total number of notes in the list """
return len(self.q(css='div.wrapper-note-excerpts').results)
class EdxNotesPageNoContent(CoursePage):
"""

View File

@@ -1,17 +1,18 @@
"""
Test LMS Notes
"""
from unittest import skip
import random
from uuid import uuid4
from datetime import datetime
from nose.plugins.attrib import attr
from ..helpers import UniqueCourseTest
from ..helpers import UniqueCourseTest, EventsTestMixin
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.course_nav import CourseNavPage
from ...pages.lms.courseware import CoursewarePage
from ...pages.lms.edxnotes import EdxNotesUnitPage, EdxNotesPage, EdxNotesPageNoContent
from ...fixtures.edxnotes import EdxNotesFixture, Note, Range
from ..helpers import EventsTestMixin
class EdxNotesTestMixin(UniqueCourseTest):
@@ -345,9 +346,10 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
self.edxnotes_fixture.create_notes(notes_list)
self.edxnotes_fixture.install()
def _add_default_notes(self, tags=None):
def _add_default_notes(self, tags=None, extra_notes=0):
"""
Creates 5 test notes. If tags are not specified, will populate the notes with some test tag data.
Creates 5 test notes by default & number of extra_notes will be created if specified.
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")
@@ -398,6 +400,19 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
updated=datetime(2015, 1, 1, 1, 1, 1, 1).isoformat()
),
]
if extra_notes > 0:
for __ in range(extra_notes):
self.raw_note_list.append(
Note(
usage_id=xblocks[random.choice([0, 1, 2, 3, 4, 5])].locator,
user=self.username,
course_id=self.course_fixture._course_key, # pylint: disable=protected-access
text="Fourth note",
quote="",
updated=datetime(2014, 1, 1, 1, 1, 1, 1).isoformat(),
tags=["review"] if tags is None else tags
)
)
self._add_notes(self.raw_note_list)
def assertNoteContent(self, item, text=None, quote=None, unit_name=None, time_updated=None, tags=None):
@@ -469,6 +484,44 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
]
self.assert_events_match(expected_events, actual_events)
def _verify_pagination_info(
self,
notes_count_on_current_page,
header_text,
previous_button_enabled,
next_button_enabled,
current_page_number,
total_pages
):
"""
Verify pagination info
"""
self.assertEqual(self.notes_page.count(), notes_count_on_current_page)
self.assertEqual(self.notes_page.get_pagination_header_text(), header_text)
if total_pages > 1:
self.assertEqual(self.notes_page.footer_visible, True)
self.assertEqual(self.notes_page.is_previous_page_button_enabled(), previous_button_enabled)
self.assertEqual(self.notes_page.is_next_page_button_enabled(), next_button_enabled)
self.assertEqual(self.notes_page.get_current_page_number(), current_page_number)
self.assertEqual(self.notes_page.get_total_pages, total_pages)
else:
self.assertEqual(self.notes_page.footer_visible, False)
def search_and_verify(self):
"""
Add, search and verify notes.
"""
self._add_default_notes(extra_notes=22)
self.notes_page.visit()
# Run the search
self.notes_page.search("note")
# No error message appears
self.assertFalse(self.notes_page.is_error_visible)
self.assertIn(u"Search Results", self.notes_page.tabs)
self.assertEqual(self.notes_page.get_total_pages, 2)
def test_no_content(self):
"""
Scenario: User can see `No content` message.
@@ -482,6 +535,57 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
"You have not made any notes in this course yet. Other students in this course are using notes to:",
notes_page_empty.no_content_text)
def test_notes_works_correctly_with_xss(self):
"""
Scenario: Note text & tags should be HTML and JS escaped
Given I am enrolled in a course with notes enabled
When I visit the Notes page, with a Notes text and tag containing HTML characters like < and >
Then the text and tags appear as expected due to having been properly escaped
"""
xblocks = self.course_fixture.get_nested_xblocks(category="html")
self._add_notes([
Note(
usage_id=xblocks[0].locator,
user=self.username,
course_id=self.course_fixture._course_key, # pylint: disable=protected-access
text='<script>alert("XSS")</script>',
quote="quote",
updated=datetime(2014, 1, 1, 1, 1, 1, 1).isoformat(),
tags=['<script>alert("XSS")</script>']
),
Note(
usage_id=xblocks[1].locator,
user=self.username,
course_id=self.course_fixture._course_key, # pylint: disable=protected-access
text='<b>bold</b>',
quote="quote",
updated=datetime(2014, 2, 1, 1, 1, 1, 1).isoformat(),
tags=['<i>bold</i>']
)
])
self.notes_page.visit()
notes = self.notes_page.notes
self.assertEqual(len(notes), 2)
self.assertNoteContent(
notes[0],
quote=u"quote",
text='<b>bold</b>',
unit_name="Test Unit 1",
time_updated="Feb 01, 2014 at 01:01 UTC",
tags=['<i>bold</i>']
)
self.assertNoteContent(
notes[1],
quote=u"quote",
text='<script>alert("XSS")</script>',
unit_name="Test Unit 1",
time_updated="Jan 01, 2014 at 01:01 UTC",
tags=['<script>alert("XSS")</script>']
)
def test_recent_activity_view(self):
"""
Scenario: User can view all notes by recent activity.
@@ -850,6 +954,7 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
self.assert_viewed_event('Search Results')
self.assert_search_event('note', 4)
@skip("scroll to tag functionality is disabled")
def test_scroll_to_tag_recent_activity(self):
"""
Scenario: Can scroll to a tag group from the Recent Activity view (default view)
@@ -861,6 +966,7 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
self.notes_page.visit()
self._scroll_to_tag_and_verify("pear", 3)
@skip("scroll to tag functionality is disabled")
def test_scroll_to_tag_course_structure(self):
"""
Scenario: Can scroll to a tag group from the Course Structure view
@@ -872,6 +978,7 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
self.notes_page.visit().switch_to_tab("structure")
self._scroll_to_tag_and_verify("squash", 5)
@skip("scroll to tag functionality is disabled")
def test_scroll_to_tag_search(self):
"""
Scenario: Can scroll to a tag group from the Search Results view
@@ -884,6 +991,7 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
self.notes_page.visit().search("note")
self._scroll_to_tag_and_verify("pumpkin", 4)
@skip("scroll to tag functionality is disabled")
def test_scroll_to_tag_from_tag_view(self):
"""
Scenario: Can scroll to a tag group from the Tags view
@@ -1005,6 +1113,291 @@ class EdxNotesPageTest(EventsTestMixin, EdxNotesTestMixin):
note = self.note_unit_page.notes[0]
self.assertFalse(note.is_visible)
def test_page_size_limit(self):
"""
Scenario: Verify that we can't get notes more than default page size.
Given that I am a registered user
And I have a course with 11 notes
When I open Notes page
Then I can see notes list contains 10 items
And I should see paging header and footer with correct data
And I should see disabled previous button
And I should also see enabled next button
"""
self._add_default_notes(extra_notes=21)
self.notes_page.visit()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
def test_pagination_with_single_page(self):
"""
Scenario: Notes list pagination works as expected for single page
Given that I am a registered user
And I have a course with 5 notes
When I open Notes page
Then I can see notes list contains 5 items
And I should see paging header and footer with correct data
And I should see disabled previous and next buttons
"""
self._add_default_notes()
self.notes_page.visit()
self._verify_pagination_info(
notes_count_on_current_page=5,
header_text='Showing 1-5 out of 5 total',
previous_button_enabled=False,
next_button_enabled=False,
current_page_number=1,
total_pages=1
)
def test_next_and_previous_page_button(self):
"""
Scenario: Next & Previous buttons are working as expected for notes list pagination
Given that I am a registered user
And I have a course with 26 notes
When I open Notes page
Then I can see notes list contains 25 items
And I should see paging header and footer with correct data
And I should see disabled previous button
And I should see enabled next button
When I click on next page button in footer
Then I should be navigated to second page
And I should see a list with 1 item
And I should see paging header and footer with correct info
And I should see enabled previous button
And I should also see disabled next button
When I click on previous page button in footer
Then I should be navigated to first page
And I should see a list with 25 items
And I should see paging header and footer with correct info
And I should see disabled previous button
And I should also see enabled next button
"""
self._add_default_notes(extra_notes=21)
self.notes_page.visit()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
self.notes_page.press_next_page_button()
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
self.notes_page.press_previous_page_button()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
def test_pagination_with_valid_and_invalid_page_number(self):
"""
Scenario: Notes list pagination works as expected for valid & invalid page number
Given that I am a registered user
And I have a course with 26 notes
When I open Notes page
Then I can see notes list contains 25 items
And I should see paging header and footer with correct data
And I should see total page value is 2
When I enter 2 in the page number input
Then I should be navigated to page 2
When I enter 3 in the page number input
Then I should not be navigated away from page 2
"""
self._add_default_notes(extra_notes=21)
self.notes_page.visit()
self.assertEqual(self.notes_page.get_total_pages, 2)
# test pagination with valid page number
self.notes_page.go_to_page(2)
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
# test pagination with invalid page number
self.notes_page.go_to_page(3)
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
def test_search_behaves_correctly_with_pagination(self):
"""
Scenario: Searching behaves correctly with pagination.
Given that I am a registered user
And I have a course with 27 notes
When I open Notes page
Then I can see notes list with 25 items
And I should see paging header and footer with correct data
And previous button is disabled
And next button is enabled
When I run the search with "note" query
Then I see no error message
And I see that "Search Results" tab appears with 26 notes found
And an event has fired indicating that the Search Results view was selected
And an event has fired recording the search that was performed
"""
self.search_and_verify()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
self.assert_viewed_event('Search Results')
self.assert_search_event('note', 26)
def test_search_with_next_and_prev_page_button(self):
"""
Scenario: Next & Previous buttons are working as expected for search
Given that I am a registered user
And I have a course with 27 notes
When I open Notes page
Then I can see notes list with 25 items
And I should see paging header and footer with correct data
And previous button is disabled
And next button is enabled
When I run the search with "note" query
Then I see that "Search Results" tab appears with 26 notes found
And an event has fired indicating that the Search Results view was selected
And an event has fired recording the search that was performed
When I click on next page button in footer
Then I should be navigated to second page
And I should see a list with 1 item
And I should see paging header and footer with correct info
And I should see enabled previous button
And I should also see disabled next button
When I click on previous page button in footer
Then I should be navigated to first page
And I should see a list with 25 items
And I should see paging header and footer with correct info
And I should see disabled previous button
And I should also see enabled next button
"""
self.search_and_verify()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
self.assert_viewed_event('Search Results')
self.assert_search_event('note', 26)
self.notes_page.press_next_page_button()
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
self.notes_page.press_previous_page_button()
self._verify_pagination_info(
notes_count_on_current_page=25,
header_text='Showing 1-25 out of 26 total',
previous_button_enabled=False,
next_button_enabled=True,
current_page_number=1,
total_pages=2
)
def test_search_with_valid_and_invalid_page_number(self):
"""
Scenario: Notes list pagination works as expected for valid & invalid page number
Given that I am a registered user
And I have a course with 27 notes
When I open Notes page
Then I can see notes list contains 25 items
And I should see paging header and footer with correct data
And I should see total page value is 2
When I run the search with "note" query
Then I see that "Search Results" tab appears with 26 notes found
And an event has fired indicating that the Search Results view was selected
And an event has fired recording the search that was performed
When I enter 2 in the page number input
Then I should be navigated to page 2
When I enter 3 in the page number input
Then I should not be navigated away from page 2
"""
self.search_and_verify()
# test pagination with valid page number
self.notes_page.go_to_page(2)
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
# test pagination with invalid page number
self.notes_page.go_to_page(3)
self._verify_pagination_info(
notes_count_on_current_page=1,
header_text='Showing 26-26 out of 26 total',
previous_button_enabled=True,
next_button_enabled=False,
current_page_number=2,
total_pages=2
)
@attr('shard_4')
class EdxNotesToggleSingleNoteTest(EdxNotesTestMixin):