Skip to content

Commit

Permalink
fix: Collapsed should support All and none
Browse files Browse the repository at this point in the history
  • Loading branch information
BeyondEvil committed Mar 28, 2023
1 parent 34ff60f commit d353a0f
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 34 deletions.
14 changes: 9 additions & 5 deletions docs/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,19 @@ Auto Collapsing Table Rows

By default, all rows in the **Results** table will be expanded except those that have :code:`Passed`.

This behavior can be customized either with a query parameter: :code:`?collapsed=Passed,XFailed,Skipped`
or by setting the :code:`render_collapsed` in a configuration file (pytest.ini, setup.cfg, etc).
This behavior can be customized with a query parameter: :code:`?collapsed=Passed,XFailed,Skipped`.
If you want all rows to be collapsed you can pass :code:`?collapsed=All`.
By setting the query parameter to empty string :code:`?collapsed=""` **none** of the rows will be collapsed.

Note that the query parameter is case insensitive, so passing :code:`PASSED` and :code:`passed` has the same effect.

You can also set the collapsed behaviour by setting the :code:`render_collapsed` in a configuration file (pytest.ini, setup.cfg, etc).
Note that the query parameter takes precedence.

.. code-block:: ini
[pytest]
render_collapsed = True
**NOTE:** Setting :code:`render_collapsed` will, unlike the query parameter, affect all statuses.
render_collapsed = failed,error
Controlling Test Result Visibility Via Query Params
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 4 additions & 0 deletions src/pytest_html/nextgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ def __init__(self, title, config):
"additionalSummary": defaultdict(list),
}

collapsed = config.getini("render_collapsed")
if collapsed:
self.set_data("collapsed", collapsed.split(","))

