8000 Added section10 final code to the repository. · ciguler/testing-python-apps@41b4c71 · GitHub
[go: up one dir, main page]

Skip to content

Commit 41b4c71

Browse files
committed
Added section10 final code to the repository.
1 parent 7a97523 commit 41b4c71

28 files changed

+385
-9
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
*.key
2+
*.screenflow
3+
*.png
14
starter_code.zip
25
.idea/
36
.DS_Store

section10/code/app.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from flask import Flask, render_template, request, redirect, url_for
2+
3+
app = Flask(__name__)
4+
5+
posts = []
6+
7+
8+
@app.route('/')
9+
def homepage():
10+
return render_template('home.html')
11+
12+
13+
@app.route('/blog')
14+
def blog_page():
15+
return render_template('blog.html', posts=posts)
16+
17+
18+
@app.route('/post', methods=['GET', 'POST'])
19+
def add_post():
20+
if request.method == 'POST':
21+
title = request.form['title']
22+
content = request.form['content']
23+
global posts
24+
25+
posts.append({
26+
'title': title,
27+
'content': content
28+
})
29+
30+
return redirect(url_for('blog_page'))
31+
return render_template('new_post.html')
32+
33+
34+
@app.route('/post/<string:title>')
35+
def see_post(title):
36+
global posts
37+
38+
for post in posts:
39+
if post['title'] == title:
40+
return render_template('post.html', post=post)
41+
42+
return render_template('post.html', post=None)
43+
44+
45+
if __name__ == '__main__':
46+
app.run()

section10/code/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Flask
2+
uwsgi
3+
behave==1.2.5
4+
beautifulsoup4==4.5.3
5+
selenium==3.4.1

section10/code/templates/blog.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script>
5+
window.onload = function() {
6+
setTimeout(function() {
7+
document.getElementById('posts').style.display = 'block';
8+
}, 3000);
9+
};
10+
11+
</script>
12+
</head>
13+
<body>
14+
<h1>This is the blog page</h1>
15+
16+
<a href="{{ url_for('homepage') }}" class="nav-link" id="home-link">Go to home</a>
17+
<a href="{{ url_for('add_post') }}" class="nav-link" id="add-post-link">Create post</a>
18+
19+
<ol id="posts" style="display: none">
20+
{% for post in posts %}
21+
<li class="post"><a href="{{ url_for('see_post', title=post['title']) }}" class="post-link">{{ post['title'] }}</a></li>
22+
{% endfor %}
23+
</ol>
24+
</body>
25+
</html>

section10/code/templates/home.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
5+
</head>
6+
<body>
7+
<h1>This is the homepage</h1>
8+
9+
<a href="{{ url_for('blog_page') }}" class="nav-link" id="blog-link">Go to blog</a>
10+
</body>
11+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
5+
</head>
6+
<body>
7+
<h1>Create post</h1>
8+
9+
<a href="{{ url_for('blog_page') }}" class="nav-link" id="blog-link">Back to blog</a>
10+
11+
<form method="POST" id="post-form">
12+
<div>
13+
<label for="title">Post title:</label>
14+
<input type="text" name="title" id="title" />
15+
</div>
16+
<div>
17+
<label for="content">Post content:</label>
18+
<textarea name="content" id="content"></textarea>
19+
</div>
20+
<div>
21+
<button type="submit" id="create-post">Create</button>
22+
</div>
23+
</form>
24+
</body>
25+
</html>

section10/code/templates/post.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
5+
</head>
6+
<body>
7+
{% if post %}
8+
<h1>{{ post['title'] }}</h1>
9+
10+
<p>{{ post['content'] }}</p>
11+
{% else %}
12+
<h1>Post not found!</h1>
13+
{% endif %}
14+
</body>
15+
</html>

section10/code/tests/__init__.py

Whitespace-only changes.

