# 4. Writing Tests with Pylenium

## Create a Test File

A **Test File** is just that - a file with tests in it. Depending on the type of project you're working on, you may want these to live right next to your code files or in a separate <mark style="color:yellow;">**`/tests`**</mark> directory.

{% hint style="info" %}
In these docs, we will assume you are writing your tests in a `/tests` directory of your project.
{% endhint %}

Create a Test File called `test_qap_dev.py`

* Test Files do not need to start with `test_`, but it's recommended
* This is a naming convention used to make it easier to distinguish between code and tests

You should now have a Project Structure that looks like this:

* Project
  * tests
    * test\_qap\_dev.py
  * conftest.py
  * pylenium.json
  * pytest.ini
  * venv

## Write the Test

We are going to make a test that does the following:

1. *Visits* the **QA at the Point** website: <https://qap.dev>
2. *Hovers* the **About** link to reveal a menu
3. *Click* the **Leadership** link in that menu
4. *Assert* **Carlos Kidman** is on the Leadership page

{% code title="test\_qap\_dev.py" %}

```python
def test_carlos_is_on_leadership(py):
    py.
```

{% endcode %}

When you type `py.`, you should see an **auto-complete** or **IntelliSense** menu appear with the list of [Pylenium Commands](/driver-commands/commands.md) like `.visit()` and `.get()`

{% hint style="warning" %}
&#x20;Your IDE may not do this or you may be missing an Extension or Plugin.

PyCharm has [pytest support](/getting-started/setup-pytest.md) out-of-the-box.
{% endhint %}

Let's move on with the steps.

* Visit <https://qap.dev>

{% code title="test\_qap\_dev.py" %}

```bash
def test_carlos_is_on_leadership(py):
    py.visit("https://qap.dev")
```

{% endcode %}

* Hover the **About** link to reveal a menu

{% code title="test\_qap\_dev.py" %}

```python
def test_carlos_is_on_leadership(py):
    py.visit("https://qap.dev")
    py.get("a[href='/about']").hover()
```

{% endcode %}

{% hint style="info" %}
When you get an Element from locator methods:

* `.get()  | .getx()`
* `.find() | .findx()`
* `.contains()`

you can perform actions against the element like:

* `.click()`
* `.type()`
* `.hover()`
* `and more!`
  {% endhint %}

{% hint style="success" %}
Make sure to check out the many commands available in Pylenium
{% endhint %}

* Click the **Leadership** link in the menu

{% code title="test\_qap\_dev.py" %}

```python
def test_carlos_is_on_leadership(py):
    py.visit("https://qap.dev")
    py.get("a[href='/about']").hover()
    py.get("a[href='/leadership'][class^='Header-nav']").click()
```

{% endcode %}

* Assert **Carlos Kidman** is on the Leadership page

{% code title="test\_qap\_dev.py" %}

```python
def test_carlos_is_on_leadership(py):
    py.visit("https://qap.dev")
    py.get("a[href='/about']").hover()
    py.get("a[href='/leadership'][class^='Header-nav']").click()
    assert py.contains("Carlos Kidman")
```

{% endcode %}

## Run the Test

If you're using PyCharm or VS Code, there should be a green **Play** button next to the test definition. Click it and select either **Run** to execute normally or **Debug** to use breakpoints in Debug Mode.

Otherwise, use the method your IDE provides. You can always use the CLI as well:

{% code title="Terminal $ (venv)" %}

```bash
pytest tests/test_qap_dev.py
```

{% endcode %}

### Look at the Difference

Here is the same test but written with Selenium out of the box:

```bash
# Define your setup and teardown fixture
@pytest.fixture
def driver():
    driver = webdriver.Chrome()
    yield driver
    driver.quit()


def test_carlos_is_on_leadership_page_with_selenium(driver):
    driver.get("https://qap.dev")
    
    # Hover About link
    about_link = driver.find_element(By.CSS_SELECTOR, "a[href='/about']")
    actions = ActionChains(driver)
    actions.move_to_element(about_link).perform()
    
    # Click Leadership link in About menu
    driver.find_element(By.CSS_SELECTOR, "a[href='/leadership'][class^='Header-nav']").click()
    
    # Check if 'Carlos Kidman' is on the page
    assert driver.find_element(By.XPATH, "//*[contains(text(), 'Carlos Kidman')]")
```

## Another Test Example

Let's write another test that searches for `Pylenium` and makes sure the results page contains that term in the title.

1. Navigate to Google.com
2. Type `Pylenium` into the search field
3. Submit the search
4. Assert the results page contains the title

```python
def test_google_search(py):
    py.visit("https://google.com")
    py.get("[name='q']").type("Pylenium")
    py.get("[name='btnK']").submit()
    assert py.should().contain_title("Pylenium")
```

You've already seen different Element commands like <mark style="color:yellow;">**`.visit()`**</mark>, <mark style="color:yellow;">**`.type()`**</mark> and <mark style="color:yellow;">**`.submit()`**</mark>,  but there is also a *Should* object for:

* [Element](/element-commands/should.md)
* [Elements](/element-commands/should.md)
* [Pylenium](/driver-commands/should.md)

In the example above, <mark style="color:yellow;">**`py.should()`**</mark> uses an Explicit Wait to wait until the "driver" detects that the current page's title contains `"Pylenium"`.&#x20;

* If the title contains `"Pylenium"` within the specified timeout, then it returns `True` and passes the assertion
* If the title does not meet the expectation within the specified timeout, then it returns `False` and fails the assertion

{% hint style="success" %}
You can leverage these *Should* expectations to easily wait for conditions or write assertions!
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pylenium.io/getting-started/writing-tests-with-pylenium.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
