Skip to content

Stephen hero patch 8 #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions course-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ content:
- introduction
- selenium_methods
- test_frameworks
- page_object
4 changes: 2 additions & 2 deletions introduction/finding_elements/find_child_element/task.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<h2><strong>Task: search of descendant</strong></h2>

<p>Open the page <a href="http://suninjuly.github.io/cats.html" rel="nofollow noopener noreferrer">http://suninjuly.github.io/cats.html</a>. Open the developer console, the Elements tab. Write a <strong>minimal</strong> sufficient CSS selector that will find the serious cat picture (Serious cat). For finding the appropriate element in the picture folder, use the parent element <strong>div.col-sm-4 </strong> together with the pseudo-class <strong>&nbsp;:nth-child(n)</strong> to choose the n-th element, as well as the picture selector based on the <strong>img</strong> tag. When writing the selector, don't use the <strong>&gt;</strong> symbol, as this is a task of finding a descendant without using child elements. To solve it, the above-mentioned selectors must be enough.</p>
<p>Open the page <a href="http://suninjuly.github.io/cats.html" rel="nofollow noopener noreferrer">http://suninjuly.github.io/cats.html</a>. Open the developer console, the Elements tab. Write a <strong>minimal</strong> sufficient CSS selector that will find the serious cat picture (Serious cat). For finding the appropriate element in the picture folder, use the parent element <strong>div.col-sm-4 </strong> together with the pseudo-class <strong>&nbsp;:nth-child(n)</strong> to choose the n-th element, as well as a picture selector based on the <strong>img</strong> tag. When writing the selector, don't use the <strong>&gt;</strong> symbol, as this is a task of finding a descendant without using child elements. To solve it, the above-mentioned selectors must be enough.</p>

<p>Please do not use selectors generated by the browser when clicking the "Copy CSS selector" button or by extensions. They often build the whole path starting from the <strong>body</strong>, and that is a very unstable selector; writing such selectors in your code is a bad practice. In case of a slightest modification in the page structure, all your selectors will lose relevance.&nbsp;</p>
<p>Please do not use selectors generated by the browser when clicking the "Copy CSS selector" button or those generated by extensions. They often build the whole path starting from the <strong>body</strong>, and that is a very unstable selector; writing such selectors in your code is a bad practice. In case of a slightest modification in the page structure, all your selectors will lose relevance.&nbsp;</p>

<p>Do not use square brackets – constructions like <em>[class=&quot;stepic&quot;].</em></p>

Expand Down
2 changes: 2 additions & 0 deletions page_object/first_tests_with_po/lesson-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type: framework
custom_name: "writing first test with page object"
3 changes: 3 additions & 0 deletions page_object/section-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
content:
- what_is_po
- first_tests_with_po
19 changes: 19 additions & 0 deletions page_object/what_is_po/about code style/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@pytest.mark.regression
# test out of scope of a class
def test_student_can_see_lesson_name_in_lesson_in_course_after_joining(self, driver):
# lines inside the scope of the test method with indent
page = CoursePromoPage(url=self.course.url, driver=driver)
page.open()


class TestLessonNameInCourseForTeacher():
@pytest.mark.regression
# test inside the class
def test_teacher_can_see_lesson_name_in_lesson_in_course(self, driver):
page = LessonPlayerPage(url=self.lesson_url, driver=driver)
page.open()
try:
# indent for any new scope
dangerous_function()
except:
close_something()
6 changes: 6 additions & 0 deletions page_object/what_is_po/about code style/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type: theory
files:
- name: main.py
visible: true
- name: __init__.py
visible: false
42 changes: 42 additions & 0 deletions page_object/what_is_po/about code style/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<h2>Немного о Code Style</h2>

<p>Среди тех, кто регулярно пишет код,
существует определенное соглашение о &quot;стиле кода&quot;.
Стиль кода &mdash;&nbsp;это всё то, что не относится к его функциональности:
форматирование, имена переменных, функций, констант и так далее.
Python прекрасен тем, что&nbsp;его очень легко читать,
но даже такой простой для понимания язык в своём коде можно превратить
в нечитаемую кашу. Нечитаемая каша опасна тем, что вы не разберетесь
в своем коде уже через пару недель, а другой человек не разберется никогда.
Хорошо написанный код экономит время при починке тестов,
при внедрении нового человека в команду, да и при написании нового кода тоже.
В общем, это очень важная тема, и следует всегда помнить о читабельности кода.</p>

