diff --git a/db.sqlite3 b/db.sqlite3 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ebd1d000d647b958273035115175320285255a44 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/functional_tests.py b/functional_tests.py index 0c4492dbfcf3265559396a8461bb4cf1fe6daac2..6e991b31c69d12d8b3b4bebd0a4990a87fe97be7 100644 --- a/functional_tests.py +++ b/functional_tests.py @@ -1,4 +1,6 @@ from selenium import webdriver +from selenium.webdriver.common.keys import Keys +import time import unittest class NewVisitorTest(unittest.TestCase): @@ -9,18 +11,35 @@ class NewVisitorTest(unittest.TestCase): def tearDown(self): self.browser.quit() - def test_can_start_a_list_and_retrieve_it_later(self): - # Edith has heard about a cool new online to-do app. She goes - # to check out its homepage + 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]) + + # She is invited to enter a to-do item straight away + def test_can_start_a_list_and_retrieve_it_later(self): self.browser.get('http://localhost:8000/homepage') # She notices the page title and header mention to-do lists - body_text = self.browser.find_element_by_tag_name('body').text - self.assertIn('Tutorial PMPL', self.browser.title) - self.assertIn('Kevin Albert Simanjuntak', body_text) - self.assertIn('NPM', body_text) + self.assertIn('To-Do', self.browser.title) + 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 - + inputbox = self.browser.find_element_by_id('id_new_item') + self.assertEqual( + inputbox.get_attribute('placeholder'), + 'Enter a to-do item' + ) + inputbox.send_keys('Buy peacock feathers') + inputbox.send_keys(Keys.ENTER) + time.sleep(5) + 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(5) + 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') + if __name__ == '__main__': unittest.main(warnings='ignore') \ No newline at end of file diff --git a/lists/__pycache__/models.cpython-37.pyc b/lists/__pycache__/models.cpython-37.pyc index 20ce025413da3c795f0bcef4dcd82ebc4e3d542f..b2cc93ad44bd444635a96baf5acdc66d806070f3 100644 Binary files a/lists/__pycache__/models.cpython-37.pyc and b/lists/__pycache__/models.cpython-37.pyc differ diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc index 89fc02474df93be6380eb68b1e7d219424d2ef57..21ea18ac445b6272577227d401157545420486b5 100644 Binary files a/lists/__pycache__/tests.cpython-37.pyc and b/lists/__pycache__/tests.cpython-37.pyc differ diff --git a/lists/__pycache__/views.cpython-37.pyc b/lists/__pycache__/views.cpython-37.pyc index 3cf9c52c882f69073889ec4c49db7d5150d9e509..c8f22a400a74cd6f793fc83c9277d53805961a68 100644 Binary files a/lists/__pycache__/views.cpython-37.pyc and b/lists/__pycache__/views.cpython-37.pyc differ diff --git a/lists/migrations/0001_initial.py b/lists/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..86a31b92753ecad65fe8c90a79d8126717dc620f --- /dev/null +++ b/lists/migrations/0001_initial.py @@ -0,0 +1,20 @@ +# Generated by Django 2.0 on 2019-09-24 15:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Item', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), + ] diff --git a/lists/migrations/0002_item_text.py b/lists/migrations/0002_item_text.py new file mode 100644 index 0000000000000000000000000000000000000000..da99df0da549fe120da8f7ee730e31d28453390b --- /dev/null +++ b/lists/migrations/0002_item_text.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0 on 2019-09-24 15:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('lists', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='item', + name='text', + field=models.TextField(default=''), + ), + ] diff --git a/lists/models.py b/lists/models.py index 71a836239075aa6e6e4ecb700e9c42c95c022d91..7ba0fddfe438a342c9e3619446dd95ebad45c1d4 100644 --- a/lists/models.py +++ b/lists/models.py @@ -1,3 +1,4 @@ from django.db import models -# Create your models here. +class Item(models.Model): + text = models.TextField(default='') \ No newline at end of file diff --git a/lists/templates/home.html b/lists/templates/home.html new file mode 100644 index 0000000000000000000000000000000000000000..9dba10315bfd2a0663b302fa1e134a8d05401b36 --- /dev/null +++ b/lists/templates/home.html @@ -0,0 +1,17 @@ +<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> \ No newline at end of file diff --git a/lists/templates/homepage.html b/lists/templates/homepage.html deleted file mode 100644 index 6417b223312bcf5f6fc01f8ec9699cf0e1f87008..0000000000000000000000000000000000000000 --- a/lists/templates/homepage.html +++ /dev/null @@ -1,10 +0,0 @@ -<html> -<head> - <meta charset="UTF-8"> - <title>Tutorial PMPL</title> -</head> -<body> - <h1>Name: {{ name }}</h1> - <h2> NPM: {{npm}} </h2> -</body> -</html> \ No newline at end of file diff --git a/lists/tests.py b/lists/tests.py index 049a01f43cce358f3c8794a9d967ece0d5a70ec3..8a65cfcfe93eeab30d3f92c7ff530b5eeb992c86 100644 --- a/lists/tests.py +++ b/lists/tests.py @@ -3,21 +3,78 @@ from django.test import TestCase from django.http import HttpRequest from django.test import Client from lists.views import home_page +from django.template.loader import render_to_string +from lists.models import Item class HomePageTest(TestCase): + def test_home_page_returns_correct_html(self): + response = self.client.get('/homepage/') + html = response.content.decode('utf8') + self.assertTrue(html.startswith('<html>')) + self.assertIn('<title>To-Do lists</title>', html) + self.assertTrue(html.strip().endswith('</html>')) + self.assertTemplateUsed(response, 'home.html') + def test_home_page_is_exist(self): response = Client().get('/homepage/') self.assertEqual(response.status_code,200) - def test_root_url_resolves_to_home_page_view(self): - found = resolve('/homepage/') - self.assertEqual(found.func, home_page) + def test_uses_home_template(self): + response = self.client.get('/homepage/') + self.assertTemplateUsed(response, 'home.html') - def test_home_page_returns_correct_html(self): - request = HttpRequest() - response = home_page(request) - html = response.content.decode('utf8') - self.assertTrue(html.startswith('<html>')) - self.assertIn('<title>Tutorial PMPL</title>', html) - self.assertIn('Kevin Albert Simanjuntak', html) - self.assertTrue(html.endswith('</html>')) \ No newline at end of file + def test_can_save_a_POST_request(self): + response = self.client.post('/homepage/', data={'item_text': 'A new list item'}) + self.assertIn('A new list item', response.content.decode()) + self.assertTemplateUsed(response, 'home.html') + + def test_only_saves_items_when_necessary(self): + self.client.get('/homepage/') + self.assertEqual(Item.objects.count(), 0) + def test_can_save_a_POST_request(self): + response = self.client.post('/homepage/', data={'item_text': 'A new list item'}) + self.assertEqual(Item.objects.count(), 1) + new_item = Item.objects.first() + self.assertEqual(new_item.text, 'A new list item') + + self.assertEqual(response.status_code, 302) + self.assertEqual(response['location'], '/homepage/') + + def test_displays_all_list_items(self): + Item.objects.create(text='itemey 1') + Item.objects.create(text='itemey 2') + + response = self.client.get('/homepage/') + + 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() + first_item.text = 'The first (ever) list item' + first_item.save() + + 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') + + def test_can_save_a_POST_request(self): + self.client.post('/homepage/', data={'item_text': 'A new list item'}) + self.assertEqual(Item.objects.count(), 1) + new_item = Item.objects.first() + self.assertEqual(new_item.text, 'A new list item') + + def test_redirects_after_POST(self): + response = self.client.post('/homepage/', data={'item_text': 'A new list item'}) + self.assertEqual(response.status_code, 302) + self.assertEqual(response['location'], '/homepage/') \ No newline at end of file diff --git a/lists/views.py b/lists/views.py index 01c479fbedd9062c7eab889e442b19517ce6fccd..7454b7657f2fe2d08d0544d6580981a9eba28fdc 100644 --- a/lists/views.py +++ b/lists/views.py @@ -1,9 +1,10 @@ -from django.http import HttpResponse -from django.shortcuts import render +from django.shortcuts import redirect, render +from lists.models import Item -# Create your views here. -name = "Kevin Albert Simanjuntak" -npm = "1606835595" def home_page(request): - response = {"name" : name, "npm" : npm} - return render(request, 'homepage.html', response) \ No newline at end of file + if request.method == 'POST': + Item.objects.create(text=request.POST['item_text']) + return redirect('/homepage/') + + items = Item.objects.all() + return render(request, 'home.html', {'items': items}) \ No newline at end of file diff --git a/s b/s new file mode 100644 index 0000000000000000000000000000000000000000..31e33cf22fbfd990c726b76f2cad4b506991086f --- /dev/null +++ b/s @@ -0,0 +1,77 @@ +[1mdiff --git a/functional_tests.py b/functional_tests.py[m +[1mindex c9ac63e..a438209 100644[m +[1m--- a/functional_tests.py[m +[1m+++ b/functional_tests.py[m +[36m@@ -35,18 +35,21 @@[m [mclass NewVisitorTest(unittest.TestCase):[m + [m + # When she hits enter, the page updates, and now the page lists[m + # "1: Buy peacock feathers" as an item in a to-do list table[m +[31m- inputbox.send_keys(Keys.ENTER) [m +[31m- time.sleep(1) [m + [m +[32m+[m[32m inputbox.send_keys(Keys.ENTER)[m +[32m+[m[32m time.sleep(1)[m + table = self.browser.find_element_by_id('id_list_table')[m + rows = table.find_elements_by_tag_name('tr') [m +[31m- self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),"New to-do item did not appear in table")[m +[31m-[m +[31m- # There is still a text box inviting her to add another item. She[m +[31m- # enters "Use peacock feathers to make a fly" (Edith is very[m +[31m- # methodical)[m +[31m- self.fail('Finish the test!')[m +[31m-[m +[31m- # The page updates again, and now shows both items on her list [m +[32m+[m[32m #self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),f"New to-do item did not appear in table")[m +[32m+[m[32m self.assertIn('1: Buy peacock feathers', [row.text for row in rows])[m +[32m+[m[32m inputbox = self.browser.find_element_by_id('id_new_item')[m +[32m+[m[32m inputbox.send_keys('Use peacock feathers to make a fly')[m +[32m+[m[32m inputbox.send_keys(Keys.ENTER)[m +[32m+[m[32m time.sleep(1)[m +[32m+[m[32m table = self.browser.find_element_by_id('id_list_table')[m +[32m+[m[32m rows = table.find_elements_by_tag_name('tr')[m +[32m+[m[32m self.assertIn('1: Buy peacock feathers', [row.text for row in rows])[m +[32m+[m[32m self.assertIn('2: Use peacock feathers to make a fly',[row.text for row in rows])[m +[32m+[m[41m [m + if __name__ == '__main__': [m + unittest.main(warnings='ignore')[m +\ No newline at end of file[m +[1mdiff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc[m +[1mindex f371935..4b6e9b9 100644[m +Binary files a/lists/__pycache__/tests.cpython-37.pyc and b/lists/__pycache__/tests.cpython-37.pyc differ +[1mdiff --git a/lists/__pycache__/views.cpython-37.pyc b/lists/__pycache__/views.cpython-37.pyc[m +[1mindex 8a440d0..2bd5393 100644[m +Binary files a/lists/__pycache__/views.cpython-37.pyc and b/lists/__pycache__/views.cpython-37.pyc differ +[1mdiff --git a/lists/templates/home.html b/lists/templates/home.html[m +[1mindex 9a2a093..dd544fc 100644[m +[1m--- a/lists/templates/home.html[m +[1m+++ b/lists/templates/home.html[m +[36m@@ -4,8 +4,12 @@[m + </head>[m + <body>[m + <h1>Your To-Do list</h1>[m +[31m- <input id="id_new_item" placeholder="Enter a to-do item" />[m +[31m- <table id="id_list_table">[m +[31m- </table>[m +[31m- </body>[m +[32m+[m [32m<form method="POST">[m +[32m+[m[41m [m [32m<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />[m +[32m+[m[41m [m [32m{% csrf_token %}[m +[32m+[m [32m</form>[m +[32m+[m [32m<table id="id_list_table">[m +[32m+[m[41m [m [32m<tr><td>1: {{ new_item_text }}</td></tr>[m +[32m+[m[41m [m [32m</table>[m +[32m+[m [32m</body>[m + </html>[m +\ No newline at end of file[m +[1mdiff --git a/lists/tests.py b/lists/tests.py[m +[1mindex 4e973ff..44473b0 100644[m +[1m--- a/lists/tests.py[m +[1m+++ b/lists/tests.py[m +[36m@@ -20,4 +20,9 @@[m [mclass HomePageTest(TestCase):[m + [m + def test_uses_home_template(self):[m + response = self.client.get('/homepage/')[m +[32m+[m[32m self.assertTemplateUsed(response, 'home.html')[m +[32m+[m +[32m+[m[32m def test_can_save_a_POST_request(self):[m +[32m+[m[32m response = self.client.post('/homepage/', data={'item_t \ No newline at end of file