Selenium Python Quiz
Ten questions on the decisions this course made and why. Each answer explains the reasoning once you check. The quiz is a self-check; nothing is recorded.
1. Code copied from an old tutorial calls driver.find_element_by_id("email") and fails on Selenium 4.52 with AttributeError. What is the fix?
Selenium 4 replaced the per-strategy helpers with find_element(By.X, value), and 4.3 removed the old ones. Downgrading locks you out of current browsers, and the driver binary has nothing to do with the Python API.
2. You add tests/login_checks.py with a function test_login, but pytest reports "no tests ran". Why?
Discovery is name-based: rename the file to test_login.py. pytest needs no decorator to find a test_ function, and nothing should import test files.
3. wait.until(EC.element_to_be_clickable(By.ID, "save")) raises TypeError. What is wrong?
The condition's single argument is the tuple (By.ID, "save"). Passing two separate arguments is a Python TypeError before any waiting happens. The condition accepts either a locator tuple or an element.
4. A fixture sets driver.implicitly_wait(10) and the tests use WebDriverWait(driver, 15). Some failures take around 20 seconds to report. Why?
Each poll of the explicit wait can block for the implicit timeout, so the combined wait overshoots. The Selenium docs give this exact example. Keep the implicit wait at 0 and use explicit waits.
5. In a yield fixture, the test body raises an AssertionError. What happens to the code after yield?
pytest runs fixture teardown after the test regardless of the outcome. That is why the fixture can replace the try/finally from the first chapter. Teardown is skipped only if the fixture's own setup failed before reaching yield.
6. A test is decorated with @pytest.mark.parametrize("value", ["a", "b", "c"]) and uses the driver fixture. You run pytest --browser chrome --browser firefox. How many test items does it produce?
Parametrisations multiply: three values times two browsers. Each combination is a separate test with its own ID, such as [firefox-b], and its own browser.
7. Why does the course's conftest.py implement pytest_runtest_makereport?
Fixtures do not receive the test outcome. The hook saves it as rep_call on the item, and the fixture reads request.node.rep_call to decide on a screenshot and the grid status. HTML reports come from pytest-html, and the hook retries nothing.
8. In the page object, locators are tuples such as SUBMIT = (By.CSS_SELECTOR, "button[type='submit']"). Why write find_element(*self.SUBMIT)?
* is Python argument unpacking: find_element(*("css selector", "...")) is find_element("css selector", "..."). It adds no waiting, and find_elements is how you get all matches.
9. A test file keeps a module-level list of the users its tests created, and a final test asserts the list has five entries. It passes with -n 0 and fails with -n 4. Why?
xdist uses processes, not threads, and does not guarantee which worker runs which test or in what order. The real problem is that the last test depends on the others; each test should set up and check its own data.
10. A pull request puts the TestingBot key and secret directly into conftest.py "so CI works". What should you ask for instead?
Anything committed, in any file or encoding, is readable by everyone with repository access and stays in the history. Environment variables filled from CI secrets keep credentials out of the code, and a leaked pair should be replaced.
Where to go next#
- Run the suite on more browser and OS combinations with the capabilities generator.
- Grow the page objects into a framework with the Page Object Model course.
- See the same suite in Java in Selenium with Java and TestNG, or compare a different tool in the Playwright course.
- Prepare for interviews with the Selenium interview questions.
You finished Selenium with Python and pytest
Put what you learned into practice. Run your tests on 6100+ real browsers and physical iOS and Android devices.