def test_can_start_a_list_for_one_user(new_browser):
    # Edith has heard about a cool new online to-do app. She goes
    # to check out its homepage
    browser = new_browser()

    # She notices the page title and header mention to-do lists
    assert "To-Do" in browser.title
    header_text = browser.find_element_by_tag_name("h1").text
    assert "To-Do" in header_text

    # She is invited to enter a to-do item straight away
    input_box = get_item_input_box(browser)
    assert input_box.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)
    input_box.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
    input_box.send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: Buy peacock feathers")

    # 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)
    input_box = get_item_input_box(browser)
    input_box.send_keys("Use peacock feathers to make a fly")
    input_box.send_keys(Keys.ENTER)

    # The page updates again, and now shows both items on her list
    wait_for_row_in_list_table(browser, "1: Buy peacock feathers")
    wait_for_row_in_list_table(browser,
                               "2: Use peacock feathers to make a fly")
def test_error_messages_are_cleared_on_input(new_browser):
    browser = new_browser()

    # Edith starts a new list and causes a validation error
    get_item_input_box(browser).send_keys("Banter too thick")
    get_item_input_box(browser).send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: Banter too thick")
    get_item_input_box(browser).send_keys("Banter too thick")
    get_item_input_box(browser).send_keys(Keys.ENTER)

    assert wait_for(lambda: get_error_element(browser).is_displayed())

    # She starts typing in the input box to clear the error
    get_item_input_box(browser).send_keys("a")

    # She is pleased to see the error message disappear
    assert wait_for(lambda: get_error_element(browser).is_displayed()) is False
def test_layout_and_styling(new_browser):
    browser = new_browser()
    browser.set_window_size(1024, 768)

    # She notices the input box is nicely centered
    inputbox = get_item_input_box(browser)
    assert (pytest.approx(512, abs=10) == inputbox.location["x"] +
            inputbox.size["width"] / 2)

    # She starts a new list and sees the input is nicely
    # centered there too
    inputbox.send_keys("testing")
    inputbox.send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: testing")
    inputbox = get_item_input_box(browser)
    assert (pytest.approx(512, abs=10) == inputbox.location["x"] +
            inputbox.size["width"] / 2)
def test_cannot_add_duplicate_items(new_browser):
    # Edith goes to the homepage and starts a new list
    browser = new_browser()
    get_item_input_box(browser).send_keys("Buy wellies")
    get_item_input_box(browser).send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: Buy wellies")

    # She accidently tries to add a duplicate item
    get_item_input_box(browser).send_keys("Buy wellies")
    get_item_input_box(browser).send_keys(Keys.ENTER)

    # She sees a helpful error message
    assert (wait_for(lambda: get_error_element(browser).text) ==
            "You've already got this in your list")
def test_multiple_users_can_start_lists_at_different_urls(new_browser):
    # Edith starts a new to-do list
    edith_browser = new_browser()
    inputbox = get_item_input_box(edith_browser)
    inputbox.send_keys("Buy peacock feathers")
    inputbox.send_keys(Keys.ENTER)
    wait_for_row_in_list_table(edith_browser, "1: Buy peacock feathers")

    # She notices that her list has a unique URL
    edith_list_url = edith_browser.current_url
    assert re.search(r"/lists/.+", edith_list_url)

    # Now a new user, Francis, comes along to the site
    edith_browser.quit()
    francis_browser = new_browser()

    # There is no sign of Edith's list
    page_text = francis_browser.find_element_by_tag_name("body").text
    assert "Buy peacock feathers" not in page_text
    assert "make a fly" not in page_text

    # Francis starts a new list
    inputbox = get_item_input_box(francis_browser)
    inputbox.send_keys("Buy milk")
    inputbox.send_keys(Keys.ENTER)
    wait_for_row_in_list_table(francis_browser, "1: Buy milk")

    # Francis gets his own url
    francis_list_url = francis_browser.current_url
    assert re.search(r"/lists/.+", edith_list_url)
    assert edith_list_url != francis_list_url

    # There is still no sign of Edith's list
    page_text = francis_browser.find_element_by_tag_name("body").text
    assert "Buy peacock feathers" not in page_text
    assert "make a fly" not in page_text
def test_cannot_add_empty_list_items(new_browser):
    # Edith goes to the home page and accidently tries to submit and empty list
    # item. She hits enter on the empty input box
    browser = new_browser()
    get_item_input_box(browser).send_keys(Keys.ENTER)

    # Browser intercepts the request, and does not load the list page
    wait_for(lambda: browser.find_element_by_css_selector("#id_text:invalid"))

    # She starts writing text for the new item and the error disappears
    get_item_input_box(browser).send_keys("Buy milk")
    wait_for(lambda: browser.find_element_by_css_selector("#id_text:valid"))

    # And she can submit successfully
    get_item_input_box(browser).send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: Buy milk")

    # Perversely, she submits a second blank list item
    get_item_input_box(browser).send_keys(Keys.ENTER)

    # Again, the browser will not comply
    wait_for_row_in_list_table(browser, "1: Buy milk")
    wait_for(lambda: browser.find_element_by_css_selector("#id_text:invalid"))

    # She can correct it by filling some text in
    get_item_input_box(browser).send_keys("Make tea")
    wait_for(lambda: browser.find_element_by_css_selector("#id_text:valid"))
    get_item_input_box(browser).send_keys(Keys.ENTER)
    wait_for_row_in_list_table(browser, "1: Buy milk")
    wait_for_row_in_list_table(browser, "2: Make tea")