selenium.common.exceptions.InvalidCookieDomainException:消息:使用 Selenium 在 Django 中执行测试时无效的 cookie 域

selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain while executing tests in Django with Selenium

我正在使用 seleniumgrid.I 为 chrome 和 firefox 设置测试,我正在使用 docker 图像 selenium-hub 和 selenium node-chrome 以及 node-firefox 作为下面。

  app:
    build: .
    command: gunicorn --reload --capture-output --log-level debug --access-logfile - -w 3 -b 0.0.0.0 app.wsgi
    restart: always
    volumes_from:
        - initialize
    ports:
      - "8000:8000"
    links:
      - db
      - rabbitmq
      - selenium_hub
    env_file: secrets.env
    volumes:
        - ./app/:/code/

  selenium_hub:
    image: selenium/hub
    ports:
      - 4444:4444
    expose:
      - 4444
    tty: true
    environment:
      - GRID_MAX_SESSION=20
      - GRID_NEW_SESSION_WAIT_TIMEOUT=60000
      - GRID_BROWSER_TIMEOUT=300
      - GRID_TIMEOUT=300
      - TIMEOUT=300
  node_1:
    image: selenium/node-chrome
    depends_on:
      - selenium_hub
    environment:
      - HUB_HOST=selenium_hub
      - HUB_PORT=4444
      - NODE_MAX_SESSION=3
      - NODE_MAX_INSTANCES=2
    shm_size: 2GB
  node_2:
    image: selenium/node-firefox
    environment:
      - HUB_HOST=selenium_hub
      - HUB_PORT=4444
      - NODE_MAX_SESSION=3
      - NODE_MAX_INSTANCES=2
    shm_size: 2GB
    depends_on:
      - selenium_hub

当我尝试 运行 测试时,我总是 运行 遇到这个错误 InvalidCookieDomainException: Message: invalid cookie domain。我已经将域设置为 self.live_server_url。 下面是测试设置的完整回溯。

  Traceback (most recent call last):
    File "/code/frontend/tests/test_user_auth.py", line 75, in setUp
        "port": "8082",
    File "/usr/local/lib/python3.5/site-packages/selenium/webdriver/remote/webdriver.py", line 894, in add_cookie
        self.execute(Command.ADD_COOKIE, {'cookie': cookie_dict})
    File "/usr/local/lib/python3.5/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
        self.error_handler.check_response(response)
    File "/usr/local/lib/python3.5/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
        raise exception_class(message, screen, stacktrace)
    selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain
    (Session info: chrome=77.0.3865.75)

测试reference tutorial.

class TestUserCreate(StaticLiveServerTestCase):
    fixtures = ["test.json"]
    port = 8082

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        caps = {
            "browserName": os.getenv("BROWSER", "chrome"),
            "javascriptEnabled": True,
         }
        cls.driver = webdriver.Remote(
            command_executor="http://selenium_hub:4444/wd/hub",
            desired_capabilities=caps,
         )
        cls.driver.implicitly_wait(10)

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()
        super().tearDownClass()

    def setUp(self):
        # Login the user
        self.assertTrue(self.client.login(username="james", password="changemequick"))

        # Add cookie to log in the browser
        cookie = self.client.cookies["sessionid"]
        self.driver.get(self.live_server_url + reverse("find_patient"))
        self.driver.add_cookie(
            {
                "name": "sessionid",
                "value": cookie.value,
                "domain": "localhost"
            }
         )
        super().setUp()

    def test_form_loader(self):
        # test forms loader is functioning properly

        driver = self.driver
        driver.get(self.live_server_url + "/accounts/login/")

        driver.find_element_by_xpath("//input[@type='submit']").click()
        driver.get_screenshot_as_file("login.png")
        assert len(driver.find_elements_by_css_selector(".loading")) == 0

这个错误信息...

selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain

...表示非法尝试在与当前文档不同的域下设置 cookie。


详情

