AG

Angelo Gladding
lahacker.net

dlv5vbq7lzlthol5 4b942a3185b37d00

angelo@lahacker.net

South Pasadena, California, United States currently feels like 54.62°F

Home CodecanopyFiles

tests.py

5 tests ran in 74 seconds. All tests are passing.

Download raw file

import pathlib
import time

import pytest
import web
from web import By, EC

import canopy


keysize = 1024
forest = "cnpy.gdn"
characters = {"Alice": {}, "Bob": {}, "Carol": {}}
tests_dir = pathlib.Path(__file__).parent / "tests"
test_data_dir = pathlib.Path(__file__).parent / "test_data"
scenes = []


def setup_module(module):
    for name, details in characters.items():
        hostname = f"test{name.lower()}.{forest}"
        canopy.delete_host(hostname)
        canopy.setup_host(name.capitalize(), f"{name.lower()}pass",
                          keysize, hostname)
        browser = web.browser()
        browser.width = 1100
        browser.name = name
        browser.hostname = hostname
        characters[name]["browser"] = browser
    for png in tests_dir.glob("*.png"):
        png.unlink()


def teardown_module(module):
    for name, details in characters.items():
        details["browser"].quit()

    toc = ""
    story = ""
    for index, (who, caption, slug, description) in enumerate(scenes):
        toc += f"<li><a href=#{slug}>{description}</a></li>"
        story += (f"<section id={slug}>"
                  f"<h2>{caption}</h2>"
                  f"<p><small>{', '.join(who)}</small>{description}</p>"
                  f"<div class=storyboard>")
        for character in sorted(characters.keys()):
            if character in who:
                url = f"results/{index:03}_{character}_{slug}.png"
                story += f"<a href={url}><img src={url}></a>"
            else:
                story += "<div class=filler></div>"
        story += (f"</div>"
                  f"</section>")
    with (tests_dir / "results.html").open("w") as fp:
        fp.write(f"""$var title: A walk through the Canopy

                     <style>
                     /* section {{ margin: 6em 0; }} */
                     .filler {{ height: 1em; width: 1em; }}
                     .storyboard {{ column-count: 3; }}
                     .storyboard img {{ border: 0; /*.1em solid #586e75;*/ }}
                     a {{
                         color: #268bd2; }}
                     a:link {{
                         color: #268bd2; }}
                     a:visited {{
                         color: #6c71c4; }}
                     a:active {{
                         color: #dc322f; }}
                     </style>

                     <nav><ol>
                     {toc}
                     </ol></nav>
                     <article>
                     {story}
                     </article>""")


def shot(caption, description, *who):
    slug = caption.replace(' ', '_').lower()
    for character in who:
        path = tests_dir / f"{len(scenes):03}_{character}_{slug}"
        characters[character]["browser"].shot(path)
    scenes.append((who, caption, slug, description))


@pytest.fixture
def alice():
    return characters["Alice"]["browser"]


@pytest.fixture
def bob():
    return characters["Bob"]["browser"]


@pytest.fixture
def carol():
    return characters["Carol"]["browser"]


def test_setup():
    """compensate for setup time showing in first result"""
    assert True


def test_home(alice, bob, carol):
    """assert alice, bob and carol's identity details have been created"""
    for character in (alice, bob, carol):
        # via Python
        canopy.contextualize(character.hostname)
        resource = canopy.content.read.get_resource("identity", "me")
        assert resource["name"] == character.name
        # via Web
        character.go(character.hostname)
        character.wait(EC.url_to_be(f"https://{character.hostname}/"))
        assert character.name in character.title
    # TODO leverage function name, positional arguments and docstring for below
    shot("At Home",
         "Alice, Bob and Carol spawn their trees with respective "
         "names, passphrases and domains.",
         "Alice", "Bob", "Carol")


def test_identification(alice, bob, carol):
    """"""
    # TODO submit form over AJAX and use loading invisibility
    passphrase_inputs = []
    for character in (alice, bob, carol):
        character.go(character.hostname, "identification")
        character.wait(EC.url_to_be(f"https://{character.hostname}"
                                    f"/authentication"),
                       EC.presence_of_element_located((By.ID, "authenticate")))
        # assert "" in alice.title
        passphrase_input = character.cssel("input[name=passphrase]")
        passphrase_input.send_keys(f"{character.name.lower()}pass")
        passphrase_inputs.append(passphrase_input)
    shot("Passphrase Entered",
         "Alice signs in with her passphrase.",
         "Alice", "Bob", "Carol")
    for passphrase_input in passphrase_inputs:
        passphrase_input.submit()
    for character in (alice, bob, carol):
        character.wait(EC.presence_of_element_located((By.ID, "signout")))
        # assert "" in alice.title
    shot("Signed In",
         "Alice is signed in and sent back to her home page.",
         "Alice", "Bob", "Carol")


