Skip to content

Commit

Permalink
Merge pull request #27 from syargeau/feature/all-matches
Browse files Browse the repository at this point in the history
All matches page
  • Loading branch information
syargeau authored Jun 20, 2018
2 parents 82ff4ee + 62a026e commit 6de7847
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 4 deletions.
102 changes: 102 additions & 0 deletions functional_tests/test_all_matches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import time

from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

from leaderboard.models import Player, Match


class AllMatchesTest(LiveServerTestCase):

def setUp(self):
"""Start all tests by setting up an authenticated browser."""
self.browser = webdriver.Firefox()

def tearDown(self):
"""Stop all tests by shutting down the browser."""
self.browser.quit()

def test_all_matches(self):
"""
Test all matches page view.
The page should load the 50 most recent matches, and show links
at the bottom to switch pages.
"""
# Load database with Bob and Sue Hope
bob = Player.objects.create(first_name='Bob', last_name='Hope')
sue = Player.objects.create(first_name='Sue', last_name='Hope')

# Input 30 games
for _ in range(30):
Match.objects.create(
winner=bob,
loser=sue,
winning_score=21,
losing_score=19
)

# Bob loads the home page, and notices a link for all matches.
self.browser.get(self.live_server_url)
all_matches_link = self.browser.find_element_by_id('all-matches-link')
all_matches_link.click()

# It takes him to a page where he sees all matches.
matches_url = self.live_server_url + '/matches/'
self.assertEqual(matches_url, self.browser.current_url)
matches = self.browser.find_elements_by_id('match')
self.assertEqual(len(matches), 30)

# He notices a paginator showing him what page he's on.
current_page = self.browser.find_element_by_id('current-page')
self.assertEqual(current_page.text, 'Page 1 of 1')

# Because there's only 1 page, there are no links to next or previous page
with self.assertRaises(NoSuchElementException):
self.browser.find_element_by_id('previous-page-link')
with self.assertRaises(NoSuchElementException):
self.browser.find_element_by_id('next-page-link')

# Input 80 more games and refresh page
for _ in range(80):
Match.objects.create(
winner=bob,
loser=sue,
winning_score=21,
losing_score=19
)
self.browser.refresh()

# He notices a paginator showing him he's on page 1 of 3 with a link to the next page.
matches = self.browser.find_elements_by_id('match')
self.assertEqual(len(matches), 50)
current_page = self.browser.find_element_by_id('current-page')
self.assertEqual(current_page.text, 'Page 1 of 3')
with self.assertRaises(NoSuchElementException):
self.browser.find_element_by_id('previous-page-link')
next_page_link = self.browser.find_element_by_id('next-page-link')
self.assertEqual(next_page_link.text, 'Next')

# He goes to the next page, and sees a previous page link.
next_page_link.click()
matches = self.browser.find_elements_by_id('match')
self.assertEqual(len(matches), 50)
current_page = self.browser.find_element_by_id('current-page')
self.assertEqual(current_page.text, 'Page 2 of 3')
previous_page_link = self.browser.find_element_by_id('previous-page-link')
self.assertEqual(previous_page_link.text, 'Previous')

# He goes to the final page, and sees no next page link.
self.browser.find_element_by_id('next-page-link').click()
matches = self.browser.find_elements_by_id('match')
self.assertEqual(len(matches), 10)
current_page = self.browser.find_element_by_id('current-page')
self.assertEqual(current_page.text, 'Page 3 of 3')
with self.assertRaises(NoSuchElementException):
self.browser.find_element_by_id('next-page-link')

# He goes back to the previous page.
self.browser.find_element_by_id('previous-page-link').click()
current_page = self.browser.find_element_by_id('current-page')
self.assertEqual(current_page.text, 'Page 2 of 3')
9 changes: 7 additions & 2 deletions leaderboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,17 @@ def score(self):
"""Hyphenated version of match score, i.e. 21-19"""
score = f'{self.winning_score}-{self.losing_score}'
return score

@property
def date(self):
"""Date part of match datetime."""
date = self.datetime.strftime('%m/%d/%Y')
return date

@property
def description(self):
match_date = self.datetime.strftime('%m/%d/%Y')
description = (
f'{match_date}: {self.winner} defeated {self.loser} {self.score}'
f'{self.date}: {self.winner} defeated {self.loser} {self.score}'
)
return description

Expand Down
45 changes: 45 additions & 0 deletions leaderboard/templates/all_matches.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>PongBoard - Matches</title>
</head>

<body>
<h1>All Matches</h1>

<table id="matches">
<tr>
<th>Date</th>
<th>Winner</th>
<th>Loser</th>
<th>Score</th>
</tr>
{% for match in matches %}
<tr id='match'>
<td>{{ match.date }}</td>
<td>{{ match.winner }}</td>
<td>{{ match.loser }}</td>
<td>{{ match.score }}</td>
</tr>
{% endfor %}
</table>