section10/code/tests/acceptance/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Feature: Test that pages have correct content
2+
Scenario: Blog page has a correct title
3+
Given I am on the blog page
4+
Then There is a title shown on the page
5+
And The title tag has content "This is the blog page"
6+
7+
Scenario: Homepage has a correct title
8+
Given I am on the homepage
9+
Then There is a title shown on the page
10+
And The title tag has content "This is the homepage"
11+
12+
Scenario: Blog page loads the posts
13+
Given I am on the blog page
14+
And I wait for the posts to load
15+
Then I can see there is a posts section on the page
16+
17+
Scenario: User can create new posts
18+
Given I am on the new post page
19+
When I enter "Test Post" in the "title" field
20+
And I enter "Test Content" in the "content" field
21+
And I press the submit button
22+
Then I am on the blog page
23+
Given I wait for the posts to load
24+
Then I can see there is a post with title "Test Post" in the posts section

section10/code/tests/acceptance/locators/__init__.py

Whitespace-only changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from selenium.webdriver.common.by import By
2+
3+
4+
class BasePageLocators:
5+
TITLE = By.TAG_NAME, 'h1'
6+
NAV_LINKS = By.CLASS_NAME, 'nav-link'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from selenium.webdriver.common.by import By
2+
3+
4+
class BlogPageLocators:
5+
ADD_POST_LINK = By.ID, 'add-post-link'
6+
POSTS_SECTION = By.ID, 'posts'
7+
POST = By.CLASS_NAME, 'post-link'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from selenium.webdriver.common.by import By
2+
3+
4+
class HomePageLocators:
5+
NAVIGATION_LINK = By.ID, 'blog-link'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from selenium.webdriver.common.by import By
2+
3+
4+
class NewPostPageLocators:
5+
NEW_POST_FORM = By.ID, 'post-form'
6+
TITLE_FIELD = By.ID, 'title'
7+
CONTENT_FIELD = By.ID, 'content'
8+
SUBMIT_BUTTON = By.ID, 'create-post'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Feature: Test navigation between pages
2+
We can have a longer description
3+
That can span a few lines
4+
5+
Scenario: Homepage can go to Blog
6+
Given I am on the homepage
7+
When I click on the "Go to blog" link
8+
Then I am on the blog page
9+
10+
Scenario: Blog can go to Homepage
11+
Given I am on the blog page
12+
When I click on the "Go to home" link
13+
Then I am on the homepage

section10/code/tests/acceptance/page_model/__init__.py

Whitespace-only changes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from tests.acceptance.locators.base_page import BasePageLocators
2+
3+
4+
class BasePage:
5+
def __init__(self, driver):
6+
self.driver = driver
7+
8+
@property
9+
def url(self):
10+
return 'http://127.0.0.1:5000'
11+
12+
@property
13+
def title(self):
14+
return self.driver.find_element(*BasePageLocators.TITLE)
15+
16+
@property
17+
def navigation(self):
18+
return self.driver.find_elements(*BasePageLocators.NAV_LINKS)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from tests.acceptance.locators.blog_page import BlogPageLocators
2+
from tests.acceptance.page_model.base_page import BasePage
3+
4+
5+
class BlogPage(BasePage):
6+
@property
7+
def url(self):
8+
return super(BlogPage, self).url + '/blog'
9+
10+
@property
11+
def posts_section(self):
12+
return self.driver.find_element(*BlogPageLocators.POSTS_SECTION)
13+
14+
@property
15+
def posts(self):
16+
return self.driver.find_elements(*BlogPageLocators.POST)
17+
18+
@property
19+
def add_post_link(self):
20+
return self.driver.find_element(*BlogPageLocators.ADD_POST_LINK)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from tests.acceptance.locators.home_page import HomePageLocators
2+
from tests.acceptance.page_model.base_page import BasePage
3+
4+
5+
class HomePage(BasePage):
6+
@property
7+
def url(self):
8+
return super(HomePage, self).url + '/'
9+
10+
@property
11+
def blog_link(self):
12+
return self.driver.find_element(*HomePageLocators.NAVIGATION_LINK)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from selenium.webdriver.common.by import By
2+
3+
from tests.acceptance.locators.new_post_page import NewPostPageLocators
4+
from tests.acceptance.page_model.base_page import BasePage
5+
6+
7+
class NewPostPage(BasePage):
8+
@property
9+
def url(self):
10+
return super(NewPostPage, self).url + '/post'
11+
12+
@property
13+
def form(self):
14+
return self.driver.find_element(*NewPostPageLocators.NEW_POST_FORM)
15+
16+
@property
17+
def submit_button(self):
18+
return self.driver.find_element(*NewPostPageLocators.SUBMIT_BUTTON)
19+
20+
def form_field(self, name):
21+
return self.form.find_element(By.NAME, name)