def test_create_note(alice, bob):
    """"""
    alice.find_element_by_link_text("Notes").click()
    alice.wait(EC.url_to_be(f"https://{alice.hostname}/notes"),
               EC.invisibility_of_element_located((By.ID, "loading")))
    note_input = alice.cssel("textarea[name=body]")
    note_input.send_keys("Hello world!")
    shot("Notes Page",
         "Alice goes to her notes page.",
         "Alice")
    alice.cssel("button[value=publish]").click()
    time.sleep(3)  # trigger "loading" UI on websocket message to wait here
    shot("Note Posted",
         "Alice's note is posted to her notes page.",
         "Alice")
    alice.find_element_by_link_text("a few seconds ago").click()
    time.sleep(3)
    # TODO alice.wait(EC.visibility_of_element_located((By.ID, "loading")),
    # TODO            EC.invisibility_of_element_located((By.ID, "loading")))
    bob.go(alice.current_url)
    time.sleep(3)
    shot("Note Page",
         "Alice's note's page.",
         "Alice", "Bob")
    bob.cssel("indie-action[do=reply] a").click()
    time.sleep(1)
    url_input = bob.cssel("form#action-handler input[name=url]")
    url_input.send_keys("https://testbob.cnpy.gdn")
    shot("Reply Web Action",
         "Bob clicks reply icon and is presented with a web action prompt.",
         "Bob")
    url_input.submit()
    time.sleep(3)
    shot("Note Reply UI",
         "Bob's note reply type selection.",
         "Bob")
    bob.cssel("div#body article button[value=note]").click()
    time.sleep(3)
    note_input = bob.cssel("textarea#body")
    note_input.send_keys("Hello Alice!")
    shot("Bob Writes Reply",
         "Bob's reply to a note with a note UI.",
         "Bob")
    bob.cssel("button[value=publish]").click()
    time.sleep(3)
    alice.go(bob.current_url)
    shot("Bob Reply Note",
         "Bob's reply note on it's own page.",
         "Alice", "Bob")


# def test_create_note():
#     """assert a note has been created"""
#     canopy.contextualize(f"testalice.{forest}")
#     body = "Hello world!"
#     resource_id = canopy.content.write.quick_draft("note", {"body": body},
#                                                    publish=True)
#     resource = canopy.content.read.get_resource_by_id(resource_id)
#     assert resource["body"] == body


# def test_upload_photo():
#     """"""
#     with (data_dir / "alice.jpg").open("rb") as fp:
#         data = {"image": fp.read()}
#     resource_id = canopy.content.write.quick_draft("image", data,
#                                                    publish=True)
#     resource = canopy.content.read.get_resource_by_id(resource_id)
#     assert "images" in resource
#     # TODO find and assign face to identity
#     # TODO update photo in profile


# def mock():
#    def note(identity, body, tags, license, datetime):
#        n = dict(body=body, tags=tags.split(","), license=license)
#        published = pendulum.strptime(datetime, "%Y-%m-%d %H:%M:%S")
#        web.tx.db = canopy.get_db("testing.{}.lahacker.net".format(identity))
#        canopy.__web__.feed.create_note(n, published)
#    note("alice", "Happy new year! Wish everyone a healthy and "
#         "fulfilling future", "holiday", "cc-zero", "2017-01-01 00:00:00")
#    note("alice", "Happy vernal equinox! Time to prep your plots!",
#         "seasons", "cc-by", "2017-03-20 10:28:00")
#    note("bob", "Washed the dog!", "seasons", "cc-by", "2017-04-03 02:19:12")


# ---------------------------------------------------------------------


