Не удаётся запустить тесты в одной сессии браузера. Проходит только первый тест.

Проблема (Вопрос) заключается …
Не удаётся запустить тесты в одной сессии браузера.

Я попытался сделать …
Вынес фикстуру в корень проекта и указал scope="session"

У меня получилось …
Запускается только первый тест. Ошибка на втором тесте.

Ошибка
test_add_group.py .F
test_add_group.py:11 (test_add_empty_group)
app = <fixture.application.Application object at 0x0389F790>

    def test_add_empty_group(app):
>       app.session.login(username="admin", password="secret")
Что заметил:

Если запускать каждый тест отдельно, то всё проходит успешно.
Проблема возникает когда запускаю тесты все сразу, т.е. правый клик по папке testRun pytest in test

Если в первом тесте ( test_add_group) поставить time.sleep(1) после app.session.logout(), то тест проходит. Потом успешно запускается и проходит тест test_add_empty_group, но потом так же возникает ошибка только на 3-м тесте, на методе app.session.login(...)

Такое ощущение что не “успевает” кликнуть по ссылке “Logout”.
Дебажил. Если в браузере в том моменте когда зависает тест сам кликну по ссылке “Logout”, то всё нормально идёт дальше.

Бьюсь 2-й день. Может у кого-то были подобные случаи? Или есть какие-то мысли?

Был бы очень рад помощи! Спасибо!)))

Структура проекта:

project
|
|-drivers
|-env
|-fixture
|   |-application.py
|   |-group.py
|   |-session.py
|-model
|   |-group.py
|-test
|   |-test_add_group.py
|   |-test_delete_first_group.py
|-conftest.py
conftest.py
import pytest

from fixture.application import Application


@pytest.fixture(scope="session")
def app(request):
    fixture = Application()
    request.addfinalizer(fixture.destroy)
    return fixture
fixture/application.py
from selenium.webdriver.firefox.webdriver import WebDriver

from fixture.group import GroupHelper
from fixture.session import SessionHelper


class Application:

    def __init__(self):
        self.wd = WebDriver(executable_path="../drivers/geckodriver.exe")
        self.wd.implicitly_wait(60)
        self.session = SessionHelper(self)
        self.group = GroupHelper(self)

    def open_home_page(self):
        wd = self.wd
        wd.get("http://addressbook.loc/")

    def destroy(self):
        self.wd.quit()
fixture/session.py
class SessionHelper:

    def __init__(self, app):
        self.app = app

    def login(self, username, password):
        wd = self.app.wd
        self.app.open_home_page()
        wd.find_element_by_name("user").click()
        wd.find_element_by_name("user").clear()
        wd.find_element_by_name("user").send_keys(username)
        wd.find_element_by_name("pass").click()
        wd.find_element_by_name("pass").clear()
        wd.find_element_by_name("pass").send_keys(password)
        wd.find_element_by_css_selector("input[type=\"submit\"]").click()

    def logout(self):
        wd = self.app.wd
        # Logout
        wd.find_element_by_link_text("Logout").click()
fixture/group.py
class GroupHelper:

    def __init__(self, app):
        self.app = app

    def return_to_groups_page(self):
        wd = self.app.wd
        # Return to groups page
        wd.find_element_by_link_text("group page").click()

    def create(self, group):
        wd = self.app.wd
        self.open_groups_page()
        # Init group creation
        wd.find_element_by_name("new").click()
        # Fill group form
        wd.find_element_by_name("group_name").click()
        wd.find_element_by_name("group_name").clear()
        wd.find_element_by_name("group_name").send_keys(group.name)
        wd.find_element_by_name("group_header").click()
        wd.find_element_by_name("group_header").clear()
        wd.find_element_by_name("group_header").send_keys(group.header)
        wd.find_element_by_name("group_footer").click()
        wd.find_element_by_name("group_footer").clear()
        wd.find_element_by_name("group_footer").send_keys(group.footer)
        # Submit group creation
        wd.find_element_by_name("submit").click()
        self.return_to_groups_page()

    def open_groups_page(self):
        wd = self.app.wd
        wd.find_element_by_link_text("groups").click()

    def delete_first_group(self):
        wd = self.app.wd
        self.open_groups_page()
        # Select first group
        wd.find_element_by_name("selected[]").click()
        # Submit deletion
        wd.find_element_by_name("delete").click()
        self.return_to_groups_page()
model/group.py
class Group:

    def __init__(self, name, header, footer):
        self.name = name
        self.header = header
        self.footer = footer
test/test_add_group.py
# -*- coding: utf-8 -*-

from model.group import Group


def test_add_group(app):
    app.session.login(username="admin", password="secret")
    app.group.create(Group(name="NewGroup", header="Header for NewGroup", footer="Footer for NewGroup"))
    app.session.logout()


def test_add_empty_group(app):
    app.session.login(username="admin", password="secret")
    app.group.create(Group(name="", header="", footer=""))
    app.session.logout()
test/test_delete_first_group.py
def test_delete_first_group(app):
    app.session.login(username="admin", password="secret")
    app.group.delete_first_group()
    app.session.logout()

Логи и ошибка вот такая …

Error
test_add_group.py .F
test_add_group.py:11 (test_add_empty_group)
app = <fixture.application.Application object at 0x0403A8F0>

    def test_add_empty_group(app):
>       app.session.login(username="admin", password="secret")
Log
Testing started at 10:05 AM ...
C:\Users\andrei\PycharmProjects\learnpytest\env\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.3\helpers\pycharm\_jb_pytest_runner.py" --path C:/Users/andrei/PycharmProjects/learnpytest/test
Launching pytest with arguments C:/Users/andrei/PycharmProjects/learnpytest/test in C:\Users\andrei\PycharmProjects\learnpytest\test

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
rootdir: C:\Users\andrei\PycharmProjects\learnpytest\test, inifile:collected 3 items

test_add_group.py .F
test_add_group.py:11 (test_add_empty_group)
app = <fixture.application.Application object at 0x0403A8F0>

    def test_add_empty_group(app):
>       app.session.login(username="admin", password="secret")