<p>Мы совсем немного затронули эту тему в предыдущих модулях, а теперь, раз уж мы потихоньку идём в сторону большей абстракции, настало время поговорить об этом чуть более подробно.</p>

<h3>&nbsp;Отступы</h3>

<p>Отступы являются частью синтаксиса в Python и означают вложенность блока, будь то тело&nbsp;функции условного выражения, цикла, и так далее. Самое важное для нас в будущих шагах, что все функции внутри класса так же должны быть отделены отступом:</p>

<pre>
<code>@pytest.mark.regression
# test out of scope of a class
def test_student_can_see_lesson_name_in_lesson_in_course_after_joining(self, driver):
# lines inside the scope of the test method with indent
page = CoursePromoPage(url=self.course.url, driver=driver)
page.open()


class TestLessonNameInCourseForTeacher():
@pytest.mark.regression
# test inside the class
def test_teacher_can_see_lesson_name_in_lesson_in_course(self, driver):
page = LessonPlayerPage(url=self.lesson_url, driver=driver)
page.open()
try:
# indent for any new scope
dangerous_function()
except:
close_something()

</code></pre>
3 changes: 3 additions & 0 deletions page_object/what_is_po/code style in tests/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if __name__ == "__main__":
# Write your solution here
pass
7 changes: 7 additions & 0 deletions page_object/what_is_po/code style in tests/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: theory
custom_name: 'code style in tests '
files:
- name: main.py
visible: true
- name: __init__.py
visible: false
27 changes: 27 additions & 0 deletions page_object/what_is_po/code style in tests/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<h2>Code Style в автотестах</h2>

<p>Здесь мы попытались собрать важные принципы написания автотестов: </p>

<ul>
<li>Стремитесь к максимальной линейности кода тестов: избегайте ветвления и циклов в тест-кейсах. Если хочется добавить в тесте if, значит, нужно разбить этот тест на два теста или подготовить тестовое окружение так, чтобы не было необходимости использовать ветвление.</li>
<li>Избегайте зависимых тестов, которые нужно запускать строго в определенном порядке.
При росте количества автотестов вы захотите запускать их в несколько потоков параллельно,
что будет невозможно при наличии зависимых тестов.
А еще зависимые тесты очень не надежны.</li>
<li>Стремитесь к тому, чтобы тест не полагался на контент, а готовил данные самостоятельно (и удалял после завершения). Используйте чистые браузеры и новых пользователей для лучшей воспроизводимости.</li>
<li>Абсолютная линейность проверок. Когда вы пишете assert-утверждения в функциях, не следует использовать ветвления и циклы. Логика проверок должна быть линейна, иначе разбор багов и починка автотестов будут стоить очень дорого.</li>
<li>Именуйте проверки в одинаковом стиле, чтобы по первому взгляду можно было понять, что это именно проверка. Например, можно именовать функции по шаблону should_be_smth:
<pre><code>def should_be_reply_comment()</code></pre>
</li>
<li>Тесты именуются в одинаковом стиле. Имена тестов должны хорошо отражать различия в похожих сценариях. Можно использовать те же подходы, что и при добавлении имен к тест-кейсам в тестовой документации. Например, <code>test_guest_can_see_teach_button()</code> — обратите внимание на явное указание на роль пользователя.</li>
<li>Одинаковые тесты, которые отличаются только каким-то контентом (например, языком интерфейса), следует не копировать, а параметризовать.</li>
<li>Пишите максимально атомарные и неделимые тесты. Не нужно писать один мега-тест, который проверяет вообще всё, напишите лучше десяток маленьких — проще будет локализовать проблему, когда она возникнет.</li>
</ul>

<p>Если у вас нет большого опыта в написании кода, в статьях по ссылкам вы можете найти дополнительные рекомендации по оформлению кода.</p>

<p>Английский язык:</p>