# def test_photo_upload(alice):
#     alice.go(f"alice.{forest}", "images")
#     alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("image index",
#          """Alice goes to her images index and clicks to create
#             a new image post.""",
#          "alice")
#     create_form = alice.cssel("#quick_editor button[value=draft]")
#     create_form.click()
#     time.sleep(1)
#     alice.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     # alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     alice.execute_script("$('#fileinput').style.display = 'block';")
#     photo_input = alice.cssel("#fileinput")
#     photo_input.send_keys(str((pathlib.Path(__file__).parent /
#                                "data/alice.jpg").resolve()))
#     alice.execute_script("$('#fileinput').style.display = 'none';")
#     shot("image editor",
#          """Alice uploads a photo of herself.""",
#          "alice")
#     action = alice.action()
#     action.move_to_element(alice.cssel("div.images > div > div"))
#     # starts at center of image
#     action.move_by_offset(40, -130)
#     action.click()
#     # action.click_and_hold()
#     # action.move_by_offset(200, 200)
#     # action.release()
#     action.perform()
#     shot("select face",
#          """Alice selects her face in the photo.""",
#          "alice")
#     face = alice.cssel("div.images > div:first-child > div + p > span")
#     face.click()
#     shot("select face identity",
#          """Alice selects herself as the face's identity.""",
#          "alice")
#     alice.cssel("button[name=action][value=publish]").click()
#     alice.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     # alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("profile photo uploaded",
#          """Alice has uploaded her profile photo.""",
#          "alice")
#
#
# def test_change_profile_photo(alice):
#     alice.go(f"alice.{forest}", "contacts/me")
#     alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("personal profile data",
#          """Alice goes to her profile and clicks to edit.""",
#          "alice")
#     alice.cssel("#edit").click()
#     alice.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     alice.cssel("input[name=photo]").click()
#     shot("editing personal profile",
#          """Alice updates her profile by selecting her face and
#             clicks to publish.""",
#          "alice")
#     alice.cssel("button[value=publish]").click()
#     alice.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     # alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("photo added to profile",
#          """Alice has added her photo to her profile.""",
#          "alice")
#
#
# def test_bob_home_and_signin(bob):
#     """"""
#     bob.go(f"bob.{forest}")
#     bob.wait(EC.url_to_be(f"https://bob.{forest}/"))
#     bob.cssel("#stylesheet_switcher").click()
#     assert "Bob" in bob.title
#
#     bob.go(f"bob.{forest}", "identification")
#     bob.wait(EC.url_to_be(f"https://bob.{forest}/authentication"),
#              EC.presence_of_element_located((By.ID, "authenticate")))
#     passphrase_input = bob.cssel("input[name=passphrase]")
#     passphrase_input.send_keys("bob")
#     passphrase_input.submit()
#     # TODO send form submissions over AJAX w/ updated interface
#     #      & use loading invisibility
#     time.sleep(1)
#     # bob.wait(EC.invisibility_of_element_located((By.ID, "bottom")))
#     bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("bob at home",
#          """Bob spawns his tree with desired name, passphrase and domain.
#             He toggles the contrast and signs in.""",
#          "bob")
#     # assert "" in bob.title
#
#
# def test_bob_follow_alice(bob):
#     bob.go(f"alice.{forest}")
#     bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("bob at alice tree",
#          """Bob travels to Alice's tree and clicks to follow.""",
#          "bob")
#     # # assert "" in bob.title
#     bob.go(f"bob.{forest}", "follows")
#     bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     time.sleep(1)
#     follow_input = bob.cssel("input[name=follow-of]")
#     follow_input.send_keys("https://alice.example.cnpy.gdn/")
#     follow_input.submit()
#     bob.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     # bob.wait(EC.invisibility_of_element_located((By.ID, "bottom")))
#     # time.sleep(1)
#     # bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("bob follows alice",
#          """Bob is following Alice.""",
#          "bob")
#     # assert "" in bob.title
#     bob.go(f"bob.{forest}", "reader/feeds/alice.example.cnpy.gdn")
#     bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("alice in bobs reader",
#          """Bob pulls up Alice's feed in his reader.""",
#          "bob")
#
#
# def test_alice_quick_note_post(alice, bob):
#     alice.go(f"alice.{forest}", "notes")
#     alice.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     notebody_input = alice.cssel("#quick_editor textarea[name=body]")
#     notebody_input.send_keys("Hello world!")
#     shot("quick note post",
#          """Alice goes to her notes index and clicks to create
#             a new note post.""",
#          "alice")
#     notebody_input.submit()
#     alice.wait(EC.invisibility_of_element_located((By.ID, "loading")))
#     bob.refresh()
#     bob.wait(EC.presence_of_element_located((By.ID, "bottom")))
#     shot("note posted",
#          """Alice has posted a note and Bob sees it in his reader.""",
#          "alice", "bob")
#
#
# # # def test_signout(alice):
# # #     alice.cssel("#signout").submit()
# # #     alice.wait(EC.invisibility_of_element_located((By.ID, "bottom")),
# # #                  EC.presence_of_element_located((By.ID, "bottom")))
# # #     alice.cssel("a[rel=home]").click()
# # #     alice.wait(EC.invisibility_of_element_located((By.ID, "bottom")),
# # #                  EC.presence_of_element_located((By.ID, "bottom")))
# # #     alice.shot("alice_14_signed_out.png",
# # #                  """Alice has signed out and is viewing her public
# # #                     homepage.""")
# #
# #
# # # alice.go("web+action://sign-in?url=https://alice.example.cnpy.gdn/"
# # #      "identification&return_to=https://alice.example.cnpy.gdn")
# # #
# # # signin_button = alice.cssel("indie-action[do=sign-in] a")
# # # signin_button.click()
# # # alice.wait().until(EC.presence_of_element_located((By.LINK_TEXT,
# # #                                                  "sign in here")))
# # #
# # # alice.shot("alice_02_unhandled_sign_in.png")