test_add_group.py:13: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\fixture\session.py:9: in login
    wd.find_element_by_name("user").click()
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
    return self.find_element(by=By.NAME, value=name)
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
    'value': value})['value']
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
    self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x03D3D910>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: [name=\\"user\\"]",...ror@chrome://marionette/content/error.js:389:5\\nelement.find/</<@chrome://marionette/content/element.js:339:16\\n"}}'}

    def check_response(self, response):
        """
        Checks that a JSON response from the WebDriver does not have an error.
    
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
    
        :Raises: If the response contains an error message.
        """
        status = response.get('status', None)
        if status is None or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get('value', None)
            if value_json and isinstance(value_json, basestring):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value.keys()) == 1:
                        value = value['value']
                    status = value.get('error', None)
                    if status is None:
                        status = value["status"]
                        message = value["value"]
                        if not isinstance(message, basestring):
                            value = message
                            message = message.get('message')
                    else:
                        message = value.get('message', None)
                except ValueError:
                    pass
    
        exception_class = ErrorInResponseException
        if status in ErrorCode.NO_SUCH_ELEMENT:
            exception_class = NoSuchElementException
        elif status in ErrorCode.NO_SUCH_FRAME:
            exception_class = NoSuchFrameException
        elif status in ErrorCode.NO_SUCH_WINDOW:
            exception_class = NoSuchWindowException
        elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
            exception_class = StaleElementReferenceException
        elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
            exception_class = ElementNotVisibleException
        elif status in ErrorCode.INVALID_ELEMENT_STATE:
            exception_class = InvalidElementStateException
        elif status in ErrorCode.INVALID_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
            exception_class = InvalidSelectorException
        elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
            exception_class = ElementNotSelectableException
        elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
            exception_class = ElementNotInteractableException
        elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
            exception_class = InvalidCookieDomainException
        elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
            exception_class = UnableToSetCookieException
        elif status in ErrorCode.TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.SCRIPT_TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.UNKNOWN_ERROR:
            exception_class = WebDriverException
        elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
            exception_class = UnexpectedAlertPresentException
        elif status in ErrorCode.NO_ALERT_OPEN:
            exception_class = NoAlertPresentException
        elif status in ErrorCode.IME_NOT_AVAILABLE:
            exception_class = ImeNotAvailableException
        elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
            exception_class = ImeActivationFailedException
        elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
            exception_class = MoveTargetOutOfBoundsException
        elif status in ErrorCode.JAVASCRIPT_ERROR:
            exception_class = JavascriptException
        elif status in ErrorCode.SESSION_NOT_CREATED:
            exception_class = SessionNotCreatedException
        elif status in ErrorCode.INVALID_ARGUMENT:
            exception_class = InvalidArgumentException
        elif status in ErrorCode.NO_SUCH_COOKIE:
            exception_class = NoSuchCookieException
        elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
            exception_class = ScreenshotException
        elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
            exception_class = ElementClickInterceptedException
        elif status in ErrorCode.INSECURE_CERTIFICATE:
            exception_class = InsecureCertificateException
        elif status in ErrorCode.INVALID_COORDINATES:
            exception_class = InvalidCoordinatesException
        elif status in ErrorCode.INVALID_SESSION_ID:
            exception_class = InvalidSessionIdException
        elif status in ErrorCode.UNKNOWN_METHOD:
            exception_class = UnknownMethodException
        else:
            exception_class = WebDriverException
        if value == '' or value is None:
            value = response['value']
        if isinstance(value, basestring):
            if exception_class == ErrorInResponseException:
                raise exception_class(response, value)
            raise exception_class(value)
        if message == "" and 'message' in value:
            message = value['message']
    
        screen = None
        if 'screen' in value:
            screen = value['screen']
    
        stacktrace = None
        if 'stackTrace' in value and value['stackTrace']:
            stacktrace = []
            try:
                for frame in value['stackTrace']:
                    line = self._value_or_default(frame, 'lineNumber', '')
                    file = self._value_or_default(frame, 'fileName', '<anonymous>')
                    if line:
                        file = "%s:%s" % (file, line)
                    meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                    if 'className' in frame:
                        meth = "%s.%s" % (frame['className'], meth)
                    msg = "    at %s (%s)"
                    msg = msg % (meth, file)
                    stacktrace.append(msg)
            except TypeError:
                pass
        if exception_class == ErrorInResponseException:
            raise exception_class(response, message)
        elif exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if 'data' in value:
                alert_text = value['data'].get('text')
            elif 'alert' in value:
                alert_text = value['alert'].get('text')
            raise exception_class(message, screen, stacktrace, alert_text)
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name="user"]

..\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
                                                     [ 66%]
test_del_group.py F
test_del_group.py:0 (test_delete_first_group)
app = <fixture.application.Application object at 0x0403A8F0>

    def test_delete_first_group(app):
>       app.session.login(username="admin", password="secret")