<p><a href="https://docs.python-guide.org/writing/style/" rel="noopener noreferrer nofollow">https://docs.python-guide.org/writing/style/</a></p>

<p><a href="https://www.python.org/dev/peps/pep-0008/" rel="noopener noreferrer nofollow">https://www.python.org/dev/peps/pep-0008/</a></p>
Empty file.
3 changes: 3 additions & 0 deletions page_object/what_is_po/code style/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if __name__ == "__main__":
# Write your solution here
pass
7 changes: 7 additions & 0 deletions page_object/what_is_po/code style/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: theory
custom_name: "code style: basic principles"
files:
- name: main.py
visible: true
- name: __init__.py
visible: false
32 changes: 32 additions & 0 deletions page_object/what_is_po/code style/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<h2>Code Style: базовые принципы </h2>

<h3>Имена переменных и функций</h3>

<p>Одним из самых важных аспектов читаемого кода является именование: будь то объявление переменных, описание функций, названия классов и так далее. Очень важно, чтобы все имена, которые вы присваивали сущностям, были осмысленными и отражали реальную суть этого объекта. Избегайте однобуквенных и бессмысленных названий типа var1, x, y, my_function, class2 и так далее. Идеальный код — самодокументируемый, к которому не нужны дополнительные пояснения. Если вы чувствуете, что вам хочется написать поясняющий комментарий, это повод переписать код так, чтобы комментарий не понадобился.</p>

<p>Обычно внутри каждой компании есть дополнительные внутренние соглашения о том, как именовать переменные, но общие правила в индустрии примерно одинаковые.</p>

<p>Функции пишутся через_нижнее_подчеркивание:</p>

<p><code>def test_guest_can_see_lesson_name_in_lesson_without_course(self, driver):</code></p>

<p>Классы пишут с помощью CamelCase:</p>

<p><code>class TestLessonNameWithoutCourseForGuest():</code></p>

<p>Константы пишут в стиле UPPERCASE:</p>

<p><code>MAIN_PAGE = "/catalog"</code></p>

<h3>Максимальная простота кода</h3>

<p>Здесь нам на помощь приходят известные принципы написания кода <a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself" rel="noopener noreferrer nofollow">DRY</a> (Don't repeat yourself) и <a href="https://en.wikipedia.org/wiki/KISS_principle" rel="noopener noreferrer nofollow">KISS</a> (Keep it simple, stupid). </p>

<ul>
<li>Пишите максимально простой код везде, где это возможно.</li>
<li>Не используйте переусложненных конструкций без большой необходимости (поменьше лямбда-выражений, map и разной другой магии). Если кусок кода можно заменить конструкцией более простой для понимания — замените.</li>
<li>Пишите максимально линейный код, где это возможно, это проще для восприятия.</li>
<li>Избегайте большой вложенности блоков кода, такие конструкции тяжело читать.</li>
<li>Если можно вынести повторяющуюся логику куда-то, выносите, не повторяйтесь.</li>
<li>По возможности пишите явный код вместо неявного. Чем меньше магии "под капотом", тем лучше.</li>
</ul>
Empty file.
28 changes: 28 additions & 0 deletions page_object/what_is_po/first_page_object/steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import math

from selenium.webdriver.support.wait import WebDriverWait


def solve_quiz(browser):
random_value = browser.find_element(By.ID, "input_value").text
answer = (math.log(abs((12 * math.sin(float(random_value))))))
text_field = browser.find_element(By.ID, "answer")
text_field.send_keys(str(answer))
browser.find_element(By.ID, "solve").click()


def wait_for_price(browser, price):
price_text = WebDriverWait(browser, 15).until(
EC.text_to_be_present_in_element((By.ID, "price"), "$100")
)


def should_be_math_text(browser):
assert browser.find_element(By.ID, "simple_text").text == "Math is real magic!"


def book(browser):
button = browser.find_element(By.ID, "book")
button.click()
21 changes: 21 additions & 0 deletions page_object/what_is_po/first_page_object/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type: edu
custom_name: "task: writing abstract methods"
files:
- name: task.py
visible: true
placeholders:
- offset: 127
length: 114
placeholder_text: '# TODO'
- name: tests/test_task.py
visible: false
- name: __init__.py
visible: false
- name: tests/__init__.py
visible: false
- name: steps.py
visible: true
placeholders:
- offset: 681
length: 84
placeholder_text: '# TODO'
13 changes: 13 additions & 0 deletions page_object/what_is_po/first_page_object/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h2>Task: writing abstract methods </h2>


