Compare commits

...

16 Commits

Author SHA1 Message Date
Jason Zhu 05b8f21943 Redirect after POST, and show all items in template 2020-11-09 12:33:20 +11:00
Jason Zhu ff01b880eb Rendering Items in the Template 2020-11-09 12:22:55 +11:00
Jason Zhu deceab97c3 5.7 Redirect After a POST 2020-11-09 11:57:23 +11:00
Jason Zhu 8bfd695ece 5.6 Saving the POST to the Database 2020-11-09 11:16:18 +11:00
Jason Zhu ac7a1a70e1 5.5.2 The Test Gets Surprisingly Far: Model for list Items and associated migration 2020-11-08 22:03:59 +11:00
Jason Zhu d5facdfa2c 5.5 The Django ORM and Our First Model, created ItemModelTest 2020-11-08 21:48:15 +11:00
Jason Zhu 87834f5a0b 5.4 Three Strikes and Refactor 2020-11-08 20:50:27 +11:00
Jason Zhu 9bacbfef4c 5.3.1+ fixed problem by replacing find_element_by_tag_name with find_elements_by_tag_name 2020-11-08 20:46:26 +11:00
Jason Zhu 892cdbf541 5.3.1 An Unexpected Failure 2020-11-08 20:39:30 +11:00
Jason Zhu c0661056cf 5.3 Passing Python Variables to Be Rendered in the Template 2020-11-08 16:50:20 +11:00
Jason Zhu 81b586ac07 5.2 Processing a POST Request on the Server 2020-11-08 16:24:07 +11:00
Jason Zhu 9c102d7add Finished 5.1 Wiring Up our form to send a POST request 2020-11-08 14:44:57 +11:00
Jason Zhu 1fb94c9d74 Finished to 4.5 Front page HTML now generated from a template 2020-11-07 21:25:24 +11:00
Jason Zhu 747e0c7009 Finished 4.4 On Refactoring 2020-11-07 21:05:22 +11:00
Jason Zhu 89224c9928 4.3.1 Refactoring to Use a Template 2020-11-07 20:48:41 +11:00
Jason Zhu 4f7cb1bb5a Finished 4.2 Using selenium to test user interactions 2020-11-07 19:21:21 +11:00
7 changed files with 109 additions and 20 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
.vscode .vscode
**/migrations/**

View File

@ -1,4 +1,6 @@
from selenium import webdriver from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import unittest import unittest
class NewVisitorTest(unittest.TestCase): class NewVisitorTest(unittest.TestCase):
@ -9,6 +11,11 @@ class NewVisitorTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
self.browser.quit() self.browser.quit()
def check_for_row_in_list_table(self, row_text):
table = self.browser.find_element_by_id('id_list_table')
rows = table.find_elements_by_tag_name('tr')
self.assertIn(row_text, [row.text for row in rows])
def test_can_start_a_list_and_retrieve_it_later(self): def test_can_start_a_list_and_retrieve_it_later(self):
# Edith has heard about a cool new online to-do app. She goes # Edith has heard about a cool new online to-do app. She goes
# to check out its homepage # to check out its homepage
@ -16,20 +23,36 @@ class NewVisitorTest(unittest.TestCase):
# She notices the page title and header mention to-do lists # She notices the page title and header mention to-do lists
self.assertIn('To-Do', self.browser.title) self.assertIn('To-Do', self.browser.title)
self.fail('Finish the test!') header_text = self.browser.find_element_by_tag_name('h1').text
self.assertIn('To-Do', header_text)
# She is invited to enter a to-do item straight away # She is invited to enter a to-do item straight away
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertEqual(
inputbox.get_attribute('placeholder'),
'Enter a to-do item'
)
# She types "Buy peacock feathers" into a text box (Edith's hobby # She types "Buy peacock feathers" into a text box (Edith's hobby
# is tying fly-fishing lures) # is tying fly-fishing lures)
inputbox.send_keys('Buy peacock feathers')
# When she hits enter, the page updates, and now the page lists # When she hits enter, the page updates, and now the page lists
# "1: Buy peacock feathers" as an item in a to-do list # "1: Buy peacock feathers" as an item in a to-do list
inputbox.send_keys(Keys.ENTER)
time.sleep(1)
self.check_for_row_in_list_table('1: Buy peacock feathers')
# There is still a text box inviting her to add another item. She # There is still a text box inviting her to add another item. She
# enters "Use peacock feathers to make a fly" (Edith is very methodical) # enters "Use peacock feathers to make a fly" (Edith is very methodical)
inputbox = self.browser.find_element_by_id('id_new_item')
inputbox.send_keys('Use peacock feathers to make a fly')
inputbox.send_keys(Keys.ENTER)
time.sleep(1)
# The page updates again, and now shows both items on her list # The page updates again, and now shows both items on her list
self.check_for_row_in_list_table('1: Buy peacock feathers')
self.check_for_row_in_list_table('2: Use peacock feathers to make a fly')
# Edith wonders whether the site will remember her list. Then she sees # Edith wonders whether the site will remember her list. Then she sees
# that the site has generated a unique URL for her -- there is some # that the site has generated a unique URL for her -- there is some

View File

@ -1,3 +1,4 @@
from django.db import models from django.db import models
# Create your models here. class Item(models.Model):
text = models.TextField(default='')

View File

@ -0,0 +1,18 @@
<html>
<head>
<title>To-Do lists</title>
</head>
<body>
<h1>Your To-Do list</h1>
<form method="POST">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
{% csrf_token %}
</form>
<table id="id_list_table">
{% for item in items %}
<tr><td>{{ forloop.counter }}: {{ item.text }}</td></tr>
{% endfor %}
</table>
</body>
</html>

View File

@ -1,8 +1,11 @@
from typing import Text
from django.http import response
from django.test import TestCase from django.test import TestCase
from django.urls import resolve from django.urls import resolve
from django.http import HttpRequest from django.http import HttpRequest
from lists.views import home_page from lists.views import home_page
from lists.models import Item
class HomePageTest(TestCase): class HomePageTest(TestCase):
@ -10,18 +13,52 @@ class HomePageTest(TestCase):
found = resolve('/') found = resolve('/')
self.assertEqual(found.func, home_page) self.assertEqual(found.func, home_page)
def test_home_page_returns_correct_html(self): def test_uses_home_template(self):
""" response = self.client.get('/')
1. Create an HttpRequest object, which is what Django will see when a user's browser asks for a page self.assertTemplateUsed(response, 'home.html')
2. Pass it to `home_page` view, which gives us a response.
3. Extract `.content` of the response, which are byte value, and should be decoded into string (HTML format)
4. Check HTML starts and end with <html> tag
5. Want to find <title> tag in the middle
"""
request = HttpRequest() #1 def test_can_save_a_POST_request(self):
response = home_page(request) #2 self.client.post('/', data={'item_text': 'A new list item'})
html = response.content.decode('utf8') #3
self.assertTrue(html.startswith('<html>')) #4 self.assertEqual(Item.objects.count(), 1)
self.assertIn('<title>To-Do list</title>', html) #5 new_item = Item.objects.first()
self.assertTrue(html.endswith('</html>')) #4 self.assertEqual(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/', data={'item_text': 'A new list item'})
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], '/')
def test_only_saves_items_when_necessary(self):
self.client.get('/')
self.assertEqual(Item.objects.count(), 0)
def test_displays_all_list_items(self):
Item.objects.create(text="itemey 1")
Item.objects.create(text="itemey 2")
response = self.client.get('/')
self.assertIn('itemey 1', response.content.decode())
self.assertIn('itemey 2', response.content.decode())
class ItemModelTest(TestCase):
def test_saving_and_retrieving_items(self):
first_item = Item() # Create an object
first_item.text = 'The first (ever) list item' # Assign attributes
first_item.save() # Calling .save() function
second_item = Item()
second_item.text = 'Item the second'
second_item.save()
saved_items = Item.objects.all()
self.assertEqual(saved_items.count(), 2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEqual(first_saved_item.text, 'The first (ever) list item')
self.assertEqual(second_saved_item.text, 'Item the second')

View File

@ -1,8 +1,16 @@
from django.http.request import HttpRequest from django.http.request import HttpRequest
from django.http.response import HttpResponse from django.http.response import HttpResponse
from django.shortcuts import render from django.shortcuts import redirect, render
from lists.models import Item
# Create your views here # Create your views here
def home_page(request): def home_page(request):
# return HttpResponse('<html><title>To-Do lists</title></html>') if request.method == 'POST':
return HttpResponse('<html><title>To-Do list</title></html>') Item.objects.create(text=request.POST['item_text'])
return redirect('/')
items = Item.objects.all() # get objects from database (model)
return render(request=request,
template_name='home.html',
context={'items': items}) # pass items into template using render

View File

@ -37,6 +37,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'lists'
] ]
MIDDLEWARE = [ MIDDLEWARE = [