<span id="paginator">
{% if matches.has_previous %}
<a id="previous-page-link" href="{% url 'all_matches' %}?page={{ matches.previous_page_number }}">Previous</a>
{% endif %}

<span id="current-page">
Page {{ matches.number }} of {{ matches.paginator.num_pages }}
</span>

{% if matches.has_next %}
<a id="next-page-link" href="{% url 'all_matches' %}?page={{ matches.next_page_number }}">Next</a>
{% endif %}
</span>


</body>
3 changes: 2 additions & 1 deletion leaderboard/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ <h1>PongBoard</h1>
{% for match in recent_matches %}
<li>{{ match.description }}</li>
{% endfor %}
</table>
</ul>
<a id="all-matches-link" href="{% url 'all_matches' %}">See all matches</a>

</body>
10 changes: 10 additions & 0 deletions leaderboard/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ def test_score(self):
expected_score = f'{self.winning_score}-{self.losing_score}'
self.assertEqual(self.match.score, expected_score)

def test_date(self):
"""
Test match model has a date property.
Date is a truncated version of the datetime with only
the date part.
"""
expected_date = self.match.datetime.strftime('%m/%d/%Y')
self.assertEqual(self.match.date, expected_date)

def test_description(self):
"""
Test match model has a description property.
Expand Down
65 changes: 65 additions & 0 deletions leaderboard/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.test import TestCase
from django.utils.html import escape
from django.contrib.auth.models import User
from django.core.paginator import Paginator

from leaderboard.models import Player, Match
from leaderboard.forms import MatchForm, PlayerForm, DUPLICATE_ERROR
Expand Down Expand Up @@ -140,3 +141,67 @@ def test_invalid_player_returns_form(self):
form = response.context['player_form']
expected_form = PlayerForm(self.invalid_player_data)
self.assertEqual(form.as_p(), expected_form.as_p())


class AllMatchesTest(TestCase):

@classmethod
def setUpClass(cls):
"""Add matches to database for each test."""
super().setUpClass() # Needed to run only once for all tests
cls.player1 = Player.objects.create(first_name='Bob', last_name='Hope')
cls.player2 = Player.objects.create(first_name='Sue', last_name='Hope')
for _ in range(51):
Match.objects.create(
winner=cls.player1,
loser=cls.player2,
winning_score=21,
losing_score=10
)

def test_correct_template(self):
"""Test that the match HTML template is used."""
response = self.client.get('/matches/')
self.assertTemplateUsed(response, 'all_matches.html')

def test_paginator_with_all_matches(self):
"""Test view has paginator with all matches."""
response = self.client.get('/matches/')
matches = response.context['matches']
self.assertEqual(matches.paginator.count, 51)

def test_num_pages(self):
"""Test paginator has correct number of pages."""
response = self.client.get('/matches/')
matches = response.context['matches']
self.assertEqual(matches.paginator.num_pages, 2)

def test_returns_num_matches(self):
"""Test that 50 matches are returned."""
response = self.client.get('/matches/')
matches = response.context['matches']
self.assertEqual(len(matches), 50)

def test_default_first_page(self):
"""Test that the default page is page 1."""
response = self.client.get('/matches/')
matches = response.context['matches']
self.assertFalse(matches.has_previous())

def test_get_page(self):
"""Test page requested through GET."""
response = self.client.get('/matches/?page=2')
matches = response.context['matches']
self.assertEqual(matches.number, 2)

def test_empty_page(self):
"""Test empty page defaults to last page."""
response = self.client.get('/matches/?page=1000')
matches = response.context['matches']
self.assertFalse(matches.has_next())

def test_num_matches_last_page(self):
"""Test that 1 match returned in last page."""
response = self.client.get('/matches/?page=2')
matches = response.context['matches']
self.assertEqual(len(matches), 1)
21 changes: 21 additions & 0 deletions leaderboard/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.shortcuts import render, redirect
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator

from leaderboard.models import Match, PlayerRating
from leaderboard.forms import MatchForm, PlayerForm
Expand Down Expand Up @@ -34,3 +35,23 @@ def home_page(request):
'unranked_players': unranked_players
}
)


def all_matches(request):
"""Render page to view all matches."""
all_matches = Match.objects.all().order_by('-datetime')
paginator = Paginator(all_matches, per_page=50)
page = request.GET.get('page')
try:
matches = paginator.page(page)
except PageNotAnInteger: # occurs when no page is passed through
matches = paginator.page(1)
except EmptyPage: # occurs when page is out of range
matches = paginator.page(paginator.num_pages) # deliver last page of results
return render(
request,
'all_matches.html',
context={
'matches': matches
}
)
5 changes: 4 additions & 1 deletion pongboard/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""

from django.conf.urls import url, include
from django.contrib import admin
from leaderboard.views import home_page

from leaderboard.views import home_page, all_matches

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', view=home_page, name='home'),
url(r'accounts/', include('django.contrib.auth.urls')),
url(r'matches/', view=all_matches, name='all_matches'),
]

0 comments on commit 6de7847

Please sign in to comment.