test_del_group.py:2: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\fixture\session.py:9: in login
    wd.find_element_by_name("user").click()
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
    return self.find_element(by=By.NAME, value=name)
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
    'value': value})['value']
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
    self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x03D3D910>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: [name=\\"user\\"]",...ror@chrome://marionette/content/error.js:389:5\\nelement.find/</<@chrome://marionette/content/element.js:339:16\\n"}}'}

    def check_response(self, response):
        """
        Checks that a JSON response from the WebDriver does not have an error.
    
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
    
        :Raises: If the response contains an error message.
        """
        status = response.get('status', None)
        if status is None or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get('value', None)
            if value_json and isinstance(value_json, basestring):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value.keys()) == 1:
                        value = value['value']
                    status = value.get('error', None)
                    if status is None:
                        status = value["status"]
                        message = value["value"]
                        if not isinstance(message, basestring):
                            value = message
                            message = message.get('message')
                    else:
                        message = value.get('message', None)
                except ValueError:
                    pass
    
        exception_class = ErrorInResponseException
        if status in ErrorCode.NO_SUCH_ELEMENT:
            exception_class = NoSuchElementException
        elif status in ErrorCode.NO_SUCH_FRAME:
            exception_class = NoSuchFrameException
        elif status in ErrorCode.NO_SUCH_WINDOW:
            exception_class = NoSuchWindowException
        elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
            exception_class = StaleElementReferenceException
        elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
            exception_class = ElementNotVisibleException
        elif status in ErrorCode.INVALID_ELEMENT_STATE:
            exception_class = InvalidElementStateException
        elif status in ErrorCode.INVALID_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
            exception_class = InvalidSelectorException
        elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
            exception_class = ElementNotSelectableException
        elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
            exception_class = ElementNotInteractableException
        elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
            exception_class = InvalidCookieDomainException
        elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
            exception_class = UnableToSetCookieException
        elif status in ErrorCode.TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.SCRIPT_TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.UNKNOWN_ERROR:
            exception_class = WebDriverException
        elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
            exception_class = UnexpectedAlertPresentException
        elif status in ErrorCode.NO_ALERT_OPEN:
            exception_class = NoAlertPresentException
        elif status in ErrorCode.IME_NOT_AVAILABLE:
            exception_class = ImeNotAvailableException
        elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
            exception_class = ImeActivationFailedException
        elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
            exception_class = MoveTargetOutOfBoundsException
        elif status in ErrorCode.JAVASCRIPT_ERROR:
            exception_class = JavascriptException
        elif status in ErrorCode.SESSION_NOT_CREATED:
            exception_class = SessionNotCreatedException
        elif status in ErrorCode.INVALID_ARGUMENT:
            exception_class = InvalidArgumentException
        elif status in ErrorCode.NO_SUCH_COOKIE:
            exception_class = NoSuchCookieException
        elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
            exception_class = ScreenshotException
        elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
            exception_class = ElementClickInterceptedException
        elif status in ErrorCode.INSECURE_CERTIFICATE:
            exception_class = InsecureCertificateException
        elif status in ErrorCode.INVALID_COORDINATES:
            exception_class = InvalidCoordinatesException
        elif status in ErrorCode.INVALID_SESSION_ID:
            exception_class = InvalidSessionIdException
        elif status in ErrorCode.UNKNOWN_METHOD:
            exception_class = UnknownMethodException
        else:
            exception_class = WebDriverException
        if value == '' or value is None:
            value = response['value']
        if isinstance(value, basestring):
            if exception_class == ErrorInResponseException:
                raise exception_class(response, value)
            raise exception_class(value)
        if message == "" and 'message' in value:
            message = value['message']
    
        screen = None
        if 'screen' in value:
            screen = value['screen']
    
        stacktrace = None
        if 'stackTrace' in value and value['stackTrace']:
            stacktrace = []
            try:
                for frame in value['stackTrace']:
                    line = self._value_or_default(frame, 'lineNumber', '')
                    file = self._value_or_default(frame, 'fileName', '<anonymous>')
                    if line:
                        file = "%s:%s" % (file, line)
                    meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                    if 'className' in frame:
                        meth = "%s.%s" % (frame['className'], meth)
                    msg = "    at %s (%s)"
                    msg = msg % (meth, file)
                    stacktrace.append(msg)
            except TypeError:
                pass
        if exception_class == ErrorInResponseException:
            raise exception_class(response, message)
        elif exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if 'data' in value:
                alert_text = value['data'].get('text')
            elif 'alert' in value:
                alert_text = value['alert'].get('text')
            raise exception_class(message, screen, stacktrace, alert_text)
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name="user"]

..\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
                                                      [100%]

================================== FAILURES ===================================
____________________________ test_add_empty_group _____________________________

app = <fixture.application.Application object at 0x0403A8F0>

    def test_add_empty_group(app):
>       app.session.login(username="admin", password="secret")

test_add_group.py:13: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\fixture\session.py:9: in login
    wd.find_element_by_name("user").click()
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
    return self.find_element(by=By.NAME, value=name)
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
    'value': value})['value']
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
    self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x03D3D910>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: [name=\\"user\\"]",...ror@chrome://marionette/content/error.js:389:5\\nelement.find/</<@chrome://marionette/content/element.js:339:16\\n"}}'}

    def check_response(self, response):
        """
        Checks that a JSON response from the WebDriver does not have an error.
    
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
    
        :Raises: If the response contains an error message.
        """
        status = response.get('status', None)
        if status is None or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get('value', None)
            if value_json and isinstance(value_json, basestring):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value.keys()) == 1:
                        value = value['value']
                    status = value.get('error', None)
                    if status is None:
                        status = value["status"]
                        message = value["value"]
                        if not isinstance(message, basestring):
                            value = message
                            message = message.get('message')
                    else:
                        message = value.get('message', None)
                except ValueError:
                    pass
    
        exception_class = ErrorInResponseException
        if status in ErrorCode.NO_SUCH_ELEMENT:
            exception_class = NoSuchElementException
        elif status in ErrorCode.NO_SUCH_FRAME:
            exception_class = NoSuchFrameException
        elif status in ErrorCode.NO_SUCH_WINDOW:
            exception_class = NoSuchWindowException
        elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
            exception_class = StaleElementReferenceException
        elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
            exception_class = ElementNotVisibleException
        elif status in ErrorCode.INVALID_ELEMENT_STATE:
            exception_class = InvalidElementStateException
        elif status in ErrorCode.INVALID_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
            exception_class = InvalidSelectorException
        elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
            exception_class = ElementNotSelectableException
        elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
            exception_class = ElementNotInteractableException
        elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
            exception_class = InvalidCookieDomainException
        elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
            exception_class = UnableToSetCookieException
        elif status in ErrorCode.TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.SCRIPT_TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.UNKNOWN_ERROR:
            exception_class = WebDriverException
        elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
            exception_class = UnexpectedAlertPresentException
        elif status in ErrorCode.NO_ALERT_OPEN:
            exception_class = NoAlertPresentException
        elif status in ErrorCode.IME_NOT_AVAILABLE:
            exception_class = ImeNotAvailableException
        elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
            exception_class = ImeActivationFailedException
        elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
            exception_class = MoveTargetOutOfBoundsException
        elif status in ErrorCode.JAVASCRIPT_ERROR:
            exception_class = JavascriptException
        elif status in ErrorCode.SESSION_NOT_CREATED:
            exception_class = SessionNotCreatedException
        elif status in ErrorCode.INVALID_ARGUMENT:
            exception_class = InvalidArgumentException
        elif status in ErrorCode.NO_SUCH_COOKIE:
            exception_class = NoSuchCookieException
        elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
            exception_class = ScreenshotException
        elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
            exception_class = ElementClickInterceptedException
        elif status in ErrorCode.INSECURE_CERTIFICATE:
            exception_class = InsecureCertificateException
        elif status in ErrorCode.INVALID_COORDINATES:
            exception_class = InvalidCoordinatesException
        elif status in ErrorCode.INVALID_SESSION_ID:
            exception_class = InvalidSessionIdException
        elif status in ErrorCode.UNKNOWN_METHOD:
            exception_class = UnknownMethodException
        else:
            exception_class = WebDriverException
        if value == '' or value is None:
            value = response['value']
        if isinstance(value, basestring):
            if exception_class == ErrorInResponseException:
                raise exception_class(response, value)
            raise exception_class(value)
        if message == "" and 'message' in value:
            message = value['message']
    
        screen = None
        if 'screen' in value:
            screen = value['screen']
    
        stacktrace = None
        if 'stackTrace' in value and value['stackTrace']:
            stacktrace = []
            try:
                for frame in value['stackTrace']:
                    line = self._value_or_default(frame, 'lineNumber', '')
                    file = self._value_or_default(frame, 'fileName', '<anonymous>')
                    if line:
                        file = "%s:%s" % (file, line)
                    meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                    if 'className' in frame:
                        meth = "%s.%s" % (frame['className'], meth)
                    msg = "    at %s (%s)"
                    msg = msg % (meth, file)
                    stacktrace.append(msg)
            except TypeError:
                pass
        if exception_class == ErrorInResponseException:
            raise exception_class(response, message)
        elif exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if 'data' in value:
                alert_text = value['data'].get('text')
            elif 'alert' in value:
                alert_text = value['alert'].get('text')
            raise exception_class(message, screen, stacktrace, alert_text)
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name="user"]

