Commit 382909b7 by Peter Fogg

Add sorting controls on Teams topics page.

TNL-1936
parent f01fd6e7
......@@ -82,7 +82,7 @@
setPage: function (page) {
var oldPage = this.currentPage,
self = this;
this.goTo(page - (this.isZeroIndexed ? 1 : 0), {reset: true}).then(
return this.goTo(page - (this.isZeroIndexed ? 1 : 0), {reset: true}).then(
function () {
self.trigger('page_changed');
},
......
......@@ -9,12 +9,16 @@
var PagingHeader = Backbone.View.extend({
initialize: function (options) {
this.srInfo = options.srInfo;
this.collections = options.collection;
this.showSortControls = options.showSortControls;
this.collection.bind('add', _.bind(this.render, this));
this.collection.bind('remove', _.bind(this.render, this));
this.collection.bind('reset', _.bind(this.render, this));
},
events: {
'change #paging-header-select': 'sortCollection'
},
render: function () {
var message,
start = _.isUndefined(this.collection.start) ? 0 : this.collection.start,
......@@ -31,9 +35,18 @@
}
this.$el.html(_.template(headerTemplate, {
message: message,
srInfo: this.srInfo
srInfo: this.srInfo,
sortableFields: this.collection.sortableFields,
sortOrder: this.sortOrder,
showSortControls: this.showSortControls
}));
return this;
},
sortCollection: function () {
var selected = this.$('#paging-header-select option:selected');
this.sortOrder = selected.attr('value');
this.collection.setSortField(this.sortOrder);
}
});
return PagingHeader;
......
......@@ -8,7 +8,7 @@ define([
var pagingHeader,
newCollection = function (size, perPage) {
var pageSize = 5,
results = _.map(_.range(size), function () { return {}; });
results = _.map(_.range(size), function (i) { return {foo: i}; });
var collection = new PagingCollection(
{
count: results.length,
......@@ -22,6 +22,14 @@ define([
collection.start = 0;
collection.totalCount = results.length;
return collection;
},
sortableHeader = function (sortable) {
var collection = newCollection(5, 4);
collection.registerSortableField('foo', 'Display Name');
return new PagingHeader({
collection: collection,
showSortControls: _.isUndefined(sortable) ? true : sortable
});
};
it('correctly displays which items are being viewed', function () {
......@@ -47,5 +55,16 @@ define([
expect(pagingHeader.$el.find('.search-count').text())
.toContain('Showing 1 out of 1 total');
});
it('optionally shows sorting controls', function () {
pagingHeader = sortableHeader().render();
expect(pagingHeader.$el.find('.listing-sort').text())
.toMatch(/Sorted by\s+Display Name/);
});
it('does not show sorting controls if the `showSortControls` option is not passed', function () {
pagingHeader = sortableHeader(false).render();
expect(pagingHeader.$el.text()).not.toContain('Sorted by');
});
});
});
<% if (!_.isUndefined(srInfo)) { %>
<h2 class="sr" id="<%= srInfo.id %>"><%- srInfo.text %></h2>
<% } %>
<div class="search-tools">
<span class="search-count">
<div class="search-tools listing-tools">
<span class="search-count listing-count">
<%= message %>
</span>
<% if (showSortControls) { %>
|
<span class="field listing-sort">
<label class="field-label" for="paging-header-select"><%- gettext("Sorted by") %></label>
<select id="paging-header-select" name="paging-header-select" class="field-input input-select listing-sort-select">
<% _.each(sortableFields, function (option, key) { %>
<option value="<%= key %>" <% if (key === sortOrder) { %> selected="true" <% } %>>
<%- option.displayName %>
</option>
<% }) %>
</select>
</span>
<% } %>
</div>
......@@ -11,6 +11,7 @@ from .fields import FieldsMixin
TOPIC_CARD_CSS = 'div.wrapper-card-core'
CARD_TITLE_CSS = 'h3.card-title'
MY_TEAMS_BUTTON_CSS = 'a.nav-item[data-index="0"]'
BROWSE_BUTTON_CSS = 'a.nav-item[data-index="1"]'
TEAMS_LINK_CSS = '.action-view'
......@@ -121,6 +122,11 @@ class BrowseTopicsPage(CoursePage, PaginatedUIMixin):
"""Return a list of the topic cards present on the page."""
return self.q(css=TOPIC_CARD_CSS).results
@property
def topic_names(self):
"""Return a list of the topic names present on the page."""
return self.q(css=CARD_TITLE_CSS).map(lambda e: e.text).results
def browse_teams_for_topic(self, topic_name):
"""
Show the teams list for `topic_name`.
......@@ -130,6 +136,13 @@ class BrowseTopicsPage(CoursePage, PaginatedUIMixin):
)[0].click()
self.wait_for_ajax()
def sort_topics_by(self, sort_order):
"""Sort the list of topics by the given `sort_order`."""
self.q(
css='#paging-header-select option[value={sort_order}]'.format(sort_order=sort_order)
).click()
self.wait_for_ajax()
class BrowseTeamsPage(CoursePage, PaginatedUIMixin):
"""
......@@ -388,3 +401,8 @@ class TeamPage(CoursePage, PaginatedUIMixin):
def new_post_button_present(self):
""" Returns True if New Post button is present else False """
return self.q(css='.discussion-module .new-post-btn').present
def click_all_topics_breadcrumb(self):
"""Navigate to the 'All Topics' page."""
self.q(css='.breadcrumbs a').results[0].click()
self.wait_for_ajax()
......@@ -2,6 +2,7 @@
Acceptance tests for the teams feature.
"""
import json
import random
import ddt
from flaky import flaky
......@@ -22,6 +23,9 @@ from ...pages.lms.tab_nav import TabNavPage
from ...pages.lms.teams import TeamsPage, MyTeamsPage, BrowseTopicsPage, BrowseTeamsPage, CreateTeamPage, TeamPage
TOPICS_PER_PAGE = 12
class TeamsTabBase(UniqueCourseTest):
"""Base class for Teams Tab tests"""
def setUp(self):
......@@ -274,6 +278,7 @@ class MyTeamsTest(TeamsTabBase):
@attr('shard_5')
@ddt.ddt
class BrowseTopicsTest(TeamsTabBase):
"""
Tests for the Browse tab of the Teams page.
......@@ -283,6 +288,66 @@ class BrowseTopicsTest(TeamsTabBase):
super(BrowseTopicsTest, self).setUp()
self.topics_page = BrowseTopicsPage(self.browser, self.course_id)
@ddt.data(('name', False), ('team_count', True))
@ddt.unpack
def test_sort_topics(self, sort_order, reverse):
"""
Scenario: the user should be able to sort the list of topics by name or team count
Given I am enrolled in a course with team configuration and topics
When I visit the Teams page
And I browse topics
Then I should see a list of topics for the course
When I choose a sort order
Then I should see the paginated list of topics in that order
"""
topics = self.create_topics(TOPICS_PER_PAGE + 1)
self.set_team_configuration({u"max_team_size": 100, u"topics": topics})
for i, topic in enumerate(random.sample(topics, len(topics))):
self.create_teams(topic, i)
topic['team_count'] = i
self.topics_page.visit()
self.topics_page.sort_topics_by(sort_order)
topic_names = self.topics_page.topic_names
self.assertEqual(len(topic_names), TOPICS_PER_PAGE)
self.assertEqual(
topic_names,
[t['name'] for t in sorted(topics, key=lambda t: t[sort_order], reverse=reverse)][:TOPICS_PER_PAGE]
)
def test_sort_topics_update(self):
"""
Scenario: the list of topics should remain sorted after updates
Given I am enrolled in a course with team configuration and topics
When I visit the Teams page
And I browse topics and choose a sort order
Then I should see the paginated list of topics in that order
When I create a team in one of those topics
And I return to the topics list
Then I should see the topics in the correct sorted order
"""
topics = self.create_topics(3)
self.set_team_configuration({u"max_team_size": 100, u"topics": topics})
self.topics_page.visit()
self.topics_page.sort_topics_by('team_count')
topic_name = self.topics_page.topic_names[-1]
topic = [t for t in topics if t['name'] == topic_name][0]
self.topics_page.browse_teams_for_topic(topic_name)
browse_teams_page = BrowseTeamsPage(self.browser, self.course_id, topic)
self.assertTrue(browse_teams_page.is_browser_on_page())
browse_teams_page.click_create_team_link()
create_team_page = CreateTeamPage(self.browser, self.course_id, topic)
create_team_page.value_for_text_field(field_id='name', value='Team Name', press_enter=False)
create_team_page.value_for_textarea_field(
field_id='description',
value='Team description.'
)
create_team_page.submit_form()
team_page = TeamPage(self.browser, self.course_id)
self.assertTrue(team_page.is_browser_on_page)
team_page.click_all_topics_breadcrumb()
self.assertTrue(self.topics_page.is_browser_on_page())
self.assertEqual(topic_name, self.topics_page.topic_names[0])
def test_list_topics(self):
"""
Scenario: a list of topics should be visible in the "Browse" tab
......@@ -294,7 +359,7 @@ class BrowseTopicsTest(TeamsTabBase):
self.set_team_configuration({u"max_team_size": 10, u"topics": self.create_topics(2)})
self.topics_page.visit()
self.assertEqual(len(self.topics_page.topic_cards), 2)
self.assertEqual(self.topics_page.get_pagination_header_text(), 'Showing 1-2 out of 2 total')
self.assertTrue(self.topics_page.get_pagination_header_text().startswith('Showing 1-2 out of 2 total'))
self.assertFalse(self.topics_page.pagination_controls_visible())
self.assertFalse(self.topics_page.is_previous_page_button_enabled())
self.assertFalse(self.topics_page.is_next_page_button_enabled())
......@@ -309,8 +374,8 @@ class BrowseTopicsTest(TeamsTabBase):
"""
self.set_team_configuration({u"max_team_size": 10, u"topics": self.create_topics(20)})
self.topics_page.visit()
self.assertEqual(len(self.topics_page.topic_cards), 12)
self.assertEqual(self.topics_page.get_pagination_header_text(), 'Showing 1-12 out of 20 total')
self.assertEqual(len(self.topics_page.topic_cards), TOPICS_PER_PAGE)
self.assertTrue(self.topics_page.get_pagination_header_text().startswith('Showing 1-12 out of 20 total'))
self.assertTrue(self.topics_page.pagination_controls_visible())
self.assertFalse(self.topics_page.is_previous_page_button_enabled())
self.assertTrue(self.topics_page.is_next_page_button_enabled())
......@@ -360,10 +425,10 @@ class BrowseTopicsTest(TeamsTabBase):
self.topics_page.visit()
self.topics_page.press_next_page_button()
self.assertEqual(len(self.topics_page.topic_cards), 1)
self.assertEqual(self.topics_page.get_pagination_header_text(), 'Showing 13-13 out of 13 total')
self.assertTrue(self.topics_page.get_pagination_header_text().startswith('Showing 13-13 out of 13 total'))
self.topics_page.press_previous_page_button()
self.assertEqual(len(self.topics_page.topic_cards), 12)
self.assertEqual(self.topics_page.get_pagination_header_text(), 'Showing 1-12 out of 13 total')
self.assertEqual(len(self.topics_page.topic_cards), TOPICS_PER_PAGE)
self.assertTrue(self.topics_page.get_pagination_header_text().startswith('Showing 1-12 out of 13 total'))
def test_topic_description_truncation(self):
"""
......
......@@ -27,7 +27,7 @@
var self = this,
deferred = $.Deferred();
if (force || this.isStale) {
this.fetch()
this.setPage(1)
.done(function() {
self.isStale = false;
deferred.resolve();
......
......@@ -3,8 +3,9 @@
define([
'gettext',
'teams/js/views/topic_card',
'common/js/components/views/paging_header',
'common/js/components/views/paginated_view'
], function (gettext, TopicCardView, PaginatedView) {
], function (gettext, TopicCardView, PagingHeader, PaginatedView) {
var TopicsView = PaginatedView.extend({
type: 'topics',
......@@ -21,11 +22,18 @@
PaginatedView.prototype.initialize.call(this);
},
createHeaderView: function () {
return new PagingHeader({
collection: this.options.collection,
srInfo: this.srInfo,
showSortControls: true
});
},
render: function() {
var self = this;
this.collection.refresh()
.done(function() {
self.collection.isStale = false;
PaginatedView.prototype.render.call(self);
});
return this;
......
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