From 4b9b3dc6b3da077ea22fe712ace5c6cce7864dc7 Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Mon, 23 Sep 2019 19:58:51 +0700
Subject: [PATCH 1/7] initial commit

---
 functional_tests.py | 49 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/functional_tests.py b/functional_tests.py
index 0c4492d..932937a 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -1,26 +1,51 @@
 from selenium import webdriver
+from selenium.webdriver.common.keys import Keys
+import time
 import unittest
 
-class NewVisitorTest(unittest.TestCase):  
+class NewVisitorTest(unittest.TestCase):
 
-    def setUp(self):  
+    def setUp(self):
         self.browser = webdriver.Firefox()
 
-    def tearDown(self):  
+    def tearDown(self):
         self.browser.quit()
 
-    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
         # to check out its homepage
-        self.browser.get('http://localhost:8000/homepage')
+        self.browser.get('http://localhost:8000')
 
         # 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
-        
-if __name__ == '__main__':  
-    unittest.main(warnings='ignore')
\ No newline at end of file
+        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
+        # is tying fly-fishing lures)
+        inputbox.send_keys('Buy peacock feathers')  
+
+        # When she hits enter, the page updates, and now the page lists
+        # "1: Buy peacock feathers" as an item in a to-do list table
+        inputbox.send_keys(Keys.ENTER)  
+        time.sleep(1)  
+
+        table = self.browser.find_element_by_id('id_list_table')
+        rows = table.find_elements_by_tag_name('tr')  
+        self.assertTrue(
+            any(row.text == '1: Buy peacock feathers' for row in rows)
+        )
+
+        # 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)
+        self.fail('Finish the test!')
+
+        # The page updates again, and now shows both items on her list
\ No newline at end of file
-- 
GitLab


From 851c8cd978cace88e1e728f3c2bf8c0e55f68edd Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Mon, 23 Sep 2019 21:10:18 +0700
Subject: [PATCH 2/7] refactor home page view to use a template

---
 lists/__pycache__/tests.cpython-37.pyc | Bin 1411 -> 1461 bytes
 lists/__pycache__/views.cpython-37.pyc | Bin 463 -> 304 bytes
 lists/templates/home.html              |   3 +++
 lists/templates/homepage.html          |  10 ----------
 lists/tests.py                         |  24 ++++++++++++------------
 lists/views.py                         |   7 +------
 6 files changed, 16 insertions(+), 28 deletions(-)
 create mode 100644 lists/templates/home.html
 delete mode 100644 lists/templates/homepage.html

diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc
index 89fc02474df93be6380eb68b1e7d219424d2ef57..f3719353bc5df3911c6e016432f677b0b2a1a4e4 100644
GIT binary patch
delta 857
zcmZqX-pbAE#LLUYz`(%3dZ{CJ=0sje#+Zrf_DU%XDQr2Mxm;0Pj12A!DeNg6Eet6f
zsm#sHQQRq<!3>&Q6KkAAG#PIR6s6{+q!z`O<i{766lLb6Puv$?&kQn;fq}u9fq|ho
zf`Ngdh9Qe#0b>f|LdIIg8pbT91<WZ-3mI#fY8V!<)G#ezO<`WhxR8;Np@v}rTMA1J
z(?TXN8zjfRkYNEw3M*WmvxYH+4J4n!5X_*-?pMX7pOK%NT9BBYs(*{6v?R@<%8kt?
zqa-)Su1d<LB(o$Z)h;Ao*Ck&eC$qSu*hU{BRK;$i4^hMk(yj+$YjWLUOU}tm%`3UZ
zoSs@T`6#nVJuApp1-Cd-^HPe-GfOgV2_+U6rxuljq~;dnB$lLx7N@3YGT&k;PR&WX
z#Zi=6T#%nvoO+7|WZp`KB5?)=hF`j_Rxu%^>50WL0lon~F$K8=ISQ#2$*D!jnZ>CJ
zMloQA#gwELmlW$2RNhhsvEo6liZ7UK$s!@n2?|CYP$V((F!C@8F!C^pFjg5%e#a;?
z*_K6QG7n>LND(&!1H&zDh~r!fOA~W$aTk{)mXsF9C+DZ6YBCjxFfcF_iGm1_qrfgJ
zk^pHEN3t(5JvBbFI6k!^v$#ZX@&iVXdKvWSV_3jc!<Yh&B5)KiqeMX!QgAXCfl?OO
zWktda3=D)FQCgf@4DophG<+FFCqH0R5W<w0Jc~ucP7>rDSr8!yA`l(}vp~Kp;$UE4
z0O4Xb5QC9}gM$Su=BLRsiPbmsmRL$wVqSW_9?U|$oczR;)S@DGkbxkLkdOi!2qr+L
X-r}&y%}*)KNws5y#SJKCpqL2&7bxV-

delta 820
zcmdnW-OSDF#LLUYz`(%3@uxAib|SANW57gpdog#06t)!h7KRk|ROV*pD9#j)U<OUj
zi5*T8?}bkmW%kOv#hjj6a*I2$xHz?_#I>+AG3OR{aY<rHX>ojVeoCq)(=C?b)SR?i
z97U<c1^Ic!sVf<Z_!t-%e(Abe#e|fmCl<#9_y+jIl%y7yWag!(=O>mVXBg@l$K+%d
zmlT7Ai}eaBZ;4Mn$1KjsF}a#WVe&gBuE}?q<?5vv7#K<zQW%>VYZ+@87BJQ@W-*m8
zFJxk5NMQ(O&}8zf;?mE^&rK~zOi$I<WGP}|U|=W$dGZ!ZT4`Q#5gP*ogC<iE4+8_k
zE!MRB(!3O~(;x&tNK^yltoWk*{F3<6qMZ1m)Z+Y{vee@ElKl9L{QBI~c#zTYWtpkv
zAVZ2-Kmo|e!B}PLk)N9ykeHqtl3HA%htCjXGm;rW`WYA)K<2PAFfceXFfbH{fqmJ`
zP|H}tSOfAaQw>uV(*ov{dd7u}wahgP3s`EH7qF%<Eo5BC$jDH`uz)Rvxdt2zU^WY!
z4N}LR!U|Cb4k9+cTP&p|X%<y%HW?+kId)YtHYJ%QIjMFbr6u`AnTa_HpvbY&hX__l
zc&C<S<|#PlB&8OWC@2JH<|gK4mFATsW>>M>=z~qr<R}8U9vrrle=(XEbEM{_6qjd~
zWN5NLLYloOwXig`xTJ^|6v8YZU62q5C5s|ZuuopVq$()@@;gX~fsu`ogOP_(fRTrh
zhq20F@<C>q$v>DxCa-1Dumh<o5(dSqEQkQ9M>DL5oq>S?go{DZ&B4gQ!odO-^V8&-
mEX?X_2Ie4X0-FJH#w`w;-29Z%oK!ndycB~H4#)*y%me^HM$)qY

diff --git a/lists/__pycache__/views.cpython-37.pyc b/lists/__pycache__/views.cpython-37.pyc
index 3cf9c52c882f69073889ec4c49db7d5150d9e509..8a440d0183ac08a94c7d014c9e3b9bebc1d82784 100644
GIT binary patch
literal 304
zcmZ?b<>g{vU|>)`))AY|z`*br#DQTZ1_lNP1_p*=2?hp+6owSW9EM!RC`Lwx6s8pB
z7KSLM6qaBHP1ctn^_q;g*oso~Qc{bO89{so1_lt#%)r3l3^D>_O9?{_LkeRvQ!s-j
zlV25QMt*LpUPei7jwWLf$SO_7TkJ)tg{7&*B`X<<SQr=>e(Abe#e|fmCl<#9_y+jI
z6yz4<D5O>-rxqn=7N;s0#pGlbmlVg8Wu}%F>lIYq0vj1$keHqdvbPvyC<9{=8v_G_
zpC)sZKuT6(UV6S>aYlYoNpfjPG1ykHG}tyIf|Y@R;TDHYZhlH>PO2TqBVfaLm;kU6
BK_>tJ

literal 463
zcmZ?b<>g{vU|`tsvN2YQk%8echy%k+3=9ko3=9m#It&a9DGVu$ISjdsQH+crHd78$
zE^`z!BSQ*v6iW(A6l)4=3R??96k7^=FoPz?OOP3wjJJ3^N=gcXQi}`n^NLe78E>%_
zrRJri7F9`jr<P^rDLCdNr52Sa1ZU<Z=4F-Ul_X|IaT%H!m{}N`np&DBGlEQEU|;|_
zgoS~D!5QQjF$M;P5{44S6vjDBwTvZ9H4G_CHH^*7!3>(rews|TSn?8cQ*SZn735a&
zX5{Cl79^&p>SdJV=4dh(fea~PWnf?^VrF1q&}6#BUX)r`np#|Pi=znY$dwF591IK$
zzjR%#VnRyO6N_U4d;@%9N>YnUGV{{Y^Ak&wGYoZ&V{$T!ONwL4GE>Wo^$IF)ae}Oh
z2ie6AawNzi21YK%B2ei1X|mtqPRUBlOV8KKC@Co@0{JIO04h?PkzZ7jTv}2Lb`z2l
mL0Z9XK_WOA7#MDG*yQG?l;)(`fx@R4<XRp^9%dFs7DfQNfo&uJ

diff --git a/lists/templates/home.html b/lists/templates/home.html
new file mode 100644
index 0000000..94d4105
--- /dev/null
+++ b/lists/templates/home.html
@@ -0,0 +1,3 @@
+<html>
+    <title>To-Do lists</title>
+</html>
\ No newline at end of file
diff --git a/lists/templates/homepage.html b/lists/templates/homepage.html
deleted file mode 100644
index 6417b22..0000000
--- 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 049a01f..4e973ff 100644
--- a/lists/tests.py
+++ b/lists/tests.py
@@ -3,21 +3,21 @@ 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
 
 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_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_uses_home_template(self):
+        response = self.client.get('/homepage/')
+        self.assertTemplateUsed(response, 'home.html')
\ No newline at end of file
diff --git a/lists/views.py b/lists/views.py
index 01c479f..e90445a 100644
--- a/lists/views.py
+++ b/lists/views.py
@@ -1,9 +1,4 @@
-from django.http import HttpResponse
 from django.shortcuts import render
 
-# 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
+    return render(request, 'home.html')
\ No newline at end of file
-- 
GitLab


From 429fb6fb29cab575a5c11d359dd3b84e7efdf7a2 Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Tue, 24 Sep 2019 18:58:12 +0700
Subject: [PATCH 3/7] Front page HTML now generated from a template

---
 functional_tests.py       | 21 +++++++++++----------
 lists/templates/home.html | 10 +++++++++-
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/functional_tests.py b/functional_tests.py
index 932937a..c9ac63e 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -3,18 +3,19 @@ from selenium.webdriver.common.keys import Keys
 import time
 import unittest
 
-class NewVisitorTest(unittest.TestCase):
+class NewVisitorTest(unittest.TestCase):  
 
-    def setUp(self):
+    def setUp(self):  
         self.browser = webdriver.Firefox()
 
-    def tearDown(self):
+    def tearDown(self):  
         self.browser.quit()
 
+    # She is invited to enter a to-do item straight away
     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
-        self.browser.get('http://localhost:8000')
+    # Edith has heard about a cool new online to-do app. She goes
+    # to check out its homepage
+        self.browser.get('http://localhost:8000/homepage')
 
         # She notices the page title and header mention to-do lists
         self.assertIn('To-Do', self.browser.title)
@@ -39,13 +40,13 @@ class NewVisitorTest(unittest.TestCase):
 
         table = self.browser.find_element_by_id('id_list_table')
         rows = table.find_elements_by_tag_name('tr')  
-        self.assertTrue(
-            any(row.text == '1: Buy peacock feathers' for row in rows)
-        )
+        self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),"New to-do item did not appear in table")
 
         # 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)
         self.fail('Finish the test!')
 
-        # The page updates again, and now shows both items on her list
\ No newline at end of file
+        # The page updates again, and now shows both items on her list        
+if __name__ == '__main__':  
+    unittest.main(warnings='ignore')
\ No newline at end of file
diff --git a/lists/templates/home.html b/lists/templates/home.html
index 94d4105..9a2a093 100644
--- a/lists/templates/home.html
+++ b/lists/templates/home.html
@@ -1,3 +1,11 @@
 <html>
-    <title>To-Do lists</title>
+    <head>
+        <title>To-Do lists</title>
+    </head>
+    <body>
+        ​<h1>Your To-Do list</h1>
+       ​<input id="id_new_item" placeholder="Enter a to-do item" />
+       ​<table id="id_list_table">
+   ​</table>
+   ​</body>
 </html>
\ No newline at end of file
-- 
GitLab


From e98e66bd7f85aa8ac42f210e2b146a881986d146 Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Tue, 24 Sep 2019 20:48:37 +0700
Subject: [PATCH 4/7] refactor

---
 functional_tests.py                    |  23 ++++----
 lists/__pycache__/tests.cpython-37.pyc | Bin 1461 -> 1766 bytes
 lists/__pycache__/views.cpython-37.pyc | Bin 304 -> 409 bytes
 lists/templates/home.html              |  12 ++--
 lists/tests.py                         |   5 ++
 lists/views.py                         |   5 +-
 s                                      |  77 +++++++++++++++++++++++++
 7 files changed, 107 insertions(+), 15 deletions(-)
 create mode 100644 s

diff --git a/functional_tests.py b/functional_tests.py
index c9ac63e..a438209 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -35,18 +35,21 @@ class NewVisitorTest(unittest.TestCase):
 
         # When she hits enter, the page updates, and now the page lists
         # "1: Buy peacock feathers" as an item in a to-do list table
-        inputbox.send_keys(Keys.ENTER)  
-        time.sleep(1)  
 
+        inputbox.send_keys(Keys.ENTER)
+        time.sleep(1)
         table = self.browser.find_element_by_id('id_list_table')
         rows = table.find_elements_by_tag_name('tr')  
-        self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),"New to-do item did not appear in table")
-
-        # 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)
-        self.fail('Finish the test!')
-
-        # The page updates again, and now shows both items on her list        
+        #self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),f"New to-do item did not appear in table")
+        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
+        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)
+        table = self.browser.find_element_by_id('id_list_table')
+        rows = table.find_elements_by_tag_name('tr')
+        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
+        self.assertIn('2: Use peacock feathers to make a fly',[row.text for row in rows])
+             
 if __name__ == '__main__':  
     unittest.main(warnings='ignore')
\ No newline at end of file
diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc
index f3719353bc5df3911c6e016432f677b0b2a1a4e4..4b6e9b94deeece6744684ad98fb68530a61ee8f0 100644
GIT binary patch
delta 334
zcmdnW{fw8-iI<m)fq{X6kFzUwKFdVDXN)=%zpC=2aI`Q)v88YZGiY*cmSgN^u1{tJ
zDPv$@U}9ikU}a!naAsg&C^lnYV5nipV#s1lVN794Va{YsVd-V6WvpRXz?8yV!<faq
zfMp@WLMBFr8ioa|HH;~&Aa)8vFoPzWUlo^rMt*K;L1KEUeiUbBNosC<Noqw&6~CiG
zUTV2QPG)h50!UPo@fM3lN@7W36(>l&UPei7jwV|X$lbSC3i69fiUb%K7>am61n*=!
z7L_QOlGNgo_~gXA_~OK})cC~s0RP~S_@dOp($wM-Nsz<YK)zuVVH9Gl()7sBO$|s)
qPYp>eF44oM(@&Fq@&*<YM#aewSQNQ97#J8h7&$mNSSE9_t^oj;>sDL<

delta 72
zcmaFHyOo>IiI<m)fq{X6^-@RdOy-Gv&lpuEepO`&X3*r=tj5^S%<QMhHu)B-$>c3;
Y!a_wH3=9k)T+9YyFmiBAwqjcY0E|x$^Z)<=

diff --git a/lists/__pycache__/views.cpython-37.pyc b/lists/__pycache__/views.cpython-37.pyc
index 8a440d0183ac08a94c7d014c9e3b9bebc1d82784..2bd53936920f4ce023b9f769a5b9be94588a1645 100644
GIT binary patch
delta 337
zcmdnMG?SUviI<m)fq{YH7)Mv^m5IEP^(qVu3@HpLj5!Rsj8Tk?AU0DDQ!aB9Gb2L^
za|%lfLljF2YcPW*+e?r>O~zY19wj9OL8-+B`FX{unvA#Dic<4ZQj3xqLGla?3?Q0=
zfq}u9fq|h|ih+TlgrSBZg)xPxh9Qe_0Tam3g-n@@&CJ0Jnyj9FRh$|5xv6>?CAm3K
zym_hR@tGy5x$z~b6(zSg5ljY6<|1YW28LTK0sg@ux0usYOEej8u@|KlmZlb$tYj$S
zoH*Myj|F5Uh+tr3V=UrkU|{gmWWB|ml9ia3p0AftQc_UF#K6E1B>)vE&d4t+NiHoZ
l2Ad7mP{hf=z<@-6LhBZXO>TZlX-=vg$Zy3U3wRiLm;ij;PpSX_

delta 241
zcmbQqyn%_=iI<m)fq{WR{a8nA`b1vIdI<&wh7^Vr#vF!R#wbQch7_h0<`#x1rWBT7
z22IwNAhnu|x7dnO^HNfak{LmK1_lNY&CI~S;LO0lPz*A#grSBZg|V3_m_d`tuZlAx
zKQ~n`qa-&+ld*`2fq_Aj@fLegYGG+=amh-CA{GV)hF`j_Rxu%^6Mq;-fD9@IsbXL(
zVq;)n@Y7_D5=hBP%uCPLE6&I-DoHLaDFzz@mIiA_B3Kz17;bUc<mRW8=A_zzTn09b
GhY0}KsW5H;

diff --git a/lists/templates/home.html b/lists/templates/home.html
index 9a2a093..dd544fc 100644
--- a/lists/templates/home.html
+++ b/lists/templates/home.html
@@ -4,8 +4,12 @@
     </head>
     <body>
         ​<h1>Your To-Do list</h1>
-       ​<input id="id_new_item" placeholder="Enter a to-do item" />
-       ​<table id="id_list_table">
-   ​</table>
-   ​</body>
+		<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">
+        	<tr><td>1: {{ new_item_text }}</td></tr>
+    	</table>
+	</body>
 </html>
\ No newline at end of file
diff --git a/lists/tests.py b/lists/tests.py
index 4e973ff..44473b0 100644
--- a/lists/tests.py
+++ b/lists/tests.py
@@ -20,4 +20,9 @@ class HomePageTest(TestCase):
 
     def test_uses_home_template(self):
         response = self.client.get('/homepage/')
+        self.assertTemplateUsed(response, 'home.html')
+
+    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')
\ No newline at end of file
diff --git a/lists/views.py b/lists/views.py
index e90445a..7ef5b31 100644
--- a/lists/views.py
+++ b/lists/views.py
@@ -1,4 +1,7 @@
+from django.http import HttpResponse
 from django.shortcuts import render
 
 def home_page(request):
-    return render(request, 'home.html')
\ No newline at end of file
+    return render(request, 'home.html', {
+        'new_item_text': request.POST.get('item_text', ''),
+    })
\ No newline at end of file
diff --git a/s b/s
new file mode 100644
index 0000000..31e33cf
--- /dev/null
+++ b/s
@@ -0,0 +1,77 @@
+diff --git a/functional_tests.py b/functional_tests.py
+index c9ac63e..a438209 100644
+--- a/functional_tests.py
++++ b/functional_tests.py
+@@ -35,18 +35,21 @@ class NewVisitorTest(unittest.TestCase):
+ 
+         # When she hits enter, the page updates, and now the page lists
+         # "1: Buy peacock feathers" as an item in a to-do list table
+-        inputbox.send_keys(Keys.ENTER)  
+-        time.sleep(1)  
+ 
++        inputbox.send_keys(Keys.ENTER)
++        time.sleep(1)
+         table = self.browser.find_element_by_id('id_list_table')
+         rows = table.find_elements_by_tag_name('tr')  
+-        self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),"New to-do item did not appear in table")
+-
+-        # 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)
+-        self.fail('Finish the test!')
+-
+-        # The page updates again, and now shows both items on her list        
++        #self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),f"New to-do item did not appear in table")
++        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
++        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)
++        table = self.browser.find_element_by_id('id_list_table')
++        rows = table.find_elements_by_tag_name('tr')
++        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
++        self.assertIn('2: Use peacock feathers to make a fly',[row.text for row in rows])
++             
+ if __name__ == '__main__':  
+     unittest.main(warnings='ignore')
+\ No newline at end of file
+diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc
+index f371935..4b6e9b9 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 8a440d0..2bd5393 100644
+Binary files a/lists/__pycache__/views.cpython-37.pyc and b/lists/__pycache__/views.cpython-37.pyc differ
+diff --git a/lists/templates/home.html b/lists/templates/home.html
+index 9a2a093..dd544fc 100644
+--- a/lists/templates/home.html
++++ b/lists/templates/home.html
+@@ -4,8 +4,12 @@
+     </head>
+     <body>
+         ​<h1>Your To-Do list</h1>
+-       ​<input id="id_new_item" placeholder="Enter a to-do item" />
+-       ​<table id="id_list_table">
+-   ​</table>
+-   ​</body>
++		<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">
++        	<tr><td>1: {{ new_item_text }}</td></tr>
++    	</table>
++	</body>
+ </html>
+\ No newline at end of file
+diff --git a/lists/tests.py b/lists/tests.py
+index 4e973ff..44473b0 100644
+--- a/lists/tests.py
++++ b/lists/tests.py
+@@ -20,4 +20,9 @@ class HomePageTest(TestCase):
+ 
+     def test_uses_home_template(self):
+         response = self.client.get('/homepage/')
++        self.assertTemplateUsed(response, 'home.html')
++
++    def test_can_save_a_POST_request(self):
++        response = self.client.post('/homepage/', data={'item_t
\ No newline at end of file
-- 
GitLab


From 43acb640101bdb85aa0b3779d8cb921541d22e10 Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Tue, 24 Sep 2019 22:14:59 +0700
Subject: [PATCH 5/7] failed test for multiple table

---
 functional_tests.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/functional_tests.py b/functional_tests.py
index a438209..547ee62 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -11,6 +11,11 @@ class NewVisitorTest(unittest.TestCase):
     def tearDown(self):  
         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])
+
     # She is invited to enter a to-do item straight away
     def test_can_start_a_list_and_retrieve_it_later(self):
     # Edith has heard about a cool new online to-do app. She goes
@@ -46,10 +51,8 @@ class NewVisitorTest(unittest.TestCase):
         inputbox.send_keys('Use peacock feathers to make a fly')
         inputbox.send_keys(Keys.ENTER)
         time.sleep(1)
-        table = self.browser.find_element_by_id('id_list_table')
-        rows = table.find_elements_by_tag_name('tr')
-        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
-        self.assertIn('2: Use peacock feathers to make a fly',[row.text for row in rows])
-             
+        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
-- 
GitLab


From 29736e9f05e7eb2fde807f36e1e971764235a2bb Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Tue, 24 Sep 2019 22:47:22 +0700
Subject: [PATCH 6/7] Model for list Items and associated migration

---
 db.sqlite3                              | Bin 0 -> 139264 bytes
 lists/__pycache__/models.cpython-37.pyc | Bin 173 -> 378 bytes
 lists/__pycache__/tests.cpython-37.pyc  | Bin 1766 -> 2417 bytes
 lists/migrations/0001_initial.py        |  20 ++++++++++++++++++++
 lists/migrations/0002_item_text.py      |  18 ++++++++++++++++++
 lists/models.py                         |   3 ++-
 lists/tests.py                          |  22 +++++++++++++++++++++-
 7 files changed, 61 insertions(+), 2 deletions(-)
 create mode 100644 lists/migrations/0001_initial.py
 create mode 100644 lists/migrations/0002_item_text.py

diff --git a/db.sqlite3 b/db.sqlite3
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..749774212f1e7fc02410e482a508672c03819652 100644
GIT binary patch
literal 139264
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
Hm=FK}O#wpx

literal 0
HcmV?d00001

diff --git a/lists/__pycache__/models.cpython-37.pyc b/lists/__pycache__/models.cpython-37.pyc
index 20ce025413da3c795f0bcef4dcd82ebc4e3d542f..b2cc93ad44bd444635a96baf5acdc66d806070f3 100644
GIT binary patch
literal 378
zcmZ?b<>g{vU|<Na>WWQbU|@I*;=nKq0|SEt0|P^`5(5K63PTEG4nr<u6eA;pJ3|Un
z3UdoX3UexB7E?2G6mtqoFoP!ROOQ@Y##?N;`6;P6#mOKp3^T(FlVD(ANM(p(Oks#(
zN@dPsNnuQ3>Sc^#O<@jZ&}6yA;#rcKdy7Gn@fLeZYFc7xPKlo;+bxdx_`Jm2)cE*Y
zT=DU_`6;D2AU02Yd|_!~4n(GiiGhLP7H3FmMTuKxYEH^6mXg$pl9dca+zbp5;+LMQ
zRZK`}dSY=*fNy|LOhIlzjzVfha%xd>W^t;5QA|!|aY=Cu#PNCsl|>*ogK#m(Xbwg&
v-%pd}7H3LUVqSW_UP=<gQdVD(f5FlS+aN3+kfS(kAWpVp1cfHZFdilV-nLgr

literal 173
zcmZ?b<>g{vU|<km)fj8Tz`*br#DQTZ1_lNP1_p*=0R{$!6owSW9EM!RC`Lwx6sBMX
zP3D&%b()N~*mCnzQge#^G?{L3rer1NrRVFVBo%=)uVg4<VPJp|zw}(KVnRyO6N_U4
zd;@%9N>YnUGV{{Y^Ak&wGYoZ&V{$T!ONwJ4X6Y4F-r}&y%}*)KNws4HIRRuB09AD;
A<^TWy

diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc
index 4b6e9b94deeece6744684ad98fb68530a61ee8f0..d154cb8796e7c13aed813ec9595e33ce0bb792bd 100644
GIT binary patch
delta 999
zcmaFH`%#F`iI<m)fq{X+$+#=lf_);N1Y^ZSb#J2-h7|T3?p&TI9!3Uth7^tz&K8Cg
z&Q#`R<|tlwh7_(8?iPj=ZZMxOg(sLnlXqfA7>6d~Ef&v`)ZC5trZX~1OfF*zXXKiE
zj%gMn&*V&I1yNB328JRr5Fr64Bqz^fmSGf{yqmdIn;Rs`10qBi7#K8}im+;6U|_f<
zK6xICIHTC)-OLJ;7qcuj1L?fQQjlL<QX~k{&kG{>Km<OMCfBekGD=OJ$C~IQ1yU;q
zBIH4Y5{N)J63mhWiE%P8Fo19|2Ll5G2O|du2MY&F5lCd>J+XR_WvL8Nj42FJOeu^h
zOf3vi%qh&l44N#rctPRfo1c=J6Ovk7lFSGSa|Q+mHU<U;76t|eX9fm_;vxnHh7yKm
zhFZoH#u~<W#u~;2ObZzpA!1A^Of^jLj5SO!u`K2VEDITGnQIspu+}gyU|YygpTfM5
ziIJg(IfX@%p_ZkFIfYe{p_Ub_fF+ADg%K<ZQqG#in8F0&r7#3DXtMcLNrhyjDx_r=
z6_+Szq?V-?X)5Go7MCbwmZauZ@q?VMP?C|VP@I~apO^BI2^10_AG`z+n(RfOz_`Uy
zQlDB;a*L%nu`Kl#dwx<@YH~^OE#}0WoFW-eoUtb7m*$mdvVmhYiVJL6JjjA5Ziu-s
zPGVVV3Yc9SB>+(cG7=&bB?wiE5Gn%44v45P0>#lSg_6|blKA4pvdp~n_{6-F_@dO3
zqRdn<7i3?tA}Fvy8W<Sa7}*#(m>?t<qW}{JBL^cNW0fAr%kbFJBV?eTCQFer1A`4i
zkqRhiR6&FuhyYoFa39!tMQRKT44_0-3<^dLCNSSmlYg=cTUJOE4=C7+^>RT8r5GHp
m;KT)1gk%udT(D<3Y;yBcN^?@}Kv7XFz`(%3!-xc#1jGPCz24yf

delta 380
zcmew;^o*C!iI<m)fq{X6kFzUwKFdTt3C5U->fU1R3@Pj>94!nf9I4FB%u(DaoWTs5
zToadsZDwMe&d4Y}c@|SRBj@B#OtTodC-*Wd7>O`2FcgV`2yr+e!N9<9OS~ktxFkL!
zKQ}eLATd2PKC?JJwIZ{)L~!zb=2kV3-9_9W9l{I@44O<uSk0N-#UjHfI{7}c!sO#D
zi_JiqZm|^P7nc+XfVA>}2wo6@*N_FQij0zz53we?N`lnNf(SVfp$H-n&IYqUZZG0s
zU|;~@Vi3W>$iczE!odO-_0!~;yqP1*0?a7_>p&17y|*}Qa`RJ4b5iXX85kIfK~Cgh
HghM6(lqp2#

diff --git a/lists/migrations/0001_initial.py b/lists/migrations/0001_initial.py
new file mode 100644
index 0000000..86a31b9
--- /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 0000000..da99df0
--- /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 71a8362..7ba0fdd 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/tests.py b/lists/tests.py
index 44473b0..4a9024e 100644
--- a/lists/tests.py
+++ b/lists/tests.py
@@ -4,6 +4,7 @@ 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):
@@ -25,4 +26,23 @@ class HomePageTest(TestCase):
     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')
\ No newline at end of file
+        self.assertTemplateUsed(response, 'home.html')
+
+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')
\ No newline at end of file
-- 
GitLab


From 324d280ad1a3de65a15e577dbcae9e014fa8ef96 Mon Sep 17 00:00:00 2001
From: Kevin Albert Simanjuntak <kevinjuntak51@gmail.com>
Date: Wed, 25 Sep 2019 03:45:23 +0700
Subject: [PATCH 7/7] Redirect after POST, and show all items in template

---
 db.sqlite3                             | Bin 139264 -> 135168 bytes
 functional_tests.py                    |  19 +++-----------
 lists/__pycache__/tests.cpython-37.pyc | Bin 2417 -> 3875 bytes
 lists/__pycache__/views.cpython-37.pyc | Bin 409 -> 520 bytes
 lists/templates/home.html              |   6 +++--
 lists/tests.py                         |  34 ++++++++++++++++++++++++-
 lists/views.py                         |  13 ++++++----
 7 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/db.sqlite3 b/db.sqlite3
index 749774212f1e7fc02410e482a508672c03819652..ebd1d000d647b958273035115175320285255a44 100644
GIT binary patch
delta 773
zcmZoTz|pXPV}dlV0RsbrA_Ejm)G%i>*qCsXpV^v+ZL^}nJ#Hprfyp*9DuPA^Rwl+)
z1{QjzhNgx_#zy>;Ib@Xi;i86?Mkba<lk<_q3=E8oEsZ8Gl(B-TGuN{)G_^3dnEXn{
z5+P=0XkunzI@w6p4k2b@Xl!I=Jh@)hgb!+mxt@`sv8nmwgR*7_Wrl{PmPV$N+2o92
zVrF_4mPV##CX+qn;Oflu%ngjq4U8xE%2^}SnHrfGm>W;Njx1(mWM*PwFj-OFL>g+X
znVx}>nYpo%0W&LuxT<4fN^WM}<c0F$Fmp`xER4*|49q4^lUG8BnHiZG8=Fi%F0Z8w
zHOExX#K_Fd#Dtf>hk=d1j)DIr{}uja{QLRq_@`|aOvvJ&T&FK6&c(~atjL+e$HT11
zn3GvtQXHRIlA6o1d6|CHhD8YqiwXoFXj1{Bz;;FlMnwfa9u00S?#KL@;23nC=qSA1
zIf1c~i&=pofBOC`#st2SjQG;x)S~$K{G3KJ<LL*p88sOBr!P!l6rKJ*o3WDBgiYLE
zbMirMiRn{w80EQn)-rH_%xYvZn$DQdsK6*ceM3H@#B{5CMo%WbrPEvU8LPKz<uX<?
zvM?|(9GRTUdVsl6#B{n=HscgVuFZ@I|K(wBWD!`-a)42RhlRg^f&V%G0siIu4VwiM
z3i#_)S(q6DLyJ=t3Q`l3^OLg`(oz#kGE$3*6-x3Iauc&t6%rNFaw^4{nHfx-N-Hsx
QsWK6#pAox$recUg0ZkmrAOHXW

delta 683
zcmZozz|nAkV}dlV4g&*&5(5JRKLY~;<3tT}MxBibNBNnpc-S^8D%|5{G7^|<E2AuE
zXli9*W@T)qXJ%<)XlZQBKbb>Dg&!npY-MVuXJBS%U}Q2mUq%@wW~yglZfI^|I(eat
z6++C+(%jtCX!0u=ON5xIfrY7&(PSf8JA|0Ap_z$+!Q^^b6F#UNCVCbomX@ZI56YUs
zl$q!mn3x+`nonkvGlq#7=vf+?8CjZ6_K<_CGte_IH#9Ien%paA4OM4i338sHh3Vw$
z$YQ33rk0i#lNIGnq#@RtSn3&>n^>3{8!)pnh^sm#rsQVkO<pK3jxfi-%)-pvaPl;H
zC776no`so#siE=Y<MLX{P;)Hw%*+kVjZAs@dl=aG>lpZ7@?YU!#=oDxj(_@Q!GtXS
z$#wdI;@ljGr6n2hrMx`MiX1ta#U;h@nI);Yo0sWFZP+ZB@ScC-0>MQE0&ujcfKgyO
zqXVO&0w4E2o^oz=zJGlG7#J9wCprpmcTQle<YL~!kTZRM7GnZ8n<*Ou2sDbAOwY+@
zoWk5_W;9(ln^A*Ne)_@`M$zfn*^HH}#%$vLnv)N5OH60XVU*YATgp%d(v)M!F0QD^
z*r;5Rn3R)>a2bNdKiwyX(QCVAE@KTN3x6|1<m6n|Q07J^)9Kndj0%iOAn8OV28QYD
pa~P``xi&K<{FjILV^aZ(z;c!Yj0zkK0wB8>_#s{mU<J!7000hWtoZ-{

diff --git a/functional_tests.py b/functional_tests.py
index 547ee62..6e991b3 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -18,8 +18,6 @@ class NewVisitorTest(unittest.TestCase):
 
     # She is invited to enter a to-do item straight away
     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
         self.browser.get('http://localhost:8000/homepage')
 
         # She notices the page title and header mention to-do lists
@@ -33,24 +31,13 @@ class NewVisitorTest(unittest.TestCase):
             inputbox.get_attribute('placeholder'),
             'Enter a to-do item'
         )
-
-        # She types "Buy peacock feathers" into a text box (Edith's hobby
-        # is tying fly-fishing lures)
-        inputbox.send_keys('Buy peacock feathers')  
-
-        # When she hits enter, the page updates, and now the page lists
-        # "1: Buy peacock feathers" as an item in a to-do list table
-
+        inputbox.send_keys('Buy peacock feathers')
         inputbox.send_keys(Keys.ENTER)
-        time.sleep(1)
-        table = self.browser.find_element_by_id('id_list_table')
-        rows = table.find_elements_by_tag_name('tr')  
-        #self.assertTrue(any(row.text == '1: Buy peacock feathers' for row in rows),f"New to-do item did not appear in table")
-        self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
+        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(1)
+        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')
 
diff --git a/lists/__pycache__/tests.cpython-37.pyc b/lists/__pycache__/tests.cpython-37.pyc
index d154cb8796e7c13aed813ec9595e33ce0bb792bd..21ea18ac445b6272577227d401157545420486b5 100644
GIT binary patch
delta 1438
zcmew;v{;VMiI<m)fq{YHXhm1-N}i2;T#Sq^lO-8-Wm33W7^2uyxKlV<7^2uxcv5&<
z7@{~*_<|WU`8RtpzGG&*HQAE&kWn%tNIL@q1Bhl}U|?`&U|=X#VqjpXVaQ@wz?j0g
zkdcw0hG79y33C?90@j5LlWkcf^@~8tHQ9=|85kIfctC^<h~QvgV7SGepOlrFTvB|C
zH95aDuSAovNObZ<R^fV;lGNgo`24(_%J|~Mvee@E%#zgH;`s86)V%n-)a2CS;>4m#
zd64xWcQ7#WFjg6Q<maXaB&Mf^q!yRx5u+dOA7%yy29P;m|0FOlFiif;B2f?XL<;Ld
zCPoG@k8L4CEfdItHB4FTDa;^oFpn{dBZUpYOJSE}NMQu=Qy797G&%gLxb!pfb5jcv
z(^K_}6c`v7s`woh@>0tcax#lc6hMB{WGqr-U|@I&3ad;#Mh1pk^&C0*$%!SI`FWb0
zkgx-VbP+u4ic~<Ms0s>2*0ju`;*wh|C8-r9MY0SG44TYEq99o@kSs@DYB@OkiX=c{
zU_uhaQf6Ra0GU|~iWCM$5k?_KE=E2kK1OiB)Po|MiGhKE6&BM03=9k<3|Wj>Oeu^h
zOudYZFdj36SHqCSynrQzWg%lNV-3Rs))dAX#w@l4><bw{K>-$FMiv1F4y#`k2Pgni
zD-{ei8H=<)fddw>O085dLJl}hjv`Q+0sH$FTXIoqVo53_U_kCK5(IgP7ew$)&S#O=
zlL04zl+5CSoW#oF_{5x?cu;7AL!ww4lytzkfsv1qkBNtA@;O#9DIALZG&v{#V>RIh
zg;$Xp$OhfX#%zj0d<+Z>9E=<s94s6x9IPD79GsIA*rXX%CQCA^vVh`!@>I5~+C}Q1
z2w{h~9pt@RETAL}@dk5ZP7WkWK@mB54tq1B*<=NdfXRX^VvJ6cKd^{upynvF#0Uy!
zrW!_2Vw|kVDqfE_aY0<d0SPlu#6xU`2Wk<>4MmzD4}#pO$plG6ps>Q0blgE<2+|Bo
zI#pVno+YWdzWFJsIg@X(DuO&Q`8|tFdJSV1GsNML+>*kEl0Vpq&mZ8dQKSJ1Q5JN6
z$bzE1UJ@MbMX4#7MWBKuJ~6E%wJ1KoKRCn}<X$#Vs%8{n<YTN-hdUNgVqnwfr^!~N
z2MQE@5Mcl!OhE)VIhcW1;4B3p<Uo9I?lNRxU@(DM$-%@S$iY@*IC(8cCmTqnNCH&O
LP4?$hWYh)#{vtjW

delta 242
zcmZ21_fd$?iI<m)fq{X+$+#=lf_)<&7bBz2WJyL{mS6@=uFXk|@0b~*CI_+}V)oNy
zpPbEU!l*QP6{jK(2Ll5G2O|du2MY(w<hz{GQX&it45<uJj42FJOeu^hOf3vi%qh&l
z44N#HmAI}Ny<}uyV9;bQ0_nTOQj%Ixa*L%nu`Kl#dwx<@YH~^OE#}0WoFW+p28LU#
z$@!&uC6kr7n;8`+FXIld_0wc2Qf6RaC{h6tsvtrSL`a|#k|3@c0|SFR0|P@b6Uc>3
TMQW4d`8pZZCcosfWE2Ac{3J6m

diff --git a/lists/__pycache__/views.cpython-37.pyc b/lists/__pycache__/views.cpython-37.pyc
index 2bd53936920f4ce023b9f769a5b9be94588a1645..c8f22a400a74cd6f793fc83c9277d53805961a68 100644
GIT binary patch
delta 428
zcmbQq+`+=<#LLUYz`($;zoIMFi*X{KM7;(B149Z!3S$mKE@Kp9E>jc}BZ$wG!<@?!
z#lpyt!kog=!Vtxp!Wzt=$@UVYS(E7&M^S1@W>IQ#$t|{`)V!3`B2C6yES@E)xyg(m
z6$}gvObiSRtPBhc&I}9;#SRP%3^fc{3@MD+OhsxXj9E-s%ry*IEGbO&k_;)#y^M?u
zC9Ekd&5XeeAjt)63mIw|OW11|Qdm>iY8W#ao0)?dG}--bu>|-BheUB^mZav!m!wvd
zfUE`4Rb2WR`MIeDiRr2ORh%HEUPei7&Mj7u%3@89TWq<hB^miCMJx;q47b?xld@8i
zONwu?CF>TYCYGcYfm~Vya`G+a#GITWW(EcZO{QDyMX80Qsl_El><kPHD;bJ-C%$uv
z28SOb7o!Lx2NM@#5kCV1gP$f_lt4;WVqSW_UU5c#QAu)XNio<sut`xoIhn;J#d^8<
dDXBTdU?+gJ74b4KFdz|plj|A9SOge(m;hPRW%&RA

delta 317
zcmeBRnaRxO#LLUYz`($8jH4^|3d2M`iFy?V28I-d6viBeT*fFyMi84RhbfmiikXoi
zg*k<#g&~S1g*BK#lkFu)qbB1m9*>fef}qsmg8aPVR87WPY(=SgDXB%tj39Xi1_lt#
z!N9=a%)r1<EXBaUP{L5dkiwY4RKt+PxPS>{=t8DU#%AVV22EB^zbej*{M=N%jFQ}(
zDBir(^7zb>)ZF-z)QXZ@oCqd^CUX%p0|Ub?mH_|YkXy{@sU@0>x7dqP3rkarOI9)z
zaZV0obn<5bxq*?5v51?2fx%Cc^%i$ZR$^XyzFtO2NkI`40|P^p092$nBfqF5xwNDh
ZY%W+s5hnu!0}{bC`5mJe3lAd?69C^`OYZ;x

diff --git a/lists/templates/home.html b/lists/templates/home.html
index dd544fc..9dba103 100644
--- a/lists/templates/home.html
+++ b/lists/templates/home.html
@@ -9,7 +9,9 @@
     		{% csrf_token %}
 		</form>
 		<table id="id_list_table">
-        	<tr><td>1: {{ new_item_text }}</td></tr>
-    	</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/tests.py b/lists/tests.py
index 4a9024e..8a65cfc 100644
--- a/lists/tests.py
+++ b/lists/tests.py
@@ -28,6 +28,27 @@ class HomePageTest(TestCase):
         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):
@@ -45,4 +66,15 @@ class ItemModelTest(TestCase):
         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')
\ No newline at end of file
+        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 7ef5b31..7454b76 100644
--- a/lists/views.py
+++ b/lists/views.py
@@ -1,7 +1,10 @@
-from django.http import HttpResponse
-from django.shortcuts import render
+from django.shortcuts import redirect, render
+from lists.models import Item
 
 def home_page(request):
-    return render(request, 'home.html', {
-        'new_item_text': request.POST.get('item_text', ''),
-    })
\ 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
-- 
GitLab