Now let's rewrite our script from [waiting task](course://selenium_methods/waits_expected_conditions/task_waiting_for_text)
in pytest style and using abstract methods to make test more human-readable.
Firstly, implement methods in step.py, using your code from [waiting task](course://selenium_methods/waits_expected_conditions/task_waiting_for_text)
Then, implement test in task.py using these methods.

<li>Open the page <a href="http://suninjuly.github.io/explicit_wait2.html" rel="noopener noreferrer nofollow">http://suninjuly.github.io/explicit_wait2.html</a>.</li>
<li>Wait till the cabin rent goes down to $100 (set the wait no lower than 12 seconds).</li>
<li>Click the "Book" button.</li>
<li>Assert an element with text "Math is a real magic!" element is presented</li>
<li>Solve a familiar arithmetical problem</li>
14 changes: 14 additions & 0 deletions page_object/what_is_po/first_page_object/task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

from steps import *

link = "https://suninjuly.github.io/explicit_wait2.html"


def wait_test(browser):
browser.get(link)
wait_for_price(browser, "100$")
book(browser)
solve_quiz(browser)
browser.switch_to.alert.accept


Empty file.
64 changes: 64 additions & 0 deletions page_object/what_is_po/first_page_object/tests/test_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import unittest
from selenium import webdriver
import time
import math

from page_object.what_is_po.first_page_object.task import *
from page_object.what_is_po.first_page_object.steps import *


def check(reply):
problem_number = 2408
minutes_to_delay= 5

ts_now = int(time.time())
ts_past = ts_now - 60*minutes_to_delay

hashcode_now = math.log(ts_now*problem_number)
hashcode_past = math.log(ts_past*problem_number)
try:
replys = float(reply)
if (replys < hashcode_now and replys > hashcode_past):
return True
elif replys <= hashcode_past:
return 0, "Срок действия кода истек, попробуйте еще раз"
else:
return 0, "Неверный код"

except ValueError:
return 0, "Неверный формат строки, должно быть число"


class TestCase(unittest.TestCase):
def test_script(self):
browser = webdriver.Chrome()
try:
browser.implicitly_wait(10)
wait_test(browser)
finally:
browser.quit()

def test_wait(self):
browser = webdriver.Chrome()
try:
browser.implicitly_wait(10)
browser.get(link)
wait_for_price(browser, "100$")
book(browser)
should_be_math_text(browser)
solve_quiz(browser)
reply = float(browser.switch_to.alert.text.split(": ")[1])
self.assertTrue(check(reply))
finally:
browser.quit()

def test_wait_negative(self):
browser = webdriver.Chrome()
try:
browser.implicitly_wait(10)
browser.get("https://suninjuly.github.io/explicit_wait3.html")
wait_for_price(browser, "100$")
book(browser)
self.assertRaises(AssertionError, should_be_math_text, browser)
finally:
browser.quit()
8 changes: 8 additions & 0 deletions page_object/what_is_po/lesson-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
custom_name: what is page object model?
content:
- about code style
- code style
- code style in tests
- task4
- first_page_object
- why page object
Empty file.
17 changes: 17 additions & 0 deletions page_object/what_is_po/task4/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
link = "http://selenium1py.pythonanywhere.com/"


def test_guest_can_go_to_login_page(browser):
browser.get(link)
login_link = browser.find_element(By.CSS_SELECTOR, "#login_link")
login_link.click()


def go_to_login_page(browser):
login_link = browser.find_element(By.CSS_SELECTOR, "#login_link")
login_link.click()

def test_guest_can_go_to_login_page(browser):
browser.get(link)
go_to_login_page(browser)

7 changes: 7 additions & 0 deletions page_object/what_is_po/task4/task-info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: theory
custom_name: "first step towards page object"
files:
- name: main.py
visible: true
- name: __init__.py
visible: false
Loading