วันเสาร์ที่ 14 เมษายน พ.ศ. 2561

Commit 9 Wordbucket : add detail page for the word and non duplicate word added function

Assignment1 : Wordbucket GitHub Link

Commit 9 Wordbucket : add detail page for the word and non duplicate word added function

Commits on Mar 4, 2018

functional tests

เพิ่ม test โดย
- แก้ implicit wait ออกเพื่อลดเวลาการ test
- แก้ประโยคที่ไม่ make sense ใน user story
- เพิ่ม test_can_view_the_word_explanation_and_add_exist_word_new_explanation เทสในคำอธิบายใหม่ในคำที่ซ้ำ(ใส่คำที่มีอยู่แล้วไป กับ explanation ที่ต่างจากเดิมจะทำการเพิ่ม explanation ในคำที่มีอยู่แล้ว) พร้อม user story ใหม่

@@ -1,3 +1,7 @@
+from selenium.common.exceptions import WebDriverException
+
+MAX_WAIT = 10
+
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
@@ -12,9 +16,31 @@ def tearDown(self):
self.browser.quit()
def check_for_row_in_list_table(self, row_text):
- table = self.browser.find_element_by_id('id_word_table')
- rows = table.find_elements_by_tag_name('tr')
- self.assertIn(row_text, [row.text for row in rows])
+ start_time = time.time()
+ while True:
+ try:
+ table = self.browser.find_element_by_id('id_word_table')
+ rows = table.find_elements_by_tag_name('tr')
+ self.assertIn(row_text, [row.text for row in rows])
+ return
+ except (AssertionError, WebDriverException) as e:
+ if time.time() - start_time > MAX_WAIT:
+ raise e
+ time.sleep(0.5)
+
+ def check_for_row_in_explanation_table(self, row_text):
+ start_time = time.time()
+ while True:
+ try:
+ table = self.browser.find_element_by_id('id_explanation_table')
+ rows = table.find_elements_by_tag_name('tr')
+ self.assertIn(row_text, [row.text for row in rows])
+ return
+ except (AssertionError, WebDriverException) as e:
+ if time.time() - start_time > MAX_WAIT:
+ raise e
+ time.sleep(0.5)
+
def test_can_start_a_list_and_retrieve_it_later(self):
# Ann has heard about a cool new online word app. She goes
@@ -33,25 +59,73 @@ def test_can_start_a_list_and_retrieve_it_later(self):
'Add new word'
)
- # She types "weeb" into a text box
+ # She types "weeb" into a text box and "otaku!" in a explanation text box
inputbox.send_keys('weeb')
+ explanationbox = self.browser.find_element_by_id('id_new_eplanation')
+ explanationbox.send_keys('otaku!')
# When she hits enter, the page updates, and now the page word lists
# "1: weeb" as an item in a word list table
inputbox.send_keys(Keys.ENTER)
- time.sleep(1)
- self.check_for_row_in_list_table('1: weeb')
+ self.check_for_row_in_list_table('weeb')
# There is still a text box inviting her to add another item. She
- # enters "PogChamp"
+ # enters "PogChamp" and "awesome!" in a explanation text box
inputbox = self.browser.find_element_by_id('id_new_word')
inputbox.send_keys('PogChamp')
+ explanationbox = self.browser.find_element_by_id('id_new_eplanation')
+ explanationbox.send_keys('awesome!')
+ inputbox.send_keys(Keys.ENTER)
+
+ # The page updates again, and now shows both items on website's word
+ self.check_for_row_in_list_table('weeb')
+ self.check_for_row_in_list_table('PogChamp')
+
+ def test_can_view_the_word_explanation_and_add_exist_word_new_explanation(self):
+ # Ann has heard about a cool new online word app. She goes
+ # to check out its homepage
+ self.browser.get(self.live_server_url)
+ # She is invited to enter a word item straight away
+ inputbox = self.browser.find_element_by_id('id_new_word')
+ self.assertEqual(
+ inputbox.get_attribute('placeholder'),
+ 'Add new word'
+ )
+
+ # She types "weeb" into a text box and "otaku!" in a explanation text box
+ inputbox.send_keys('weeb')
+ explanationbox = self.browser.find_element_by_id('id_new_eplanation')
+ explanationbox.send_keys('otaku!')
+
+ # When she hits enter, the page updates, and now the page word lists
+ # "1: weeb" as an item in a word list table
+ inputbox.send_keys(Keys.ENTER)
+ self.check_for_row_in_list_table('weeb')
+
+ # She test add exist word's second explanation
+ inputbox = self.browser.find_element_by_id('id_new_word')
+ inputbox.send_keys('weeb')
+ explanationbox = self.browser.find_element_by_id('id_new_eplanation')
+ explanationbox.send_keys('non japanese otaku!')
inputbox.send_keys(Keys.ENTER)
- time.sleep(1)
+
+ # She notice message "duplicate word, your explanation add to existing word."
+ message_text = self.browser.find_element_by_tag_name('h4').text
+ self.assertIn('duplicate word, your explanation add to existing word.', message_text)
+
+ # She click on weeb's url.
+ url_table = self.browser.find_element_by_id('id_word_table')
+ url = url_table.find_element_by_link_text('weeb')
+ url.send_keys(Keys.ENTER)
+
+ # She notices that her word has a unique URL
+ ann_list_url = self.browser.current_url
+ self.assertRegex(ann_list_url, '/.+')
- # The page updates again, and now shows both items on her list
- self.check_for_row_in_list_table('1: weeb')
- self.check_for_row_in_list_table('2: PogChamp')
+ # now the page "weeb" word
+ # "awesome!" as an item in a "weeb" word table
+ self.check_for_row_in_explanation_table('explanation 1 : otaku!')
+ self.check_for_row_in_explanation_table('explanation 2 : non japanese otaku!')
if __name__ == '__main__':
unittest.main(warnings='ignore')