..\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
___________________________ test_delete_first_group ___________________________

app = <fixture.application.Application object at 0x0403A8F0>

    def test_delete_first_group(app):
>       app.session.login(username="admin", password="secret")

test_del_group.py:2: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\fixture\session.py:9: in login
    wd.find_element_by_name("user").click()
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
    return self.find_element(by=By.NAME, value=name)
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
    'value': value})['value']
..\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
    self.error_handler.check_response(response)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x03D3D910>
response = {'status': 404, 'value': '{"value":{"error":"no such element","message":"Unable to locate element: [name=\\"user\\"]",...ror@chrome://marionette/content/error.js:389:5\\nelement.find/</<@chrome://marionette/content/element.js:339:16\\n"}}'}

    def check_response(self, response):
        """
        Checks that a JSON response from the WebDriver does not have an error.
    
        :Args:
         - response - The JSON response from the WebDriver server as a dictionary
           object.
    
        :Raises: If the response contains an error message.
        """
        status = response.get('status', None)
        if status is None or status == ErrorCode.SUCCESS:
            return
        value = None
        message = response.get("message", "")
        screen = response.get("screen", "")
        stacktrace = None
        if isinstance(status, int):
            value_json = response.get('value', None)
            if value_json and isinstance(value_json, basestring):
                import json
                try:
                    value = json.loads(value_json)
                    if len(value.keys()) == 1:
                        value = value['value']
                    status = value.get('error', None)
                    if status is None:
                        status = value["status"]
                        message = value["value"]
                        if not isinstance(message, basestring):
                            value = message
                            message = message.get('message')
                    else:
                        message = value.get('message', None)
                except ValueError:
                    pass
    
        exception_class = ErrorInResponseException
        if status in ErrorCode.NO_SUCH_ELEMENT:
            exception_class = NoSuchElementException
        elif status in ErrorCode.NO_SUCH_FRAME:
            exception_class = NoSuchFrameException
        elif status in ErrorCode.NO_SUCH_WINDOW:
            exception_class = NoSuchWindowException
        elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
            exception_class = StaleElementReferenceException
        elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
            exception_class = ElementNotVisibleException
        elif status in ErrorCode.INVALID_ELEMENT_STATE:
            exception_class = InvalidElementStateException
        elif status in ErrorCode.INVALID_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR \
                or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
            exception_class = InvalidSelectorException
        elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
            exception_class = ElementNotSelectableException
        elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
            exception_class = ElementNotInteractableException
        elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
            exception_class = InvalidCookieDomainException
        elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
            exception_class = UnableToSetCookieException
        elif status in ErrorCode.TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.SCRIPT_TIMEOUT:
            exception_class = TimeoutException
        elif status in ErrorCode.UNKNOWN_ERROR:
            exception_class = WebDriverException
        elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
            exception_class = UnexpectedAlertPresentException
        elif status in ErrorCode.NO_ALERT_OPEN:
            exception_class = NoAlertPresentException
        elif status in ErrorCode.IME_NOT_AVAILABLE:
            exception_class = ImeNotAvailableException
        elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
            exception_class = ImeActivationFailedException
        elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
            exception_class = MoveTargetOutOfBoundsException
        elif status in ErrorCode.JAVASCRIPT_ERROR:
            exception_class = JavascriptException
        elif status in ErrorCode.SESSION_NOT_CREATED:
            exception_class = SessionNotCreatedException
        elif status in ErrorCode.INVALID_ARGUMENT:
            exception_class = InvalidArgumentException
        elif status in ErrorCode.NO_SUCH_COOKIE:
            exception_class = NoSuchCookieException
        elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
            exception_class = ScreenshotException
        elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
            exception_class = ElementClickInterceptedException
        elif status in ErrorCode.INSECURE_CERTIFICATE:
            exception_class = InsecureCertificateException
        elif status in ErrorCode.INVALID_COORDINATES:
            exception_class = InvalidCoordinatesException
        elif status in ErrorCode.INVALID_SESSION_ID:
            exception_class = InvalidSessionIdException
        elif status in ErrorCode.UNKNOWN_METHOD:
            exception_class = UnknownMethodException
        else:
            exception_class = WebDriverException
        if value == '' or value is None:
            value = response['value']
        if isinstance(value, basestring):
            if exception_class == ErrorInResponseException:
                raise exception_class(response, value)
            raise exception_class(value)
        if message == "" and 'message' in value:
            message = value['message']
    
        screen = None
        if 'screen' in value:
            screen = value['screen']
    
        stacktrace = None
        if 'stackTrace' in value and value['stackTrace']:
            stacktrace = []
            try:
                for frame in value['stackTrace']:
                    line = self._value_or_default(frame, 'lineNumber', '')
                    file = self._value_or_default(frame, 'fileName', '<anonymous>')
                    if line:
                        file = "%s:%s" % (file, line)
                    meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                    if 'className' in frame:
                        meth = "%s.%s" % (frame['className'], meth)
                    msg = "    at %s (%s)"
                    msg = msg % (meth, file)
                    stacktrace.append(msg)
            except TypeError:
                pass
        if exception_class == ErrorInResponseException:
            raise exception_class(response, message)
        elif exception_class == UnexpectedAlertPresentException:
            alert_text = None
            if 'data' in value:
                alert_text = value['data'].get('text')
            elif 'alert' in value:
                alert_text = value['alert'].get('text')
            raise exception_class(message, screen, stacktrace, alert_text)
