'What does the exception NoSuchWindowException mean, when I try to access a submit button of a webpage with the webdriver module in Selenium?

I have written a webscraping script that automatically logs into my Email account and sends a message.

Code:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

myPassword = 'XXXXXXXXXXXXXX!'

browser = webdriver.Firefox() # Opens Firefox webbrowser
browser.get('https://protonmail.com/') # Go to protonmail website
loginButton = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "a.btn-ghost:nth-child(1)")))
loginButton.click()
usernameElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#username")))
usernameElem.send_keys("[email protected]")
passwordElem = browser.find_element_by_css_selector("#password")
passwordElem.send_keys(myPassword)
anmeldenButton = browser.find_element_by_css_selector(".button")
anmeldenButton.click()
newMessage = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, "/html/body/div[1]/div[3]/div/div/div[1]/div[2]/button")))
newMessage.click()
addressElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[id^='to-composer']")))
addressElem.send_keys('[email protected]')
subjectElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[id^='subject-composer']")))
subjectElem.send_keys('anySubject')
WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[title='Editor']")))
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#squire"))).send_keys('Test message')
sendButton = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "body > div.app-root > div.composer-container > div > div > div > footer > div > div.button-group.button-group-solid-norm.button-group-medium > button > span")))
sendButton.click()
browser.switch_to.default_content()

I wanted the browser to click the submit button after input of the message.

enter image description here

I have copied the CSS selector of the span element and tried this:

sendButton = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "body > div.app-root > div.composer-container > div > div > div > footer > div > div.button-group.button-group-solid-norm.button-group-medium > button > span")))
sendButton.click()

I get the following error:

selenium.common.exceptions.NoSuchWindowException: Message: Browsing context has been discarded

I am not sure, if I targeted the right element for what I want to achieve. I often struggle to find the right strategy to target an element. What is the best way if there is no id element oder a nice and short css selector? I checked the Selenium docs (https://selenium-python.readthedocs.io/locating-elements.html) but hesitated choosing one of the suggested methods.

This is an HTML snipped fo the submit button:

<footer data-testid="composer:footer" class="composer-actions flex-item-noshrink flex max-w100">
  <div class="flex flex-row-reverse flex-align-self-center w100 ml0-5 mr1-5 pl1-25 pr0-25 mb1">
    <div class="button-group button-group-solid-norm button-group-medium" data-testid="composer:send-actions"><button class="button button-group-item button-ghost-weak composer-send-button" aria-busy="false" type="button" data-testid="composer:send-button" aria-describedby="tooltip-19621"><svg viewBox="0 0 16 16" class="icon-16p no-desktop no-tablet on-mobile-flex" role="img" focusable="false"><use xlink:href="#ic-paper-plane"></use></svg><span class="pl1 pr1 no-mobile">Senden</span></button></div>
    <div
      class="flex flex-item-fluid">
      <div class="flex"><button class="button button-for-icon button-ghost-weak mr0-5" aria-busy="false" type="button" data-testid="composer:delete-draft-button" aria-describedby="tooltip-19622"><svg viewBox="0 0 16 16" class="icon-16p" role="img" focusable="false"><use xlink:href="#ic-trash"></use></svg><span class="sr-only">Entwurf löschen</span></button>
        <button
          class="button button-for-icon button-ghost-weak mr0-5" aria-busy="false" type="button" data-testid="composer:password-button" aria-pressed="false" aria-describedby="tooltip-19623"><svg viewBox="0 0 16 16" class="icon-16p" role="img" focusable="false"><use xlink:href="#ic-lock"></use></svg><span class="sr-only">Verschlüsselung</span></button><button aria-expanded="false" aria-busy="false" data-testid="dropdown-button" class="editor-toolbar-button interactive composer-toolbar-fontDropDown max-w100 flex flex-align-items-center flex-nowrap button button-for-icon composer-more-dropdown"
            type="button" tabindex="-1" title="Weitere Optionen" aria-describedby="tooltip-19625"><svg viewBox="0 0 16 16" class="icon-16p" role="img" focusable="false"><use xlink:href="#ic-ellipsis"></use></svg><span class="sr-only">Weitere Optionen</span></button></div>
      <div
        class="flex-item-fluid flex pr1"><span class="mr0-5 mauto no-mobile color-weak">Nicht gespeichert</span>
        <div class="composer-attachments-button-wrapper flex flex-flex-align-items-center"><label class="button button-for-icon button-ghost-weak inline-block text-center inline-flex" aria-busy="false" role="button" data-testid="composer:attachment-button" aria-describedby="tooltip-19626"><svg viewBox="0 0 16 16" class="icon-16p" role="img" focusable="false"><use xlink:href="#ic-paperclip"></use></svg><input type="file" multiple="" class="composer-attachments-button" data-testid="composer-attachments-button"></label></div>
  </div>
  </div>
  </div>
</footer>


Solution 1:[1]

The input field for the email address and the subject is in an iframe. After switching to the iframe

WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[title='Editor']")))

I need to switch back to default content

 browser.switch_to.default_content()

before telling the browser to click on the submit button.

Solution 2:[2]

As per the screenshot:

screenshot

to identify the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.button-group.button-group-solid-norm.button-group-medium > button span"))).click()
    

Solution 3:[3]

I would try to select the button by xpath. I think its way more accurate. If your on chrome or fire fox

right click on the an element on the browser

right click and copy and copy by full xpath

//*[@id="hireme"]/div/ul/li[4]/div/a

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 aurumpurum
Solution 2 undetected Selenium
Solution 3 T_Rex-87 GaMing