models.py

เพิ่ม model เล็กน้อยโดยใส่ datetime ที่ โพสเข้าไป

@@ -1,10 +1,15 @@
+from datetime import datetime
from django.db import models
+from django.utils import timezone
class Word(models.Model):
#word (text)
word = models.TextField(default='')
+ date_pub = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.word
+ def was_published_recently(self):
+ return self.date_pub >= timezone.now() - datetime.timedelta(days=1)
class Explanation(models.Model):
#foreign key

/templates/detail.html
เพิ่มหน้า detail.html สำหรับดูคำอธิบาย (explanation) ของ word (มีหลาย explanation สำหรับหลายคนก็อาจจะอธิบายไม่เหมือนกัน)

@@ -0,0 +1,21 @@
+<html>
+ <head>
+ <title>Word Bucket</title>
+ </head>
+ <body>
+ <h1>Word Bucket</h1>
+ <form method="POST" id="form1">
+ <input name="explanation_input" id="id_new_eplanation" placeholder="Add explanation" />
+ {% csrf_token %}
+ </form>
+ <button type="submit" form="form1" value="Submit">Submit</button>
+
+ <h2>{{ word }}</h2>
+
+ <table id="id_explanation_table">
+ {% for explanation in word.explanation_set.all %}
+ <tr><td>explanation {{ forloop.counter }} : {{ explanation.explanation_text }}</td></tr>
+ {% endfor %}
+ </table>
+ </body>
+</html>

/templates/home.html
- เพิ่ม message เตือนตอน word ซ้ำโดยให้ตัวแปรชื่อ d_message
- เปลี่ยนจากโชว์ word ในตารางธรรมดาเป็น link ไปหน้า detail ของ word นั้นๆ


@@ -4,6 +4,7 @@
</head>
<body>
<h1>Word Bucket</h1>
+ <h4>{{ d_message }}</h4>
<form method="POST" id="form1">
<input name="word_input" id="id_new_word" placeholder="Add new word" />
<input name="explanation_input" id="id_new_eplanation" placeholder="Add explanation" />
@@ -13,7 +14,7 @@ <h1>Word Bucket</h1>
<table id="id_word_table">
{% for word in words %}
- <tr><td>{{ forloop.counter }}: {{ word.word }}</td></tr>
+ <tr><td id="word.word"><a href="{% url 'wordbucket:detail' word.id %}">{{ word.word }}</a></td></tr>
{% endfor %}
</table>
</body>

unit test

- แก้ชื่อคลาส WordAndExplanationModelTest  เป็น AllAroundModelsTest เนื่องจากไม่ได้ test แค่ word กับ explanation แต่จะมี ตารางอื่นเพิ่มมาในอนาคต
- test หน้า word view (function word_view and template detail.html) โดยมี 3 tests คือ
    - test template ถูกต้องหรือไม่
    - test ใช้ template
    - test แสดง explanation ใน word ที่เราดู

