Killer Web Development

by Marco Laspe

5.2 HTML and more Tests

In this section we will learn the basics of HTML, which are quite simple; on the way we will fix our remaining tests and create new ones for new pages. We will write static HTML in the view of our index function. For learning purposes let's remove all content from the index.html file; but before we commit the changes to our repository:

1.
2.
3.
4.
$ hg status
M fts/test_static_pages.py
$ hg commit -m"new test for our home page"
$ gedit views/default/index.html

Remove all content from index.html. If you pay attention, you see that we lost our whole design, that we inherited from the default web2py application; run the tests again and see how the error messages are changing (From now own you should be able to run the tests yourself.).

What is HTML?

HTML is a markup language that structure websites in chunks of content and meta information about the content itself - which language has it, who is the author, what ist the title of the website. You can imagine a website like a magazine article: It consists of a title, a header, maybe several subheadeings, a lot of paragraphs, etc.

Wikipedia says

HTML

HyperText Markup Language (HTML) is the main markup language for web pages. HTML elements are the basic building-blocks of webpages. HTML is written in the form of HTML elements consisting of tags enclosed in angle brackets (like ), within the web page content. HTML tags most commonly come in pairs like . The first tag in a pair is the start tag, the second tag is the end tag (they are also called opening tags and closing tags). In between these tags web designers can add text, tags, comments and other types of text-based content. The purpose of a web browser is to read HTML documents and compose them into visible or audible web pages. The browser does not display the HTML tags, but uses the tags to interpret the content of the page.

HTML structures it's content in elements, for example a very basic version of our index.html file could look like this:

1.
2.
3.
4.
5.
6.
7.
8.
9.
<!DOCTYPE html>
<
html>
<
head>
<
title>Microposts On Steroids</title>
</
head>
<
body>
<
h1>Messages With 300 Chars</h1>
</
body>
</
html>

In line 1 we define the document type of our webpage, the doctype html is always fine and you won't need any other in the future.
Line 2 opens the html document.
In line 3 begins the head section of the document, which contains information about the content of the page, in our case the title of the page - which is defined in line 4.
In line 6 starts the content of the page which is encapsulated by the body element.
h1 in line 7 stands for first a first order headline.

As you probably recognized, HTML elements are normally surrounded by a start tag and an end tag. There are also a few elements that have only one tag - the img tag is the most important.

The elements are divided in two groups block and inline elements. Block elements usually claim the whole width for them self; inline elements only take the space they need. In our index.html we use only block elements at the moment.

Let's ad an inline element:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<!DOCTYPE html>
<
html>
<
head>
<
title>Microposts On Steroids</title>
</
head>
<
body>
<
h1>Messages With 300 Chars</h1>
<
p>Welcome to <strong>Tukker.Me</strong>, the new way to
tell your friends and the world what you are thinking.</p>
</
body>
</
html>

We created an inline element strong and filled it with the content Tukker.Me.

Let's see how our page looks in the browser. The look of the content is determined by the default settings of the browser, later in this chapter we will define our own styles. If you press F12 you can examine the source code and the styles of the page in the web browser.

Now let's check if we pass our tests.

1.
2.
3.
4.
5.
6.
7.
8.
$ python functional_tests.py

...

----------------------------------------------------------------------
Ran 3 test in 19.552s

OK

Looking good so far. Maybe it's time to commit our changes:

1.
$ hg commit -m"Finished first draft of home page"

More Static pages

If we look at our website structure, we can see the rest of our static pages like Privacy, About, etc.

website structue of our twitter like app

We will begin implementing them by writing our tests first.

Open test_static_pages.py and add the following content:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
class TestPrivacyPage(FunctionalTest):

def setUp(self):
# John opens his browser and goes to the privacy page
self.url = ROOT + '/tukker/default/privacy'
get_browser=self.browser.get(self.url)

def test_can_view_privacy_page(self):
# Let's check if the website was loaded ok
response_code = self.get_response_code(self.url)
self.assertEqual(response_code, 200)

def test_has_right_title(self):
# First he looks at the topbar and sees 'Tukker.Me Privacy Policy'
title = self.browser.find_element_by_tag_name('title')
self.assertEqual('Tukker.Me Privacy Policy', title.text)

def test_has_right_heading(self):
# He's looking for the heading "Tukker.Me Privacy Policy"
heading = self.browser.find_element_by_tag_name('h1')
self.assertIn('Tukker.Me Privacy Policy', heading.text)