>       raise exception_class(message, screen, stacktrace)
E       selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name="user"]

..\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
===================== 2 failed, 1 passed in 11.38 seconds =====================
Process finished with exit code 0

Версии ОС и софта следующие …

  • Windows 10 x64 Pro Version 10.0.17134 Build 17134
  • PyCharm Community Edition 2018.3.3 x64
  • Python 3.7.2
  • Firefox 64.0.2 (64-bit)
  • geckodriver-v0.24.0-win64
pip list
Package        Version
-------------- -------
atomicwrites   1.2.1  
attrs          18.2.0 
colorama       0.4.1  
more-itertools 5.0.0  
pip            19.0.1 
pluggy         0.8.1  
py             1.7.0  
pytest         4.1.1  
selenium       3.141.0
setuptools     40.7.1 
six            1.12.0 
urllib3        1.24.1 
wheel          0.32.3

Судя по коду, вы выполняете домашнее задание на курсе А.Баранцева. Почему вы не спросите у него или в чате учеников?
Попробуйте разделить fixture def app на def app и def stop с addfinalizer

2 лайка

Увы, не был на курсах А. Баранцева. Вопрос задавать неудобно так как пользуюсь материалом из просторов интернетов)

Не совсем представляю как это будет работать.

В def app создаётся экземпляр класса Application где как раз и инициализируется WebDriver. В этом же классе есть метод def destroy, который завершает работу драйвера.

def app передаётся тестам качества в параметра тестам. Т.е. одна фикстура управляет всеми тестами.

Как должна выглядеть def stop с addfinalizer отдельно?

Что ещё попробовал:

  1. Изменил селектор. Вместо искать по имени find_element_by_name изменил на find_element_by_css_selector - ошибка осталась.
  2. Добавил time.sleep(1) в метод def logoutв классе SessionHelper после клика- ошибки нет
Теперь код выглядит так:
import time


class SessionHelper:

    def __init__(self, app):
        self.app = app

    def login(self, username, password):
        wd = self.app.wd
        self.app.open_home_page()
        wd.find_element_by_css_selector("input[name='user']").click()
        wd.find_element_by_css_selector("input[name='user']").clear()
        wd.find_element_by_css_selector("input[name='user']").send_keys(username)
        wd.find_element_by_css_selector("input[name='pass']").click()
        wd.find_element_by_css_selector("input[name='pass']").clear()
        wd.find_element_by_css_selector("input[name='pass']").send_keys(password)
        wd.find_element_by_css_selector("input[type='submit']").click()

    def logout(self):
        wd = self.app.wd
        # Logout
        wd.find_element_by_css_selector("form[name='logout'] > a").click()
        time.sleep(1)

Это нормальные костыли или есть лучше практика? Или вообще причина может быть в другом? Спасибо!

Нет, это не нормально. Попробуйте в логине проверять, есть ли кнопка логаут, уберите все слипы.

1 лайк

Ошибка осталась.

Новый код
from selenium.common.exceptions import NoSuchElementException


class SessionHelper:

    def __init__(self, app):
        self.app = app

    def login(self, username, password):
        wd = self.app.wd
        self.app.open_home_page()
        wd.find_element_by_name("user").click()
        wd.find_element_by_name("user").clear()
        wd.find_element_by_name("user").send_keys(username)
        wd.find_element_by_name("pass").click()
        wd.find_element_by_name("pass").clear()
        wd.find_element_by_name("pass").send_keys(password)
        wd.find_element_by_css_selector("input[type=\"submit\"]").click()

    def logout(self):
        wd = self.app.wd
        elm_logout = "form[name='logout'] > a"
        if self.check_exists_by_css_selector(elm_logout):
            wd.find_element_by_css_selector(elm_logout).click()

    def check_exists_by_css_selector(self, selector):
        wd = self.app.wd
        try:
            wd.find_element_by_css_selector(selector)
            print("Element: " + selector + " exists")
        except NoSuchElementException:
            print("Element: " + selector + " doesn't exist")
            return False
        return True

Log

Testing started at 11:56 PM …
C:\Users\andrei\PycharmProjects\learnpytest\env\Scripts\python.exe “C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.3\helpers\pycharm_jb_pytest_runner.py” --path C:/Users/andrei/PycharmProjects/learnpytest/test/test_add_group.py
Launching pytest with arguments C:/Users/andrei/PycharmProjects/learnpytest/test/test_add_group.py in C:\Users\andrei\PycharmProjects\learnpytest\test

============================= test session starts =============================
platform win32 – Python 3.7.2, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
rootdir: C:\Users\andrei\PycharmProjects\learnpytest\test, inifile:collected 2 items

test_add_group.py .Element: form[name=‘logout’] > a exists
F
test_add_group.py:11 (test_add_empty_group)
app = <fixture.application.Application object at 0x038B12B0>

def test_add_empty_group(app):
  app.session.login(username="admin", password="secret")

test_add_group.py:13:


…\fixture\session.py:14: in login
wd.find_element_by_name(“user”).click()
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
return self.find_element(by=By.NAME, value=name)
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
‘value’: value})[‘value’]
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
self.error_handler.check_response(response)


