Intercepting Sleep Calls in Tests with Qase

Introduction

As we've already covered in the article about Network Profiler, Qase provides powerful tools for monitoring and analyzing test scenarios. In this article, we'll explore another important profiler: Sleep Profiler, which helps identify and optimize the use of delays in tests.

The Problem with Using Sleep in E2E Tests

In E2E (end-to-end) tests, especially when working with UI controls and web applications, developers often use time.sleep() to wait for elements to appear on the page, for animations to complete, or for data to load. This is a simple solution, but it has serious drawbacks:

  • Increased test execution time: Fixed delays always wait for the full duration, even if the element appears earlier
  • Test instability: If an element loads slower than expected, the test may fail
  • Hidden performance issues: It's difficult to understand exactly where tests are spending time waiting
  • Debugging complexity: It's impossible to see all places where delays are used without manually searching through the code

The Right Approach: Conditional Waits

Instead of fixed delays, it's recommended to use smart waits with condition checking. For example, in Playwright this is page.wait_for_selector() ; in Selenium, WebDriverWait with expected_conditions. These mechanisms check the condition periodically and complete as soon as the condition is met, which significantly speeds up tests.

What is Sleep Profiler

Sleep Profiler is a Qase tool that automatically intercepts all time.sleep() calls in your tests and logs them as separate steps. This allows you to:

  • Find all places with delays: See all sleep() calls in one place
  • Measure wait time: Understand how much time is spent on delays
  • Optimize tests: Identify places where sleep() can be replaced with smart waits
  • Analyze performance: Assess the impact of delays on overall test execution time

How Sleep Profiler Works

Sleep Profiler uses Monkey Patching technique to intercept time.sleep() calls. It replaces the standard time.sleep function with its own wrapper that:

  1. Logs the start of the delay with the specified duration
  2. Executes the original time.sleep()
  3. Logs the completion of the delay
  4. Sends delay information to Qase as a separate step

Usage Examples

Basic Example with pytest and Playwright

Let's consider a simple E2E test using Playwright that demonstrates the problem and solution:

❌ Bad Example: Using sleep

import time
from playwright.sync_api import sync_playwright
from qase.pytest import qase


@qase.title("Login Test with Sleep")
def test_login_with_sleep():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()

        with qase.step("Navigate to login page"):
            page.goto("https://the-internet.herokuapp.com/login")

            # ❌ Bad: fixed delay
            time.sleep(2)  # Wait for page to load

        with qase.step("Fill in login form and submit"):
            page.fill("input[type='text']", "tomsmith")
            page.fill("input[type='password']", "SuperSecretPassword!")

            # ❌ Bad: another delay
            time.sleep(1)  # Wait before clicking

        with qase.step("Click login button"):
            page.click("button:has-text('Login')")

            # ❌ Bad: delay to wait for redirect
            time.sleep(3)  # Wait for redirect to secure page

        with qase.step("Verify successful login"):
            assert "/secure" in page.url

        browser.close()

Execution time: ~11 seconds (minimum, even if everything loads faster)

We can see in the result that delays added in each step increase the total test execution time:

✅ Good Example: Using Smart Waits

from playwright.sync_api import sync_playwright
from qase.pytest import qase

@qase.title("Login Test with Smart Waits")
def test_login_with_waits():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        
        with qase.step("Navigate to login page"):
            page.goto("https://the-internet.herokuapp.com/login")
        
            # ✅ Good: wait for element to appear
            page.wait_for_selector("input[type='text']", state="visible")
        
        with qase.step("Fill in login form and submit"):
            page.fill("input[type='text']", "tomsmith")
            page.fill("input[type='password']", "SuperSecretPassword!")
              
        with qase.step("Click login button"):
            # ✅ Good: wait for button to be clickable
            page.wait_for_selector("button:has-text('Login')", state="visible")
            page.click("button:has-text('Login')")
        
            # ✅ Good: wait for navigation
            page.wait_for_url("**/secure")
        
        with qase.step("Verify successful login"):
            assert "/secure" in page.url
        
        browser.close()

Execution time: ~4 seconds (completes as soon as conditions are met)

We can see that using smart waits significantly reduced the test execution time:

Getting Reports with Sleep Profiler

After running tests with Sleep Profiler enabled, you'll receive a detailed report in Qase where each time.sleep() call is displayed as a separate step with the duration specified. This makes it easy to analyze and optimize the use of delays in your tests.

Configuration

To enable Sleep Profiler in your tests, you can use two approaches: via command line or via the qase.config.json configuration file.

Enabling via Command Line

# Enable only Sleep Profiler
pytest --qase-profilers=sleep

# Combine with other profilers
pytest --qase-profilers=sleep,network,db

Configuration via qase.config.json File

{
    "mode": "testops",
    "profilers": ["sleep"],
    "testops": {
        "api": {
            "host": "qase.io"
        }
    }
}

Optimization Recommendations

After Sleep Profiler has helped you find all places with sleep(), it's recommended to:

  1. Replace with smart waits: Use wait_for_selector(), wait_for_url(), and similar methods
  2. Use timeouts: Set reasonable timeouts for waits (usually 5-10 seconds)
  3. Check conditions: Instead of waiting for time, wait for conditions to be met
  4. Monitor performance: Regularly check Sleep Profiler reports to identify new issues

Conclusion

Sleep Profiler is a powerful tool for optimizing E2E tests. It helps identify all places where fixed delays are used and assess their impact on test execution time. By using Sleep Profiler in combination with smart waits, you can significantly speed up your tests and make them more stable.