class TestAboutPage(FunctionalTest):

def setUp(self):
# John opens his browser and goes to the about page
self.url = ROOT + '/tukker/default/about'
get_browser=self.browser.get(self.url)

def test_can_view_about_page(self):
# Let's check if the website was loaded ok
response_code = self.get_response_code(self.url)
self.assertEqual(response_code, 200)

def test_has_right_title(self):
# First he looks at the topbar and sees 'About Tukker.Me'
title = self.browser.find_element_by_tag_name('title')
self.assertEqual('About Tukker.Me', title.text)

def test_has_right_heading(self):
# He's looking for the heading "About Tukker.Me"
heading = self.browser.find_element_by_tag_name('h1')
self.assertIn('About Tukker.Me', heading.text)

Now re-run functional_tests.pyand look at the output:

1.
2.
3.
4.
5.
6.
7.
$ python functional_tests.py
...

----------------------------------------------------------------------
Ran 9 tests in 16.724s

FAILED (errors=6)

The new tests should all fail, cause the pages are not created yet. We will change this now and pass each test one by one. We will first create a new controller function in the default.py controller and then create a corresponding view with the content we need. Open default.py in gedit:

1.
$ gedit controllers/default.py

and add the following content:

1.
2.
def privacy():
return dict()

Now run the functional_tests.py again, you should only have 4 errors and one failure remaining. This means 4 tests did pass.

What the difference between a failure and an error? Errors get raised if some code is not executable, e.g. if there is no title tag in the webpage and you try to self.browser.find_element_by_tag_name('title') you get an error. Failures on the other hand come from unsatisfied assertions, e.g. the privacy page has a title, but is has a wrong value, ergo you get a failure (If you wonder why there is an title element in the privacy page: It gets created by some default/fallback values of web2py.)

To pass the two other tests for the privacy page we need to create a new view in the views folder:

1.
$ gedit views/privacy.html

and we begin with the basic html structure of the view:

1.
2.
3.
4.
5.
6.
7.
<!DOCTYPE html>
<
html>
<
head>
</
head>
<
body>
</
body>
</
html>

again test it (Yeah I know we test a lot, but it is for learning purposes!). What does it say? 5 errors remaining.

1.
2.
3.
4.
5.
6.
7.
8.
<!DOCTYPE html>
<
html>
<
head>
<
title>Tukker.Me Privacy Policy</title>
</
head>
<
body>
</
body>
</
html>

you are right: test it! This time we should only have 4 errors remaining. Seems we're heading in the right direction. Now we are finishing the last test for the privacy page, add a header in privacy.html:

1.
2.
3.
4.
5.
6.
7.
8.
9.
<!DOCTYPE html>
<
html>
<
head>
<
title>Tukker.Me Privacy Policy</title>
</
head>
<
body>
<
h1>Tukker.Me Privacy Policy</h1>
</
body>
</
html>

Now if we start our tests it, we are down to 3 errors. We did pass all the test for the privacy page. That was fun, wasn't it. We will fix now pass the tests for the about page. This time we will write all the code at once and then check if we pass the tests:

  1. First add an about function to the default.py controller:

    def about(): return dict()

then create a new view about.html:

1.
$ gedit views/default/about.html

with the following content:

1.
2.
3.
4.
5.
6.
7.
8.
9.
<!DOCTYPE html>
<
html>
<
head>
<
title>About Tukker.Me</title>
</
head>
<
body>
<
h1>About Tukker.Me</h1>
</
body>
</
html>

Now test your Tukker.Me application again: TaDA, we passed all our test! We should commit that :)

1.
$ hg commit -m"Created privacy and about page (controllers, views, tests)"

Question and Answers about Functional Tests

Do I have to test every bit on a webpage?
You should test as much as possible. Everything, that has to be implemented by you, has to be tested. In our example we were quite extreme, testing even simple content. On a production site you probably wouldn't do this. Especially if you have longer text passages.
How often should I test?
You should test as often as possible. Try to pass one test at a time. I know that seems exaggerated, but if your projects get bigger this will save you a lot of time and hassle.
Do I have to test every sentence that gets displayed on the page?
No, normally not. We did it for learning purposes. You should always test user interaction like clicking on a link or submitting forms. We will see this later in the book.

Books often read by web2py and Python experts:

Comments

  1. Should be: $ gedit views/dafault/privacy.html instead of: $ gedit views/privacy.html Cheers

Leave a Reply

Required fields are marked *.