Package: zeit.nightwatch
zeit.nightwatchpytest helpers for http smoke testsMaking HTTP requestszeit.nightwatch.Browserwraps arequestsSessionto provide some convenience features:Instantiate with a base url, and then only use paths:http =Browser('https://example.com');http.get('/foo')will requesthttps://example.com/fooA conveniencehttpfixture is provided, which can be configured via thenightwatch_configfixture.Use call instead of get, because it’s just thatlittle bitshorter.
(http('/foo')instead ofhttp.get('/foo'))Fill and submit forms, powered bymechanicalsoup.
(We’ve customized this a bit, so that responses are only parsed with beautifulsoup if a feature like forms or links is actually used.)Logs request and response headers, so pytest prints these on test failures, to help debugging.Usesso_login(username, password)to log intohttps://meine.zeit.de.See source code for specific API details.Example usage:@pytest.fixture(scope='session')
def nightwatch_config():
    return dict(browser=dict(
        baseurl='https://example.com',
        sso_url='https://meine.zeit.de/anmelden',
    ))

def test_my_site(http):
    r = http.get('/something')
    assert r.status_code == 200

def test_login(http):
    http('/login')
    http.select_form()
    http.form['username'] = 'joe@example.com'
    http.form['password'] = 'secret'
    r = http.submit()
    assert '/home' in r.url