self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x0321D8D0>
response = {‘status’: 404, ‘value’: ‘{“value”:{“error”:“no such element”,“message”:“Unable to locate element: [name=\“user\”]”,…ror@chrome://marionette/content/error.js:389:5\nelement.find/</<@chrome://marionette/content/element.js:339:16\n"}}’}

def check_response(self, response):
    """
    Checks that a JSON response from the WebDriver does not have an error.

    :Args:
     - response - The JSON response from the WebDriver server as a dictionary
       object.

    :Raises: If the response contains an error message.
    """
    status = response.get('status', None)
    if status is None or status == ErrorCode.SUCCESS:
        return
    value = None
    message = response.get("message", "")
    screen = response.get("screen", "")
    stacktrace = None
    if isinstance(status, int):
        value_json = response.get('value', None)
        if value_json and isinstance(value_json, basestring):
            import json
            try:
                value = json.loads(value_json)
                if len(value.keys()) == 1:
                    value = value['value']
                status = value.get('error', None)
                if status is None:
                    status = value["status"]
                    message = value["value"]
                    if not isinstance(message, basestring):
                        value = message
                        message = message.get('message')
                else:
                    message = value.get('message', None)
            except ValueError:
                pass

    exception_class = ErrorInResponseException
    if status in ErrorCode.NO_SUCH_ELEMENT:
        exception_class = NoSuchElementException
    elif status in ErrorCode.NO_SUCH_FRAME:
        exception_class = NoSuchFrameException
    elif status in ErrorCode.NO_SUCH_WINDOW:
        exception_class = NoSuchWindowException
    elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
        exception_class = StaleElementReferenceException
    elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
        exception_class = ElementNotVisibleException
    elif status in ErrorCode.INVALID_ELEMENT_STATE:
        exception_class = InvalidElementStateException
    elif status in ErrorCode.INVALID_SELECTOR \
            or status in ErrorCode.INVALID_XPATH_SELECTOR \
            or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
        exception_class = InvalidSelectorException
    elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
        exception_class = ElementNotSelectableException
    elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
        exception_class = ElementNotInteractableException
    elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
        exception_class = InvalidCookieDomainException
    elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
        exception_class = UnableToSetCookieException
    elif status in ErrorCode.TIMEOUT:
        exception_class = TimeoutException
    elif status in ErrorCode.SCRIPT_TIMEOUT:
        exception_class = TimeoutException
    elif status in ErrorCode.UNKNOWN_ERROR:
        exception_class = WebDriverException
    elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
        exception_class = UnexpectedAlertPresentException
    elif status in ErrorCode.NO_ALERT_OPEN:
        exception_class = NoAlertPresentException
    elif status in ErrorCode.IME_NOT_AVAILABLE:
        exception_class = ImeNotAvailableException
    elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
        exception_class = ImeActivationFailedException
    elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
        exception_class = MoveTargetOutOfBoundsException
    elif status in ErrorCode.JAVASCRIPT_ERROR:
        exception_class = JavascriptException
    elif status in ErrorCode.SESSION_NOT_CREATED:
        exception_class = SessionNotCreatedException
    elif status in ErrorCode.INVALID_ARGUMENT:
        exception_class = InvalidArgumentException
    elif status in ErrorCode.NO_SUCH_COOKIE:
        exception_class = NoSuchCookieException
    elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
        exception_class = ScreenshotException
    elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
        exception_class = ElementClickInterceptedException
    elif status in ErrorCode.INSECURE_CERTIFICATE:
        exception_class = InsecureCertificateException
    elif status in ErrorCode.INVALID_COORDINATES:
        exception_class = InvalidCoordinatesException
    elif status in ErrorCode.INVALID_SESSION_ID:
        exception_class = InvalidSessionIdException
    elif status in ErrorCode.UNKNOWN_METHOD:
        exception_class = UnknownMethodException
    else:
        exception_class = WebDriverException
    if value == '' or value is None:
        value = response['value']
    if isinstance(value, basestring):
        if exception_class == ErrorInResponseException:
            raise exception_class(response, value)
        raise exception_class(value)
    if message == "" and 'message' in value:
        message = value['message']

    screen = None
    if 'screen' in value:
        screen = value['screen']

    stacktrace = None
    if 'stackTrace' in value and value['stackTrace']:
        stacktrace = []
        try:
            for frame in value['stackTrace']:
                line = self._value_or_default(frame, 'lineNumber', '')
                file = self._value_or_default(frame, 'fileName', '<anonymous>')
                if line:
                    file = "%s:%s" % (file, line)
                meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                if 'className' in frame:
                    meth = "%s.%s" % (frame['className'], meth)
                msg = "    at %s (%s)"
                msg = msg % (meth, file)
                stacktrace.append(msg)
        except TypeError:
            pass
    if exception_class == ErrorInResponseException:
        raise exception_class(response, message)
    elif exception_class == UnexpectedAlertPresentException:
        alert_text = None
        if 'data' in value:
            alert_text = value['data'].get('text')
        elif 'alert' in value:
            alert_text = value['alert'].get('text')
        raise exception_class(message, screen, stacktrace, alert_text)
  raise exception_class(message, screen, stacktrace)

E selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name=“user”]

…\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
[100%]

================================== FAILURES ===================================
____________________________ test_add_empty_group _____________________________

app = <fixture.application.Application object at 0x038B12B0>

def test_add_empty_group(app):
  app.session.login(username="admin", password="secret")

test_add_group.py:13:


…\fixture\session.py:14: in login
wd.find_element_by_name(“user”).click()
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:496: in find_element_by_name
return self.find_element(by=By.NAME, value=name)
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:978: in find_element
‘value’: value})[‘value’]
…\env\lib\site-packages\selenium\webdriver\remote\webdriver.py:321: in execute
self.error_handler.check_response(response)