根据 HTML-Living Standard Specs,在以下情况下,Document Object 可能被归类为 cookie-averse Document 对象:

  • 没有 Browsing Context.
  • 的文档
  • URL 方案不是网络方案的文档。

深入探讨

根据 Invalid cookie domain 如果当前域为 example.com,则可能会发生此错误,将无法为域 example.org 添加 cookie。

举个例子:

  • 示例代码:

    from selenium import webdriver
    from selenium.common import exceptions
    
    session = webdriver.Firefox()
    session.get("https://example.com/")
    try:
        cookie = {"name": "foo",
              "value": "bar",
              "domain": "example.org"}
        session.add_cookie(cookie)
    except exceptions.InvalidCookieDomainException as e:
        print(e.message)
    
  • 控制台输出:

    InvalidCookieDomainException: https://example.org/
    

解决方案

如果您存储了来自域 example.com 的 cookie,这些存储的 cookie 不能 通过 webdriver 会话推送到任何其他不同的域,例如example.edu。存储的 cookie 只能在 example.com 内使用。此外,为了将来自动登录用户,您只需要存储 cookie 一次,即用户登录时。在添加回 cookie 之前,您需要浏览到收集 cookie 的同一域。


例子

例如,您可以在用户登录应用程序后存储 cookie,如下所示:

from selenium import webdriver
import pickle

driver = webdriver.Chrome()
driver.get('http://demo.guru99.com/test/cookie/selenium_aut.php')
driver.find_element_by_name("username").send_keys("abc123")
driver.find_element_by_name("password").send_keys("123xyz")
driver.find_element_by_name("submit").click()

# storing the cookies
pickle.dump( driver.get_cookies() , open("cookies.pkl","wb"))
driver.quit()

以后如果你想让用户自动登录,你需要先浏览到特定的域/url然后你必须添加cookie如下:

from selenium import webdriver
import pickle

driver = webdriver.Chrome()
driver.get('http://demo.guru99.com/test/cookie/selenium_aut.php')

# loading the stored cookies
cookies = pickle.load(open("cookies.pkl", "rb"))
for cookie in cookies:
    # adding the cookies to the session through webdriver instance
    driver.add_cookie(cookie)
driver.get('http://demo.guru99.com/test/cookie/selenium_cookie.php')

额外考虑

您似乎在使用 chrome=77.0.3865.75。理想情况下,您需要确保:


参考

您可以在以下位置找到详细讨论:

  • Error when loading cookies into a Python request session

在 selenium 中我们必须使用测试服务器的 URL 默认情况下这是 localhost,以启用对外部可访问服务器地址的访问,该地址是我们需要使用的托管 docker 容器的地址服务器机器的IP地址, 所以设置如下,

class BaseTestCase(StaticLiveServerTestCase):
"""
Provides base test class which connects to the Docker
container running Selenium.
"""
host = '0.0.0.0'  # Bind to 0.0.0.0 to allow external access

@classmethod
def setUpClass(cls):
    super().setUpClass()
    # Set host to externally accessible web server address
    cls.host = socket.gethostbyname(socket.gethostname())

引用here

我运行遇到了同样的问题。我的解决方案只是避免在 cookie 中设置 domain 值(wich is optional,顺便说一句)。

    class MyTestCase(StaticLiveServerTestCase):
        host = os.environ['DJANGO_CONTAINER_NAME']

        def test_logged_in(self):
            self.client.login(username="integration", password="test")
            self.selenium.get(self.live_server_url)
            self.selenium.add_cookie({"name": settings.SESSION_COOKIE_NAME, 
                                    "value": self.client.cookies[settings.SESSION_COOKIE_NAME].value})
            post = Post.objects.first()
            self.selenium.get(f"{self.live_server_url}{reverse('post', args=(post.slug, ))}")

这里的要点是让 Django 客户端(此处 self.client)登录,然后将其会话 cookie 复制到 Selenium 浏览器会话,该会话应该已经从您的实时服务器访问过一个页面 - 在其他情况下话说,先让Selenium浏览器打开一个页面,然后设置cookie(跳过domain),然后,selenium浏览器就登录了。