@property
def title(self):
return self._data["title"]
Expand Down
4 changes: 2 additions & 2 deletions src/pytest_html/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def pytest_addoption(parser):
)
parser.addini(
"render_collapsed",
type="bool",
default=False,
type="string",
default="",
help="Open the report with all rows collapsed. Useful for very large reports",
)
parser.addini(
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_html/scripts/datamanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { getCollapsedCategory } = require('./storage.js')

class DataManager {
setManager(data) {
const collapsedCategories = [...getCollapsedCategory(), 'passed']
const collapsedCategories = [...getCollapsedCategory(data.collapsed)]
const dataBlob = { ...data, tests: Object.values(data.tests).flat().map((test, index) => ({
...test,
id: `test_${index}`,
Expand Down
12 changes: 1 addition & 11 deletions src/pytest_html/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { dom, findAll } = require('./dom.js')
const { manager } = require('./datamanager.js')
const { doSort } = require('./sort.js')
const { doFilter } = require('./filter.js')
const { getVisible } = require('./storage.js')
const { getVisible, possibleResults } = require('./storage.js')

const removeChildren = (node) => {
while (node.firstChild) {
Expand Down Expand Up @@ -61,16 +61,6 @@ const renderContent = (tests) => {
}

const renderDerived = (tests, collectedItems, isFinished) => {
const possibleResults = [
{ result: 'passed', label: 'Passed' },
{ result: 'skipped', label: 'Skipped' },
{ result: 'failed', label: 'Failed' },
{ result: 'error', label: 'Errors' },
{ result: 'xfailed', label: 'Unexpected failures' },
{ result: 'xpassed', label: 'Unexpected passes' },
{ result: 'rerun', label: 'Reruns' },
]

const currentFilter = getVisible()
possibleResults.forEach(({ result, label }) => {
const count = tests.filter((test) => test.result.toLowerCase() === result).length
Expand Down
36 changes: 30 additions & 6 deletions src/pytest_html/scripts/storage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
const possibleFilters = ['passed', 'skipped', 'failed', 'error', 'xfailed', 'xpassed', 'rerun']
const possibleResults = [
{ result: 'passed', label: 'Passed' },
{ result: 'skipped', label: 'Skipped' },
{ result: 'failed', label: 'Failed' },
{ result: 'error', label: 'Errors' },
{ result: 'xfailed', label: 'Unexpected failures' },
{ result: 'xpassed', label: 'Unexpected passes' },
{ result: 'rerun', label: 'Reruns' },
]
const possibleFilters = possibleResults.map((item) => item.result)

const getVisible = () => {
const url = new URL(window.location.href)
Expand Down Expand Up @@ -49,16 +58,29 @@ const setSort = (type) => {
history.pushState({}, null, unescape(url.href))
}

const getCollapsedCategory = () => {
let categotries
const getCollapsedCategory = (config) => {
let categories
if (typeof window !== 'undefined') {
const url = new URL(window.location.href)
const collapsedItems = new URLSearchParams(url.search).get('collapsed')
categotries = collapsedItems?.split(',') || []
switch (true) {
case collapsedItems === null:
categories = config || ['passed'];
break;
case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems):
categories = [];
break;
case /^all$/.test(collapsedItems):
categories = [...possibleFilters];
break;
default:
categories = collapsedItems?.split(',').map(item => item.toLowerCase()) || [];
break;
}
} else {
categotries = []
categories = []
}
return categotries
return categories
}

const getSortDirection = () => JSON.parse(sessionStorage.getItem('sortAsc'))
Expand All @@ -75,4 +97,6 @@ module.exports = {
setSort,
setSortDirection,
getCollapsedCategory,
possibleFilters,
possibleResults,
}
122 changes: 113 additions & 9 deletions testing/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import random
import re
import urllib.parse
from base64 import b64encode
from pathlib import Path

Expand All @@ -26,9 +27,16 @@
}


def run(pytester, path="report.html", *args):
def run(pytester, path="report.html", cmd_flags=None, query_params=None):
if cmd_flags is None:
cmd_flags = []

if query_params is None:
query_params = {}
query_params = urllib.parse.urlencode(query_params)

path = pytester.path.joinpath(path)
pytester.runpytest("-s", "--html", path, *args)
pytester.runpytest("--html", path, *cmd_flags)

chrome_options = webdriver.ChromeOptions()
if os.environ.get("CI", False):
Expand All @@ -48,7 +56,7 @@ def run(pytester, path="report.html", *args):
continue
# End workaround

driver.get(f"file:///reports{path}")
driver.get(f"file:///reports{path}?{query_params}")
return BeautifulSoup(driver.page_source, "html.parser")
finally:
driver.quit()
Expand Down Expand Up @@ -91,6 +99,10 @@ def get_text(page, selector):
return get_element(page, selector).string


def is_collapsed(page, test_name):
return get_element(page, f".summary tbody[id$='{test_name}'] .expander")


def get_log(page, test_id=None):
# TODO(jim) move to get_text (use .contents)
if test_id:
Expand Down Expand Up @@ -267,7 +279,7 @@ def pytest_html_report_title(report):

def test_resources_inline_css(self, pytester):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester, "report.html", "--self-contained-html")
page = run(pytester, cmd_flags=["--self-contained-html"])

content = file_content()

Expand Down Expand Up @@ -349,7 +361,7 @@ def pytest_runtest_makereport(item, call):
)

pytester.makepyfile("def test_pass(): pass")
page = run(pytester, "report.html", "--self-contained-html")
page = run(pytester, cmd_flags=["--self-contained-html"])

element = page.select_one(".summary a[class='col-links__extra text']")
assert_that(element.string).is_equal_to("Text")
Expand All @@ -374,7 +386,7 @@ def pytest_runtest_makereport(item, call):
)

pytester.makepyfile("def test_pass(): pass")
page = run(pytester, "report.html", "--self-contained-html")
page = run(pytester, cmd_flags=["--self-contained-html"])

content_str = json.dumps(content)
data = b64encode(content_str.encode("utf-8")).decode("ascii")
Expand Down Expand Up @@ -435,7 +447,7 @@ def pytest_runtest_makereport(item, call):
"""
)
pytester.makepyfile("def test_pass(): pass")
page = run(pytester, "report.html", "--self-contained-html")
page = run(pytester, cmd_flags=["--self-contained-html"])

# element = page.select_one(".summary a[class='col-links__extra image']")
src = f"data:{mime_type};base64,{data}"
Expand Down Expand Up @@ -463,7 +475,7 @@ def pytest_runtest_makereport(item, call):
"""
)
pytester.makepyfile("def test_pass(): pass")
page = run(pytester, "report.html", "--self-contained-html")
page = run(pytester, cmd_flags=["--self-contained-html"])

# element = page.select_one(".summary a[class='col-links__extra video']")
src = f"data:{mime_type};base64,{data}"
Expand All @@ -477,7 +489,7 @@ def pytest_runtest_makereport(item, call):

def test_xdist(self, pytester):
pytester.makepyfile("def test_xdist(): pass")
page = run(pytester, "report.html", "-n1")
page = run(pytester, cmd_flags=["-n1"])
assert_results(page, passed=1)

def test_results_table_hook_insert(self, pytester):
Expand Down Expand Up @@ -624,3 +636,95 @@ def test_no_log(self, test_file, pytester):
assert_that(log).contains("No log output captured.")
for when in ["setup", "test", "teardown"]:
assert_that(log).does_not_match(self.LOG_LINE_REGEX.format(when))


class TestCollapsedQueryParam:
@pytest.fixture
def test_file(self):
return """
import pytest
@pytest.fixture
def setup():
error
def test_error(setup):
assert True
def test_pass():
assert True
def test_fail():
assert False
"""

def test_default(self, pytester, test_file):
pytester.makepyfile(test_file)
page = run(pytester)
assert_results(page, passed=1, failed=1, error=1)

assert_that(is_collapsed(page, "test_pass")).is_true()
assert_that(is_collapsed(page, "test_fail")).is_false()
assert_that(is_collapsed(page, "test_error::setup")).is_false()

@pytest.mark.parametrize("param", ["failed,error", "FAILED,eRRoR"])
def test_specified(self, pytester, test_file, param):
pytester.makepyfile(test_file)
page = run(pytester, query_params={"collapsed": param})
assert_results(page, passed=1, failed=1, error=1)

assert_that(is_collapsed(page, "test_pass")).is_false()
assert_that(is_collapsed(page, "test_fail")).is_true()
assert_that(is_collapsed(page, "test_error::setup")).is_true()

def test_all(self, pytester, test_file):
pytester.makepyfile(test_file)
page = run(pytester, query_params={"collapsed": "all"})
assert_results(page, passed=1, failed=1, error=1)

for test_name in ["test_pass", "test_fail", "test_error::setup"]:
assert_that(is_collapsed(page, test_name)).is_true()

@pytest.mark.parametrize("param", ["", 'collapsed=""', "collapsed=''"])
def test_falsy(self, pytester, test_file, param):
pytester.makepyfile(test_file)
page = run(pytester, query_params={"collapsed": param})
assert_results(page, passed=1, failed=1, error=1)

assert_that(is_collapsed(page, "test_pass")).is_false()
assert_that(is_collapsed(page, "test_fail")).is_false()
assert_that(is_collapsed(page, "test_error::setup")).is_false()

def test_render_collapsed(self, pytester, test_file):
pytester.makeini(
"""
[pytest]
render_collapsed = failed,error
"""
)
pytester.makepyfile(test_file)
page = run(pytester)
assert_results(page, passed=1, failed=1, error=1)

assert_that(is_collapsed(page, "test_pass")).is_false()
assert_that(is_collapsed(page, "test_fail")).is_true()
assert_that(is_collapsed(page, "test_error::setup")).is_true()

def test_render_collapsed_precedence(self, pytester, test_file):
pytester.makeini(
"""
[pytest]
render_collapsed = failed,error
"""
)
test_file += """
def test_skip():
pytest.skip('meh')
"""
pytester.makepyfile(test_file)
page = run(pytester, query_params={"collapsed": "skipped"})
assert_results(page, passed=1, failed=1, error=1, skipped=1)

assert_that(is_collapsed(page, "test_pass")).is_false()
assert_that(is_collapsed(page, "test_fail")).is_false()
assert_that(is_collapsed(page, "test_error::setup")).is_false()
assert_that(is_collapsed(page, "test_skip")).is_true()
Loading

0 comments on commit d353a0f

Please sign in to comment.