self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x0321D8D0>
response = {‘status’: 404, ‘value’: ‘{“value”:{“error”:“no such element”,“message”:“Unable to locate element: [name=\“user\”]”,…ror@chrome://marionette/content/error.js:389:5\nelement.find/</<@chrome://marionette/content/element.js:339:16\n"}}’}

def check_response(self, response):
    """
    Checks that a JSON response from the WebDriver does not have an error.

    :Args:
     - response - The JSON response from the WebDriver server as a dictionary
       object.

    :Raises: If the response contains an error message.
    """
    status = response.get('status', None)
    if status is None or status == ErrorCode.SUCCESS:
        return
    value = None
    message = response.get("message", "")
    screen = response.get("screen", "")
    stacktrace = None
    if isinstance(status, int):
        value_json = response.get('value', None)
        if value_json and isinstance(value_json, basestring):
            import json
            try:
                value = json.loads(value_json)
                if len(value.keys()) == 1:
                    value = value['value']
                status = value.get('error', None)
                if status is None:
                    status = value["status"]
                    message = value["value"]
                    if not isinstance(message, basestring):
                        value = message
                        message = message.get('message')
                else:
                    message = value.get('message', None)
            except ValueError:
                pass

    exception_class = ErrorInResponseException
    if status in ErrorCode.NO_SUCH_ELEMENT:
        exception_class = NoSuchElementException
    elif status in ErrorCode.NO_SUCH_FRAME:
        exception_class = NoSuchFrameException
    elif status in ErrorCode.NO_SUCH_WINDOW:
        exception_class = NoSuchWindowException
    elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
        exception_class = StaleElementReferenceException
    elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
        exception_class = ElementNotVisibleException
    elif status in ErrorCode.INVALID_ELEMENT_STATE:
        exception_class = InvalidElementStateException
    elif status in ErrorCode.INVALID_SELECTOR \
            or status in ErrorCode.INVALID_XPATH_SELECTOR \
            or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
        exception_class = InvalidSelectorException
    elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
        exception_class = ElementNotSelectableException
    elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
        exception_class = ElementNotInteractableException
    elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
        exception_class = InvalidCookieDomainException
    elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
        exception_class = UnableToSetCookieException
    elif status in ErrorCode.TIMEOUT:
        exception_class = TimeoutException
    elif status in ErrorCode.SCRIPT_TIMEOUT:
        exception_class = TimeoutException
    elif status in ErrorCode.UNKNOWN_ERROR:
        exception_class = WebDriverException
    elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
        exception_class = UnexpectedAlertPresentException
    elif status in ErrorCode.NO_ALERT_OPEN:
        exception_class = NoAlertPresentException
    elif status in ErrorCode.IME_NOT_AVAILABLE:
        exception_class = ImeNotAvailableException
    elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
        exception_class = ImeActivationFailedException
    elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
        exception_class = MoveTargetOutOfBoundsException
    elif status in ErrorCode.JAVASCRIPT_ERROR:
        exception_class = JavascriptException
    elif status in ErrorCode.SESSION_NOT_CREATED:
        exception_class = SessionNotCreatedException
    elif status in ErrorCode.INVALID_ARGUMENT:
        exception_class = InvalidArgumentException
    elif status in ErrorCode.NO_SUCH_COOKIE:
        exception_class = NoSuchCookieException
    elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
        exception_class = ScreenshotException
    elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
        exception_class = ElementClickInterceptedException
    elif status in ErrorCode.INSECURE_CERTIFICATE:
        exception_class = InsecureCertificateException
    elif status in ErrorCode.INVALID_COORDINATES:
        exception_class = InvalidCoordinatesException
    elif status in ErrorCode.INVALID_SESSION_ID:
        exception_class = InvalidSessionIdException
    elif status in ErrorCode.UNKNOWN_METHOD:
        exception_class = UnknownMethodException
    else:
        exception_class = WebDriverException
    if value == '' or value is None:
        value = response['value']
    if isinstance(value, basestring):
        if exception_class == ErrorInResponseException:
            raise exception_class(response, value)
        raise exception_class(value)
    if message == "" and 'message' in value:
        message = value['message']

    screen = None
    if 'screen' in value:
        screen = value['screen']

    stacktrace = None
    if 'stackTrace' in value and value['stackTrace']:
        stacktrace = []
        try:
            for frame in value['stackTrace']:
                line = self._value_or_default(frame, 'lineNumber', '')
                file = self._value_or_default(frame, 'fileName', '<anonymous>')
                if line:
                    file = "%s:%s" % (file, line)
                meth = self._value_or_default(frame, 'methodName', '<anonymous>')
                if 'className' in frame:
                    meth = "%s.%s" % (frame['className'], meth)
                msg = "    at %s (%s)"
                msg = msg % (meth, file)
                stacktrace.append(msg)
        except TypeError:
            pass
    if exception_class == ErrorInResponseException:
        raise exception_class(response, message)
    elif exception_class == UnexpectedAlertPresentException:
        alert_text = None
        if 'data' in value:
            alert_text = value['data'].get('text')
        elif 'alert' in value:
            alert_text = value['alert'].get('text')
        raise exception_class(message, screen, stacktrace, alert_text)
  raise exception_class(message, screen, stacktrace)

E selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [name=“user”]

…\env\lib\site-packages\selenium\webdriver\remote\errorhandler.py:242: NoSuchElementException
===================== 1 failed, 1 passed in 8.01 seconds ======================
Process finished with exit code 0

Из сообщения test_add_group.py .Element: form[name=‘logout’] > a exists понятно, что элемент успешно находится.

Вместо try catch можно было
if len(wd.find_elememts_by_xxx(xxxxx))>0:
print (“элемент есть”)
else
print (“элемента нет”)
пишу с телефона, не самое удобное, значения подставите
А так, можно проверять, что logout исчез, поставить здесь явное ожидание вместо sleep(1)

1 лайк

Сделал 2 варианта и с if и с implicit waits. Оба работают, но вот что смущает:

if len(…) > 0

почему тест проходит успешно если отработал блок в login():

else:
    print("!!!Code that shouldn't be shown")
Code
class SessionHelper:

    def __init__(self, app):
        self.app = app
        self.elem_logout = "form[name='logout'] > a"
        self.elem_input_user = "input[name='user']"
        self.elem_input_pass = "input[name='pass']"

    def login(self, username, password):
        wd = self.app.wd
        self.app.open_home_page()
        if not self.check_exists_by_css_selector(self.elem_logout):
            wd.find_element_by_css_selector(self.elem_input_user).click()
            wd.find_element_by_css_selector(self.elem_input_user).clear()
            wd.find_element_by_css_selector(self.elem_input_user).send_keys(username)
            wd.find_element_by_css_selector(self.elem_input_pass).click()
            wd.find_element_by_css_selector(self.elem_input_pass).clear()
            wd.find_element_by_css_selector(self.elem_input_pass).send_keys(password)
            wd.find_element_by_css_selector("input[type='submit']").click()
        else:
            print("!!!Code that shouldn't be shown")

    def logout(self):
        wd = self.app.wd
        if self.check_exists_by_css_selector(self.elem_logout):
            wd.find_element_by_css_selector(self.elem_logout).click()

    def check_exists_by_css_selector(self, selector):
        wd = self.app.wd
        if len(wd.find_elements_by_css_selector(selector)) > 0:
            print("Element: $(\"" + selector + "\") - exists")
            return True
        else:
            print("Element: $(\"" + selector + "\") - doesn't exist")
            return False
Log
Testing started at 10:29 AM ...
C:\Users\andrei\PycharmProjects\learnpytest\env\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.3\helpers\pycharm\_jb_pytest_runner.py" --path C:/Users/andrei/PycharmProjects/learnpytest/test
Launching pytest with arguments C:/Users/andrei/PycharmProjects/learnpytest/test in C:\Users\andrei\PycharmProjects\learnpytest\test

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
rootdir: C:\Users\andrei\PycharmProjects\learnpytest\test, inifile:collected 5 items

test_add_group.py .Element: $("form[name='logout'] > a") - doesn't exist
Element: $("form[name='logout'] > a") - exists
.Element: $("form[name='logout'] > a") - exists
!!!Code that shouldn't be shown
Element: $("form[name='logout'] > a") - exists
                                                     [ 40%]
test_del_group.py .Element: $("form[name='logout'] > a") - exists
!!!Code that shouldn't be shown
Element: $("form[name='logout'] > a") - exists
                                                      [ 60%]
test_modify_group.py .Element: $("form[name='logout'] > a") - exists
!!!Code that shouldn't be shown
Element: $("form[name='logout'] > a") - exists
.Element: $("form[name='logout'] > a") - exists
!!!Code that shouldn't be shown
Element: $("form[name='logout'] > a") - exists
                                                  [100%]

========================== 5 passed in 10.99 seconds ==========================
Process finished with exit code 0

Implicit waits

Так же и здесь. Как выполняется этот код?

else:
    print("Scope Login: $(\"" + self.elem_logout + "\") - Element exists")

Если бы элемент logout был на странице login, то мы бы не смогли авторизоваться.

Code
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait


class SessionHelper:

    def __init__(self, app):
        self.app = app
        self.elem_logout = "form[name='logout'] > a"
        self.elem_input_user = "input[name='user']"
        self.elem_input_pass = "input[name='pass']"

    def login(self, username, password):
        wd = self.app.wd
        self.app.open_home_page()

        if not self.presence_of_element(3, self.elem_logout):
            wd.find_element_by_css_selector(self.elem_input_user).click()
            wd.find_element_by_css_selector(self.elem_input_user).clear()
            wd.find_element_by_css_selector(self.elem_input_user).send_keys(username)
            wd.find_element_by_css_selector(self.elem_input_pass).click()
            wd.find_element_by_css_selector(self.elem_input_pass).clear()
            wd.find_element_by_css_selector(self.elem_input_pass).send_keys(password)
            wd.find_element_by_css_selector("input[type='submit']").click()
        else:
            print("Scope Login: $(\"" + self.elem_logout + "\") - Element exists")

    def logout(self):
        wd = self.app.wd
        if self.presence_of_element(3, self.elem_logout):
            wd.find_element_by_css_selector(self.elem_logout).click()
        else:
            print("Scope Logout: $(\"" + self.elem_logout + "\") - Element doesn't exists")

    def presence_of_element(self, timeout_sec, css_selector):
        wd = self.app.wd
        try:
            wait = WebDriverWait(wd, timeout_sec)
            wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, css_selector)))
            return True
        except TimeoutException:
            return False