def test_meinezeit_redirects_to_konto_after_login(http):
    r = http.sso_login('joe@example.com', 'secret')
    assert r.url == 'https://www.zeit.de/konto'Examining HTML responsesnightwatch adds two helper methods to therequests.Responseobject:xpath(): parses the response withlxml.htmland then callsxpath()on that documentcss(): converts the selector to xpath usingcssselectand then callsxpath()Example usage:def test_error_page_contains_home_link(http):
    r = http('/nonexistent')
    assert r.status_code == 404
    assert r.css('a.home')Controlling a browser with Seleniumzeit.nightwatch.WebDriverChromeinherits fromselenium.webdriver.Chrometo provide some convenience features:Instantiate with a base url, and then only use paths:browser =WebDriverChrome('https://example.com');browser.get('/foo')A convenienceseleniumfixture is provided, which can be configured via thenightwatch_configfixture.wait()wrapsWebDriverWaitand convertsTimeoutException` into an ``AssertionErrorUsesso_login(username, password)to log intohttps://meine.zeit.deSee source code for specific API details.nightwatch also declares a pytest commandline option--selenium-visibleto help toggling headless mode,
and adds aseleniummark to all tests that use aseleniumfixture, so you can (de)select them withpytest-mselenium(or-m'not selenium').
Since you’ll probably want to set a base url, you have to provide this fixture yourself.Example usage:@pytest.fixture(scope='session')
def nightwatch_config():
    return dict(selenium=dict(
        baseurl='https://example.com',
    ))

def test_js_based_video_player(selenium):
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    s = selenium
    s.get('/my-video')
    s.wait(EC.presence_of_element_located((By.CLASS_NAME, 'videoplayer')))Advanced usecase: To intercept/modify browser requests withselenium-wire, install that package (e.g.pip installselenium-wire) and setdriver_class=ProxiedWebDriverChromein the nightwatchseleniumconfig:@pytest.fixture(scope='session')
def nightwatch_config():
    return dict(selenium=dict(
        baseurl='https://example.com',
        driver_class='ProxiedWebDriverChrome',
    ))

def test_inject_authorization_header(selenium):
    s = selenium
    s.request_interceptor = lambda x: r.headers['authorization'] = 'Bearer MYTOKEN'
    s.get('/protected-page')Controlling a browser with playwrightAs an alternative to Selenium (above) nightwatch also supports playwright;
mostly by pulling in thepytest-playwrightplugin, so you can use their fixtures, with some convenience features:Configure a base url, and then only use paths:page.goto('/foo')Example usage:@pytest.fixture(scope='session')
def nightwatch_config():
    return dict(selenium=dict(
        baseurl='https://example.com',
    ))

def test_playwright_works(page):
    page.goto('/something')Running against different environmentsTo help with running the same tests against e.g. a staging and production environment, nightwatch declares a pytest commandline option--nightwatch-environment.A pattern we found helpful is using a fixture to provide environment-specific settings, like this:CONFIG_STAGING = {
    'base_url': 'https://staging.example.com',
    'username': 'staging_user',
    'password': 'secret',
}

CONFIG_PRODUCTION = {
    'base_url': 'https://www.example.com',
    'username': 'production_user',
    'password': 'secret2',
}

@pytest.fixture(scope='session')
def nightwatch_config(nightwatch_environment):
    config = globals()['CONFIG_%s' % nightwatch_environment.upper()]
    return dict(environment=nightwatch_environment, browser=config)

def test_some_integration_that_has_no_staging(http, nightwatch_config):
    if nightwatch_config['environment'] != 'production':
        pytest.skip('The xyz integration has no staging')
    r = http('/trigger-xyz')
    assert r.json()['message'] == 'OK'Sending test results to prometheusLike the medieval night watch people who made the rounds checking that doors were locked,
our use case for this library is continuous black box high-level tests that check that main functional areas of our systems are working.For this purpose, we want to integrate the test results with our monitoring system, which is based onPrometheus.
We’ve taken inspiration from thepytest-prometheusplugin, and tweaked it a little to use a stable metric name, so we can write a generic alerting rule.This uses the configuredPushgatewayto record metrics like this (theenvironmentlabel is populated from--nightwatch-environment, see above):nightwatch_check{test="test_error_page_contains_home_link",environment="staging",job="website"}=1  # pass=1, fail=0Clients should set the job name, e.g. like this:def pytest_configure(config):
    config.option.prometheus_job_name = 'website'This functionality is disabled by default, nightwatch declares a pytest commandline option--prometheuswhich has to be present to enable pushing the metrics.
There also are commandline options to override the pushgateway url etc., please see the source code for those details.Sending test results to elasticsearchWe’re running our tests as kubernetes pods, and their stdout/stderr output is captured and sent to elasticsearch.
However the normal pytest output is meant for humans, but is not machine-readable.
Thus we’ve implemented a JSON lines test report format that can be enabled with--json-report=filenameor--json-report=-to directly send to stdout.Here’s an output example, formatted for readability (in reality, each test produces a single JSON line, since that’s what our k8s log processor expects):{
  "time": "2023-12-08T10:37:40.630617+00:00",
  "test_stage": "call",
  "test_class": "smoketest.test_api",
  "test_name": "test_example",
  "test_outcome": "passed",
  "system_log": "11:37:40 INFO  [zeit.nightwatch.requests][MainThread] > POST http://example.com/something\n..."
}zeit.nightwatch changes1.7.1 (2023-12-13)Don’t try to json report if no argument was given1.7.0 (2023-12-08)Implement--json-report=-for line-based output1.6.0 (2022-12-16)Support playwright1.5.1 (2022-06-24)Use non-deprecated selenium API1.5.0 (2022-03-25)Supportselenium-wirein addition toselenium1.4.2 (2022-02-21)ZO-712: Set referer explicitly during sso_login, required for csrf validation1.4.1 (2021-10-27)Include tests & setup in tarball to supportdevpi test1.4.0 (2021-10-26)Add patch to requests1.3.3 (2021-04-01)Support contains instead of equals forfind_link1.3.2 (2021-02-18)Record skipped tests as passed to prometheus, not failed1.3.1 (2021-02-17)Handle same metric name (and testname only as label) correctly1.3.0 (2021-02-17)Allow to configure the test browsers via a config fixture1.2.0 (2021-02-17)Add conveniencenightwatchfixture and toplevel APIAdd first test & fix package setup1.1.0 (2021-02-12)Include prometheus functionality here, to fix pushgateway bug
and support sending the test name as a label.Declare namespace package properly1.0.0 (2021-02-11)Initial release