{"action":"created","comment":{"url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/comments/84253872","pull_request_review_id":5041618,"id":84253872,"diff_hunk":"@@ -0,0 +1,496 @@\n+# -*- coding: utf-8 -*-\n+\n+\"\"\"\n+Different utilities to be used in tests\n+\"\"\"\n+import re\n+import time\n+import functools\n+import datetime\n+import imaplib\n+import email\n+\n+import requests\n+from requests.auth import HTTPBasicAuth\n+from edx_rest_api_client.client import EdxRestApiClient\n+from opaque_keys.edx.keys import AssetKey, CourseKey\n+\n+from regression.pages.whitelabel.const import (\n+    ACCESS_TOKEN,\n+    AUTH_PASSWORD,\n+    AUTH_USERNAME,\n+    DEFAULT_GMAIL_USER,\n+    DEFAULT_TIMEOUT,\n+    ECOMMERCE_API_URL,\n+    EMAIL_SENDER_ACCOUNT,\n+    GMAIL_PASSWORD,\n+    INITIAL_WAIT_TIME,\n+    ORG,\n+    TIME_OUT_LIMIT,\n+    WAIT_TIME\n+)\n+\n+\n+class MailException(Exception):\n+    \"\"\"\n+    Exceptions for Mail failures\n+    \"\"\"\n+    pass\n+\n+\n+class ApiException(Exception):\n+    \"\"\"\n+    Exceptions for API failures\n+    \"\"\"\n+    pass\n+\n+\n+class MailClient(object):\n+    \"\"\"\n+    Connect to Gmail clinet using imap and read mails from Inbox\n+    \"\"\"\n+\n+    def __init__(self):\n+        self.mail = imaplib.IMAP4_SSL('imap.gmail.com')\n+\n+    def login_to_email_account(self):\n+        \"\"\"\n+        Login to gmail account\n+        \"\"\"\n+        self.mail.login(DEFAULT_GMAIL_USER, GMAIL_PASSWORD)\n+\n+    def open_inbox(self):\n+        \"\"\"\n+        Open inbox to get the list of emails\n+        \"\"\"\n+        self.mail.list()\n+        # Out: list of \"folders\" aka labels in gmail.\n+        self.mail.select(\"inbox\")  # connect to inbox.\n+\n+    def get_latest_email_uid(self, current_email_user, mail_topic):\n+        \"\"\"\n+        This function will check the availability of target email at the\n+        intervals of 5 seconds and if the email is found it's uuid is returned.\n+        If the email is not found after predefined period of time seconds,\n+        this function will raise an error\n+        Args:\n+            current_email_user:\n+            mail_topic:\n+        Returns:\n+            email_uuid:\n+        \"\"\"\n+        self.login_to_email_account()\n+        self.open_inbox()\n+        latest_email_uid = None\n+        t_end = time.time() + TIME_OUT_LIMIT\n+        # Run the loop for a pre defined time\n+        time.sleep(INITIAL_WAIT_TIME)\n+        while time.time() < t_end:\n+            try:\n+                # Check that target email is present in Inbox\n+                # The target mail has to satisfy following criteria\n+                # a) It has to be sent during the last 24 hours (this is used\n+                # mainly to speed up the search)\n+                # b) Mail From and Mail To are correct\n+                # c) The partial subject string is present in the mail subject\n+                result, data = self.mail.uid(\n+                    'search',\n+                    None,\n+                    '(SENTSINCE {date} HEADER FROM {mail_from} TO '\n+                    '{mail_to} SUBJECT {mail_subject})'.format(\n+                        date=yesterday_date(),\n+                        mail_from=EMAIL_SENDER_ACCOUNT[ORG],\n+                        mail_to=current_email_user,\n+                        mail_subject=mail_topic\n+                    )\n+                )\n+                if not result:\n+                    raise MailException\n+                # Get the uid of last email that satisfies the criteria\n+                latest_email_uid = data[0].split()[-1]\n+                break\n+            except MailException:\n+                time.sleep(WAIT_TIME)\n+        if latest_email_uid:\n+            return latest_email_uid\n+        else:\n+            raise MailException('No Email matching the search criteria')\n+\n+    def get_email_message(self, current_email_user, mail_topic):\n+        \"\"\"\n+        Get the text message from Email\n+        Args:\n+            current_email_user:\n+            mail_topic:\n+        Returns:\n+            email text:\n+        \"\"\"\n+        resulting_data = self.mail.uid(\n+            'fetch',\n+            self.get_latest_email_uid(current_email_user, mail_topic),\n+            '(RFC822)'\n+        )\n+        mail_data = resulting_data[1]\n+        raw_email = mail_data[0][1]\n+        email_message = email.message_from_string(raw_email)\n+        return self.get_first_text_block(email_message)\n+\n+    @staticmethod\n+    def get_first_text_block(email_message_instance):\n+        \"\"\"\n+        In case of multiple payloads return first text block\n+        Args:\n+            email_message_instance:\n+        \"\"\"\n+        maintype = email_message_instance.get_content_maintype()\n+        if maintype == 'multipart':\n+            for part in email_message_instance.get_payload():\n+                if part.get_content_maintype() == 'text':\n+                    return part.get_payload()\n+        elif maintype == 'text':\n+            return email_message_instance.get_payload()\n+\n+\n+def get_target_url_from_text(partial_url_string, text_chunk):\n+    \"\"\"\n+    Search and return the target url from text chunk, the url is searched\n+    on the basis of partial string embedded in url\n+    Args:\n+        partial_url_string:\n+        text_chunk:\n+    Returns:\n+        target url:\n+    \"\"\"\n+    pattern = r\"(?P<url>http[s]?://[^\\s]+(/{}/)[^\\s]+)\".format(\n+        partial_url_string\n+    )\n+    regex_result = re.search(pattern, text_chunk)\n+    if regex_result:\n+        target_url = regex_result.group(\"url\")\n+        return target_url.rstrip('.')\n+    else:\n+        return 'Target URL not found in the text'\n+\n+\n+class EcommerceApiClient(object):\n+    \"\"\"\n+    Ecommerce API client for various actions like creating, deleting\n+    downloading coupons\n+    \"\"\"\n+\n+    @property\n+    def ecommerce_api_client(self):\n+        \"\"\"\n+        E-Commerce API Client\n+        \"\"\"\n+        return EdxRestApiClient(\n+            ECOMMERCE_API_URL, oauth_access_token=ACCESS_TOKEN)\n+\n+    def create_coupon(self, payload):\n+        \"\"\"\n+        Create coupons using API\n+        Args:\n+            payload:\n+        \"\"\"\n+        response = self.ecommerce_api_client.coupons.post(data=payload)\n+        return response['coupon_id']\n+\n+    def get_coupon_report(self, coupon_id):\n+        \"\"\"\n+        Get coupon report using api\n+        Args:\n+            coupon_id:\n+        \"\"\"\n+        return self.ecommerce_api_client.products(coupon_id).get()\n+\n+    def delete_coupon(self, coupon_id):\n+        \"\"\"\n+        Delete the coupon created in the tests and all associated stock\n+        records and vouchers.\n+        Args:\n+            coupon_id:\n+        \"\"\"\n+        self.ecommerce_api_client.coupons(coupon_id).delete()\n+\n+    def get_coupon_codes(self, coupon_id):\n+        \"\"\"\n+        Get coupon codes from coupon report\n+        Args:\n+            coupon_id:\n+        \"\"\"\n+        coupon_codes = []\n+        items = (\n+            self.get_coupon_report(coupon_id)['attribute_values'][0]['value'])\n+        for item in items:\n+            coupon_codes.append(item['code'])\n+        return coupon_codes\n+\n+\n+def yesterday_date():\n+    \"\"\"\n+    Get and return yesterday's date in dd-mmm-yyyy format\n+    \"\"\"\n+    return (datetime.date.today() - datetime.timedelta(1)).strftime(\"%d-%b-%Y\")\n+\n+\n+def get_required_cookies(cookies_dict_list):\n+    \"\"\"\n+    Format required cookies\n+    Args:\n+        cookies_dict_list:\n+    \"\"\"\n+    response_dict = {}\n+    for cookie in cookies_dict_list:\n+        if cookie['name'] == 'ecommerce_csrftoken':\n+            response_dict.update({'ecommerce_csrftoken': cookie['value']})\n+        elif cookie['name'] == 'ecommerce_sessionid':\n+            response_dict.update({'ecommerce_sessionid': cookie['value']})\n+    required_cookies = '; '.join('{}={}'.format(\n+        key, val) for key, val in response_dict.items())\n+    return required_cookies\n+\n+\n+def get_coupon_request(target_url, cookie_str):\n+    \"\"\"\n+    Send a Get request and return the response if successful\n+    Args:\n+      target_url:\n+      cookie_str:\n+    \"\"\"\n+    kwargs = {}\n+    headers = {\n+        'Accept': 'text/html,application/xhtml+xml,'\n+                  'application/xml;q=0.9,image/webp,*/*;q=0.8',\n+        'Accept-Language': 'en-US,en;q=0.8',\n+        'Accept-Encoding': 'gzip, deflate, sdch, br',\n+        'Cookie': cookie_str\n+    }\n+    kwargs.update({\n+        'headers': headers,\n+        'auth': HTTPBasicAuth(AUTH_USERNAME, AUTH_PASSWORD),\n+    })\n+    response = requests.get(target_url, **kwargs)\n+    if response.ok:\n+        return response.content\n+    else:\n+        msg = \"Could not use restful API.  Status code: {0}\".format(\n+            response.status_code)\n+        raise ApiException(msg)\n+\n+\n+def get_enrollment_codes_from_email(coupon_string):\n+    \"\"\"\n+    Read enrollment codes and urls from email\n+    Ignore first four lines of file as these are just headers\n+    Args:\n+        coupon_string:\n+    Returns:\n+        coupon codes and urls:\n+    \"\"\"\n+    coupons = {}\n+    for i, row in enumerate(coupon_string.splitlines()):\n+        # Read the coupons starting from line 5\n+        if i > 3:\n+            if row:\n+                new_row = row.split(',')\n+                coupons.update({new_row[0]: new_row[1]})\n+    if coupons:\n+        return coupons\n+    else:\n+        return 'Coupons not found'\n+\n+\n+def skip_cleanup_if_test_passed():\n+    \"\"\"\n+    Skip cleanup when tests are passing\n+    \"\"\"\n+    def decorator(test_function):\n+        \"\"\"\n+        Decorator\n+        Args:\n+            test_function:\n+        \"\"\"\n+        @functools.wraps(test_function)\n+        def wrapper(self, *args, **kwargs):\n+            \"\"\"\n+            Wrapper\n+            Args:\n+                self:\n+                *args:\n+                **kwargs:\n+            \"\"\"\n+            test_function(self, *args, **kwargs)\n+            self.full_cleanup = False\n+        return wrapper\n+    return decorator\n+\n+\n+def fill_input_fields(page, selectors_and_values_dict):\n+    \"\"\"\n+    A helper function to fill multiple fields in a form\n+    Args:\n+        page:\n+        selectors_and_values_dict:\n+    \"\"\"\n+    for key, value in selectors_and_values_dict.iteritems():\n+        page.q(css=key).fill(value)\n+\n+\n+def select_value_from_drop_down(page, drop_down_name, value):\n+    \"\"\"\n+    A helper function to select value from drop down\n+    Args:\n+        page:\n+        drop_down_name:\n+        value:\n+    \"\"\"\n+    page.wait_for_element_visibility(\n+        'select[name={}]'.format(drop_down_name), 'Drop down is visible')\n+    page.q(\n+        css='select[name={}] option[value=\"{}\"]'.format(drop_down_name, value)\n+    ).click()\n+    page.wait_for(\n+        lambda: page.q(\n+            css='select[name={}] option[value=\"{}\"]'.\n+            format(drop_down_name, value)\n+        ).selected,\n+        \"Correct value is selected\",\n+        timeout=DEFAULT_TIMEOUT\n+    )\n+\n+\n+def click_checkbox(page, css_selector):\n+    \"\"\"\n+    A helper function to click check boxes\n+    Args:\n+       page:\n+       css_selector:\n+    \"\"\"\n+    # pylint: disable=unnecessary-lambda\n+    page.wait_for_element_visibility(css_selector, 'wait for target checkbox')\n+    page_elem = page.q(css=css_selector).results[0]\n+    if not page_elem.is_selected():\n+        page.browser.execute_script(\"arguments[0].click();\", page_elem)\n+        page.wait_for(\n+            lambda: page_elem.is_selected(),\n+            'Target checkbox is selected'\n+        )\n+\n+\n+def remove_spaces_from_list_elements(list_with_spaces):\n+    \"\"\"\n+    A helper function to remove spaces from all items in the list\n+    Args:\n+      list_with_spaces:\n+    \"\"\"\n+    return [x.replace(' ', '') for x in list_with_spaces]\n+\n+\n+def get_text_against_page_elements(page, css_selectors):\n+    \"\"\"\n+    A helper function to get text values for a list of web elements\n+    Args:\n+        page:\n+        css_selectors:\n+    Returns:\n+        list_of_text:\n+    \"\"\"\n+    list_of_text = []\n+    for css_selector in css_selectors:\n+        list_of_text.append(page.q(css=css_selector).text[0])\n+    return list_of_text\n+\n+\n+def extract_mmm_dd_yyyy_date_string_from_text(original_string):","path":"regression/pages/common/utils.py","position":404,"original_position":404,"commit_id":"3b4deb20c790ac199d2644eb6fd7258f2b930184","original_commit_id":"3b4deb20c790ac199d2644eb6fd7258f2b930184","user":{"login":"kashifch","id":7318240,"avatar_url":"https://avatars.githubusercontent.com/u/7318240?v=3","gravatar_id":"","url":"https://api.github.com/users/kashifch","html_url":"https://github.com/kashifch","followers_url":"https://api.github.com/users/kashifch/followers","following_url":"https://api.github.com/users/kashifch/following{/other_user}","gists_url":"https://api.github.com/users/kashifch/gists{/gist_id}","starred_url":"https://api.github.com/users/kashifch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kashifch/subscriptions","organizations_url":"https://api.github.com/users/kashifch/orgs","repos_url":"https://api.github.com/users/kashifch/repos","events_url":"https://api.github.com/users/kashifch/events{/privacy}","received_events_url":"https://api.github.com/users/kashifch/received_events","type":"User","site_admin":false},"body":"I am just extracting the date from a text chunk, I guess I should rename params and name to make it clear","created_at":"2016-10-20T10:25:28Z","updated_at":"2016-10-20T10:25:28Z","html_url":"https://github.com/edx/edx-e2e-tests/pull/88#discussion_r84253872","pull_request_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88","_links":{"self":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/comments/84253872"},"html":{"href":"https://github.com/edx/edx-e2e-tests/pull/88#discussion_r84253872"},"pull_request":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88"}}},"pull_request":{"url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88","id":89297728,"html_url":"https://github.com/edx/edx-e2e-tests/pull/88","diff_url":"https://github.com/edx/edx-e2e-tests/pull/88.diff","patch_url":"https://github.com/edx/edx-e2e-tests/pull/88.patch","issue_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/88","number":88,"state":"open","locked":false,"title":"Utils","user":{"login":"kashifch","id":7318240,"avatar_url":"https://avatars.githubusercontent.com/u/7318240?v=3","gravatar_id":"","url":"https://api.github.com/users/kashifch","html_url":"https://github.com/kashifch","followers_url":"https://api.github.com/users/kashifch/followers","following_url":"https://api.github.com/users/kashifch/following{/other_user}","gists_url":"https://api.github.com/users/kashifch/gists{/gist_id}","starred_url":"https://api.github.com/users/kashifch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kashifch/subscriptions","organizations_url":"https://api.github.com/users/kashifch/orgs","repos_url":"https://api.github.com/users/kashifch/repos","events_url":"https://api.github.com/users/kashifch/events{/privacy}","received_events_url":"https://api.github.com/users/kashifch/received_events","type":"User","site_admin":false},"body":"@benpatterson \r\n\r\nI am breaking the PR in smaller chunks.\r\nHere is the first installments\r\nIt basically consists of Utils\r\nI have made following changes\r\nAdded unit tests to most of the methods\r\nBrought all regex functions from across tests  in Utils and added unit tests for these\r\nThe date conversion function is now generic\r\nI have removed the Email APIs I was using previously, now I am creating new users and reading emails using the python imap plus gmail aliases\r\nThe course ids and numbers are now extracted using opaque keys\r\n\r\nThings which are not changed\r\nI haven't yet changed the skip_clean_up, as I have commented earlier, I am looking into using the api for un-enrolling multiple users from course, if it works I will remove the function, otherwise we could look into an alternate.\r\n\r\nI am still clicking the checkboxes/option buttons using javascript as I experience flakiness when I use the selenium click, if that is unacceptable I can look into other options","created_at":"2016-10-13T22:55:26Z","updated_at":"2016-10-20T10:25:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"aff5d9c30180bf290615ea289b1525ce8cd51974","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88/commits","review_comments_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88/comments","review_comment_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/comments{/number}","comments_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/88/comments","statuses_url":"https://api.github.com/repos/edx/edx-e2e-tests/statuses/3b4deb20c790ac199d2644eb6fd7258f2b930184","head":{"label":"edx:kashif/utils","ref":"kashif/utils","sha":"3b4deb20c790ac199d2644eb6fd7258f2b930184","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":13808625,"name":"edx-e2e-tests","full_name":"edx/edx-e2e-tests","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-e2e-tests","description":"End-to-end tests for edx applications","fork":false,"url":"https://api.github.com/repos/edx/edx-e2e-tests","forks_url":"https://api.github.com/repos/edx/edx-e2e-tests/forks","keys_url":"https://api.github.com/repos/edx/edx-e2e-tests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-e2e-tests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-e2e-tests/teams","hooks_url":"https://api.github.com/repos/edx/edx-e2e-tests/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-e2e-tests/events","assignees_url":"https://api.github.com/repos/edx/edx-e2e-tests/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-e2e-tests/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-e2e-tests/tags","blobs_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-e2e-tests/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-e2e-tests/languages","stargazers_url":"https://api.github.com/repos/edx/edx-e2e-tests/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-e2e-tests/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-e2e-tests/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-e2e-tests/subscription","commits_url":"https://api.github.com/repos/edx/edx-e2e-tests/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-e2e-tests/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-e2e-tests/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-e2e-tests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-e2e-tests/merges","archive_url":"https://api.github.com/repos/edx/edx-e2e-tests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-e2e-tests/downloads","issues_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-e2e-tests/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-e2e-tests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-e2e-tests/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-e2e-tests/releases{/id}","deployments_url":"https://api.github.com/repos/edx/edx-e2e-tests/deployments","created_at":"2013-10-23T16:45:07Z","updated_at":"2016-10-13T06:49:19Z","pushed_at":"2016-10-20T08:22:50Z","git_url":"git://github.com/edx/edx-e2e-tests.git","ssh_url":"git@github.com:edx/edx-e2e-tests.git","clone_url":"https://github.com/edx/edx-e2e-tests.git","svn_url":"https://github.com/edx/edx-e2e-tests","homepage":null,"size":11205,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":6,"forks":8,"open_issues":6,"watchers":3,"default_branch":"master"}},"base":{"label":"edx:master","ref":"master","sha":"ebe31800877c7c5d32b8f59d2ea4786fcc1872a4","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":13808625,"name":"edx-e2e-tests","full_name":"edx/edx-e2e-tests","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-e2e-tests","description":"End-to-end tests for edx applications","fork":false,"url":"https://api.github.com/repos/edx/edx-e2e-tests","forks_url":"https://api.github.com/repos/edx/edx-e2e-tests/forks","keys_url":"https://api.github.com/repos/edx/edx-e2e-tests/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-e2e-tests/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-e2e-tests/teams","hooks_url":"https://api.github.com/repos/edx/edx-e2e-tests/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-e2e-tests/events","assignees_url":"https://api.github.com/repos/edx/edx-e2e-tests/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-e2e-tests/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-e2e-tests/tags","blobs_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-e2e-tests/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-e2e-tests/languages","stargazers_url":"https://api.github.com/repos/edx/edx-e2e-tests/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-e2e-tests/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-e2e-tests/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-e2e-tests/subscription","commits_url":"https://api.github.com/repos/edx/edx-e2e-tests/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-e2e-tests/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-e2e-tests/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-e2e-tests/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-e2e-tests/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-e2e-tests/merges","archive_url":"https://api.github.com/repos/edx/edx-e2e-tests/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-e2e-tests/downloads","issues_url":"https://api.github.com/repos/edx/edx-e2e-tests/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-e2e-tests/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-e2e-tests/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-e2e-tests/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-e2e-tests/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-e2e-tests/releases{/id}","deployments_url":"https://api.github.com/repos/edx/edx-e2e-tests/deployments","created_at":"2013-10-23T16:45:07Z","updated_at":"2016-10-13T06:49:19Z","pushed_at":"2016-10-20T08:22:50Z","git_url":"git://github.com/edx/edx-e2e-tests.git","ssh_url":"git@github.com:edx/edx-e2e-tests.git","clone_url":"https://github.com/edx/edx-e2e-tests.git","svn_url":"https://github.com/edx/edx-e2e-tests","homepage":null,"size":11205,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":6,"forks":8,"open_issues":6,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88"},"html":{"href":"https://github.com/edx/edx-e2e-tests/pull/88"},"issue":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/issues/88"},"comments":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/issues/88/comments"},"review_comments":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88/comments"},"review_comment":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/pulls/88/commits"},"statuses":{"href":"https://api.github.com/repos/edx/edx-e2e-tests/statuses/3b4deb20c790ac199d2644eb6fd7258f2b930184"}}}}
{"actor":{"display_login":"kashifch"}}