section10/code/tests/acceptance/steps/__init__.py

Whitespace-only changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from behave import *
2+
3+
from tests.acceptance.page_model.base_page import BasePage
4+
from tests.acceptance.page_model.blog_page import BlogPage
5+
6+
use_step_matcher('re')
7+
8+
9+
@then('There is a title shown on the page')
10+
def step_impl(context):
11+
page = BasePage(context.driver)
12+
assert page.title.is_displayed()
13+
14+
15+
@step('The title tag has content "(.*)"')
16+
def step_impl(context, content):
17+
page = BasePage(context.driver)
18+
assert page.title.text == content
19+
20+
21+
@then('I can see there is a posts section on the page')
22+
def step_impl(context):
23+
page = BlogPage(context.driver)
24+
25+
assert page.posts_section.is_displayed()< 341A /div>
26+
27+
28+
@then('I can see there is a post with title "(.*)" in the posts section')
29+
def step_impl(context, title):
30+
page = BlogPage(context.driver)
31+
posts_with_title = [post for post in page.posts if post.text == title]
32+
33+
assert len(posts_with_title) > 0
34+
assert all([post.is_displayed() for post in posts_with_title])
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from behave import *
2+
3+
from tests.acceptance.page_model.base_page import BasePage
4+
from tests.acceptance.page_model.new_post_page import NewPostPage
5+
6+
use_step_matcher('re')
7+
8+
9+
@when('I click on the "(.*)" link')
10+
def step_impl(context, link_text):
11+
page = BasePage(context.driver)
12+
links = page.navigation
13+
14+
matching_links = [l for l in links if l.text == link_text]
15+
16+
if len(matching_links) > 0:
17+
matching_links[0].click()
18+
else:
19+
raise RuntimeError()
20+
21+
22+
@when('I enter "(.*)" in the "(.*)" field')
23+
def step_impl(context, content, field_name):
24+
page = NewPostPage(context.driver)
25+
page.form_field(field_name).send_keys(content)
26+
27+
28+
@when('I press the submit button')
29+
def step_impl(context):
30+
page = NewPostPage(context.driver)
31+
page.submit_button.click()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from behave import *
2+
from selenium import webdriver
3+
4+
from tests.acceptance.page_model.blog_page import BlogPage
5+
from tests.acceptance.page_model.home_page import HomePage
6+
from tests.acceptance.page_model.new_post_page import NewPostPage
7+
8+
use_step_matcher('re')
9+
10+
11+
@given('I am on the homepage')
12+
def step_impl(context):
13+
context.driver = webdriver.Chrome()
14+
page = HomePage(context.driver)
15+
context.driver.get(page.url)
16+
17+
18+
@given('I am on the blog page')
19+
def step_impl(context):
20+
context.driver = webdriver.Chrome()
21+
page = BlogPage(context.driver)
22+
context.driver.get(page.url)
23+
24+
25+
@given('I am on the new post page')
26+
def step_impl(context):
27+
context.driver = webdriver.Chrome()
28+
page = NewPostPage(context.driver)
29+
context.driver.get(page.url)
30+
31+
32+
@then('I am on the blog page')
33+
def step_impl(context):
34+
expected_url = BlogPage(context.driver).url
35+
assert context.driver.current_url == expected_url
36+
37+
38+
@then('I am on the homepage')
39+
def step_impl(context):
40+
expected_url = HomePage(context.driver).url
41+
assert context.driver.current_url == expected_url

0 commit comments

Comments
 (0)
0