@@ -2,7 +2,6 @@
from django.test import TestCase
from django.http import HttpRequest
from django.template.loader import render_to_string
-
from wordbucket.views import home_page
from wordbucket.models import Word, Explanation, Like_and_dislike
@@ -46,7 +45,7 @@ def test_displays_all_list_words(self):
self.assertIn('wordey 2', response.content.decode())
-class WordAndExplanationModelTest(TestCase):
+class AllAroundModelsTest(TestCase):
def test_saving_and_retrieving_words(self):
@@ -76,9 +75,6 @@ def test_saving_and_retrieving_words(self):
self.assertEqual(second_saved_explanation.explanation_text, 'Explanation the second')
self.assertEqual(second_saved_explanation.word, word_)
-
-class ExplanationAndLike_and_dislikeModelTest(TestCase):
-
def test_saving_and_retrieving_like_and_dislike(self):
word_ = Word()
@@ -112,5 +108,38 @@ def test_saving_and_retrieving_like_and_dislike(self):
self.assertEqual(second_saved_votes_like.votes_dislike, 2)
self.assertEqual(second_saved_votes_like.explanation, explanation_)
+class WordViewTest(TestCase):
+
+ def test_passes_correct_word_to_template(self):
+ other_word = Word.objects.create()
+ correct_word = Word.objects.create()
+ response = self.client.get('/%d/' % (correct_word.id,))
+ self.assertEqual(response.context['word'], correct_word)
+
+ def test_uses_word_template(self): # detail page
+ word_ = Word.objects.create()
+ response = self.client.get('/%d/' % (word_.id,))
+ self.assertTemplateUsed(response, 'detail.html')
+
+
+ def test_displays_only_explanation_for_that_word(self):
+ correct_word = Word.objects.create()
+ Explanation.objects.create(explanation_text='itemey 1', word=correct_word)
+ Explanation.objects.create(explanation_text='itemey 2', word=correct_word)
+ other_word = Word.objects.create()
+ Explanation.objects.create(explanation_text='other word item 1', word=other_word)
+ Explanation.objects.create(explanation_text='other word item 2', word=other_word)
+
+ response = self.client.get('/%d/' % (correct_word.id,))
+
+ self.assertContains(response, 'itemey 1')
+ self.assertContains(response, 'itemey 2')
+ self.assertNotContains(response, 'other word item 1')
+ self.assertNotContains(response, 'other word item 2')
+'''
+class NewWordTest(TestCase):
+class NewExplanationTest(TestCase):
+class VoteTest(TestCase):
+class SearchAndBrowseTest(TestCase):'''

urls.py
เพิ่ม path function ที่เพิ่มใน views.py
@@ -1,6 +1,13 @@
from django.urls import path, re_path
from wordbucket import views
+app_name = 'wordbucket'
urlpatterns = [
path('', views.home_page, name='home'),
+ path('add_word/', views.add_word, name='add_word'),
+ path('search/', views.search, name='search'),
+ re_path(r'^(\d+)/$', views.view_word, name='detail'),
+ re_path(r'^(\d+)/add_explanation$', views.add_explanation, name='add_explanation'),
+ re_path(r'^(\d+)/like$', views.vote_like, name='like'),
+ re_path(r'^(\d+)/dislike$', views.vote_dislike, name='dislike'),
]

views.py
- แก้การ home_page() ไม่ให้สามารถเพิ่ม duplicate word แล้วสร้างคำใหม่โดยใช้ตัวแปร d_query query หา word ใน database ถ้าไม่มีถึงเพิ่มได้ ถ้ามีจะเพิ่ม explanation ใน word เดิม

- เพิ่ม function view_word() โดยตอนนี้ทำเพียง ส่งตัวแปร word_  ตาม link จากหน้า home ในชื่อ word  โดยสามารถ ขอ explanation_set ของ word นั้นใน template ได้ จึงสามารถแสดง explanation ทั้งหมดของ word นั้นๆได้

@@ -2,10 +2,39 @@
from wordbucket.models import Word, Explanation, Like_and_dislike
def home_page(request):
+ d_message = ""
+ words = Word.objects.order_by('-date_pub')[:5]
if request.method == 'POST':
- word_ = Word.objects.create(word=request.POST['word_input'])
- Explanation.objects.create(explanation_text=request.POST['explanation_input'], word=word_)
- return redirect('/')
+ word_reference = str(request.POST['word_input'])
+ # query for duplicate word
+ d_query = Word.objects.filter(word=word_reference)
+ if not d_query :
+ word_ = Word.objects.create(word = request.POST['word_input'])
+ Explanation.objects.create(explanation_text=request.POST['explanation_input'], word=word_)
+ return redirect('/')
+ else :
+ # duplacate word id
+ dword_id = Word.objects.get(word = word_reference)
+ Explanation.objects.create(explanation_text=request.POST['explanation_input'], word=dword_id)
+ d_message = "duplicate word, your explanation add to existing word."
+ return render(request, 'home.html', {'words': words, 'd_message': d_message})
+ return render(request, 'home.html', {'words': words, 'd_message': d_message})
- words = Word.objects.all()
- return render(request, 'home.html', {'words': words})
+def view_word(request, word_id):
+ word_ = Word.objects.get(id=word_id)
+ return render(request, 'detail.html', {'word': word_})
+
+def add_word(request):
+ pass
+
+def add_explanation(request):
+ pass
+
+def vote_like(request):
+ pass
+
+def vote_dislike(request):
+ pass
+
+def search(request):
+ pass


ไม่มีความคิดเห็น:

แสดงความคิดเห็น