Log
Testing started at 10:34 AM ...
C:\Users\andrei\PycharmProjects\learnpytest\env\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2018.3.3\helpers\pycharm\_jb_pytest_runner.py" --path C:/Users/andrei/PycharmProjects/learnpytest/test
Launching pytest with arguments C:/Users/andrei/PycharmProjects/learnpytest/test in C:\Users\andrei\PycharmProjects\learnpytest\test

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
rootdir: C:\Users\andrei\PycharmProjects\learnpytest\test, inifile:collected 5 items

test_add_group.py ..Scope Login: $("form[name='logout'] > a") - Element exists
                                                     [ 40%]
test_del_group.py .Scope Login: $("form[name='logout'] > a") - Element exists
                                                      [ 60%]
test_modify_group.py .Scope Login: $("form[name='logout'] > a") - Element exists
.Scope Login: $("form[name='logout'] > a") - Element exists
                                                  [100%]

========================== 5 passed in 11.47 seconds ==========================
Process finished with exit code 0

И ещё))) Что значат проценты в квадратных скобках?
test_add_group.py ..Scope Login: $("form[name='logout'] > a") - Element exists
                                                     [ 40%]

процент пройденных тестов

1 лайк

Странно. Тесты прошли все, а показывает разный процент.

Screen

Итоговый 100%

1 лайк

Понял, т.е. прогресс показывает по конкретному файлу с тестами. Процент относительно общего кол-ва файлов с тестами.

Правильно понял, проблема имеете 2 решения?

Сообщение: Не удаётся запустить тесты в одной сессии браузера. Проходит только первый тест. - #10 от пользователя allhimik

Там же есть 2 вопроса, может есть какие то мысли?

Есть ссылка на github ?

Проверил сотый раз под дебагом на Firefox. Ошибки нет. Но если обычно запустить, то ошибка.
Так же ошибка под Edge

Ошибки нет под chromedriver


Firefox обновлённый до 65.0, драйвер последний v0.24.0
Edge 17.17134, драйвер от сюда Release 17134


Ошибку не решил, копаю дальше. Временно тесты буду гонять только под хромом.
Если есть предположения, мысли - ПИШИТЕ! У меня голова уже кругом)))

Добавьте в конец logout:
time.sleep(0.1)

Предварительно import time.
С числом можно играться, но этого должно хватить