From ff7cc3280f70e3cc3791eb8e6a5723555a59529e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jim=20Br=C3=A4nnlund?= Date: Wed, 26 Jan 2022 10:12:02 +0100 Subject: [PATCH] Update next-gen with recent changes to master (#494) * remove phantomjs dependency (#424) * properly classify all npm dependencies (#425) * Move the changelog to read the docs (#423) * split plugin.py into smaller files (#427) * Implement the visible URL query parameter to control visibility of test results on page load. (#433) * enable control of test result visability via query params * Allow for redacting of environment table values (#431) * Disable Codecov (#480) * Disable Codecov * Disable pypy3 on mac * Add Tests.yml reusable workflow (#484) * Use the tests reusable workflow (#486) * Migrate to precommit.ci (#487) * Separate Nightly workflow (#488) Co-authored-by: Gleb Nikonorov Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/actions.yml | 147 +-------------- .github/workflows/nightly.yml | 9 + .github/workflows/tests.yml | 119 +++++++++++++ .pre-commit-config.yaml | 14 +- pyproject.toml | 1 - src/pytest_html/html_report.py | 2 +- src/pytest_html/plugin.py | 2 +- src/pytest_html/resources/index.html | 14 +- src/pytest_html/resources/main.js | 10 +- src/pytest_html/resources/old_main.js | 246 ++++++++++++++++++++++++++ testing/js_test_report.html | 2 +- testing/test_pytest_html.py | 2 +- 12 files changed, 404 insertions(+), 164 deletions(-) create mode 100644 .github/workflows/nightly.yml create mode 100644 .github/workflows/tests.yml create mode 100644 src/pytest_html/resources/old_main.js diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 74b4257e..6b4a4e36 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -1,4 +1,4 @@ -name: gh +name: Main on: create: # is used for publishing to PyPI and TestPyPI @@ -12,13 +12,11 @@ on: - >- ** pull_request: - schedule: - - cron: 1 0 * * * # Run daily at 0:01 UTC jobs: build_docs: name: Build Docs - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Set up Python @@ -26,149 +24,18 @@ jobs: with: python-version: 3.6 - name: Install tox - run: | - python -m pip install --upgrade tox + run: python -m pip install --upgrade tox - name: Build docs with tox - run: | - python -m tox -e docs - build_python: - name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: ubuntu-18.04 - name: py36-ubuntu - python-version: 3.6 - - - os: windows-latest - name: py36-windows - python-version: 3.6 - - - os: macOS-latest - name: py36-mac - python-version: 3.6 - - - os: ubuntu-18.04 - name: py37-ubuntu - python-version: 3.7 - - - os: windows-latest - name: py37-windows - python-version: 3.7 - - - os: macOS-latest - name: py37-mac - python-version: 3.7 - - - os: ubuntu-18.04 - name: py38-ubuntu - python-version: 3.8 - - - os: windows-latest - name: py38-windows - python-version: 3.8 - - - os: macOS-latest - name: py38-mac - python-version: 3.8 + run: python -m tox -e docs - - os: ubuntu-18.04 - name: py39-ubuntu - python-version: 3.9 + tests: + uses: pytest-dev/pytest-html/.github/workflows/tests.yml@master - - os: windows-latest - name: py39-windows - python-version: 3.9 - - - os: macOS-latest - name: py39-mac - python-version: 3.9 - - - os: ubuntu-18.04 - name: pypy3-ubuntu - python-version: pypy3 - - - os: windows-latest - name: pypy3-windows - python-version: pypy3 - - - os: macOS-latest - name: pypy3-mac - python-version: pypy3 - - - os: ubuntu-18.04 - name: devel-ubuntu - python-version: 3.8 - - steps: - - name: Set Newline Behavior - run : | - git config --global core.autocrlf false - - uses: actions/checkout@master - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix['python-version'] }} - - name: Install tox - run: | - python -m pip install --upgrade tox - - name: Get Tox Environment Name From Matrix Name - uses: rishabhgupta/split-by@v1 - id: split-matrix-name - with: - string: '${{ matrix.name }}' - split-by: '-' - - name: Test with tox - run: | - python -m tox -e ${{ steps.split-matrix-name.outputs._0}}-cov - - name: Upload coverage to codecov - uses: codecov/codecov-action@v1 - with: - fail_ci_if_error: true - file: ./coverage.xml - flags: tests - name: ${{ matrix.py }} - ${{ matrix.os }} - verbose: true - build_javascript: - name: grunt - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Install Dependencies - run: | - npm install - - name: QUnit Tests - run: | - npm test - env: - CI: true - linting: - name: linting - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@master - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.6 - - name: Install tox - run: | - python -m pip install --upgrade tox - - name: Lint with tox - run: | - python -m tox -e linting publish: name: Publish to PyPI registry needs: - - build_python - - build_javascript + - tests runs-on: ubuntu-latest - env: PY_COLORS: 1 TOXENV: packaging diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..d97d3156 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,9 @@ +name: Nightly tests + +on: + schedule: + - cron: '1 0 * * *' # Run daily at 0:01 UTC + +jobs: + tests: + uses: pytest-dev/pytest-html/.github/workflows/tests.yml@master diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..42afa78d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,119 @@ +name: Tests + +on: + workflow_call: + +jobs: + test_python: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + name: py36-ubuntu + python-version: 3.6 + + - os: windows-latest + name: py36-windows + python-version: 3.6 + + - os: macOS-latest + name: py36-mac + python-version: 3.6 + + - os: ubuntu-latest + name: py37-ubuntu + python-version: 3.7 + + - os: windows-latest + name: py37-windows + python-version: 3.7 + + - os: macOS-latest + name: py37-mac + python-version: 3.7 + + - os: ubuntu-latest + name: py38-ubuntu + python-version: 3.8 + + - os: windows-latest + name: py38-windows + python-version: 3.8 + + - os: macOS-latest + name: py38-mac + python-version: 3.8 + + - os: ubuntu-latest + name: py39-ubuntu + python-version: 3.9 + + - os: windows-latest + name: py39-windows + python-version: 3.9 + + - os: macOS-latest + name: py39-mac + python-version: 3.9 + + - os: ubuntu-latest + name: pypy3-ubuntu + python-version: pypy3 + + - os: windows-latest + name: pypy3-windows + python-version: pypy3 + + # https://github.com/pytest-dev/pytest-html/issues/482 +# - os: macOS-latest +# name: pypy3-mac +# python-version: pypy3 + + - os: ubuntu-latest + name: devel-ubuntu + python-version: 3.9 + + steps: + - name: Set Newline Behavior + run : git config --global core.autocrlf false + - uses: actions/checkout@master + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix['python-version'] }} + - name: Install tox + run: python -m pip install --upgrade tox + - name: Get Tox Environment Name From Matrix Name + uses: rishabhgupta/split-by@v1 + id: split-matrix-name + with: + string: '${{ matrix.name }}' + split-by: '-' + - name: Test with tox + run: python -m tox -e ${{ steps.split-matrix-name.outputs._0}}-cov + # TODO: https://github.com/pytest-dev/pytest-html/issues/481 +# - name: Upload coverage to codecov +# if: github.event.schedule == '' +# uses: codecov/codecov-action@v2 +# with: +# fail_ci_if_error: true +# file: ./coverage.xml +# flags: tests +# name: ${{ matrix.py }} - ${{ matrix.os }} +# verbose: true + + test_javascript: + name: grunt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: '12.x' + - name: Install Dependencies + run: npm install + - name: QUnit Tests + run: npm test diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b5757483..dcbc8a52 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,13 +37,13 @@ repos: hooks: - id: pyupgrade args: [--py3-plus] - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v7.13.0 - hooks: - - id: eslint - additional_dependencies: - - eslint@7.13.0 - args: [src] +# - repo: https://github.com/pre-commit/mirrors-eslint +# rev: v7.13.0 +# hooks: +# - id: eslint +# additional_dependencies: +# - eslint@7.13.0 +# args: [src] - repo: local hooks: - id: rst diff --git a/pyproject.toml b/pyproject.toml index 512272eb..2683f072 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,4 +11,3 @@ build-backend = "setuptools.build_meta" [tool.setuptools_scm] local_scheme = "no-local-version" write_to = "src/pytest_html/__version.py" - diff --git a/src/pytest_html/html_report.py b/src/pytest_html/html_report.py index 66e10f07..28afe823 100644 --- a/src/pytest_html/html_report.py +++ b/src/pytest_html/html_report.py @@ -178,7 +178,7 @@ def _generate_report(self, session): ] with open( - os.path.join(os.path.dirname(__file__), "resources", "main.js") + os.path.join(os.path.dirname(__file__), "resources", "old_main.js") ) as main_js_fp: main_js = main_js_fp.read() diff --git a/src/pytest_html/plugin.py b/src/pytest_html/plugin.py index 3d79860e..3961bcde 100644 --- a/src/pytest_html/plugin.py +++ b/src/pytest_html/plugin.py @@ -4,12 +4,12 @@ import os import pytest +from _pytest.pathlib import Path from . import extras # noqa: F401 from .html_report import HTMLReport from .nextgen import NextGenReport -from _pytest.pathlib import Path def pytest_addhooks(pluginmanager): from . import hooks diff --git a/src/pytest_html/resources/index.html b/src/pytest_html/resources/index.html index 417809e0..f75cf531 100644 --- a/src/pytest_html/resources/index.html +++ b/src/pytest_html/resources/index.html @@ -64,17 +64,17 @@

Environment

Summary

(Un)check the boxes to filter the results.

- - + + - - + + - +
@@ -86,7 +86,7 @@

Summary

Results

- +
@@ -97,4 +97,4 @@

Results

- \ No newline at end of file + diff --git a/src/pytest_html/resources/main.js b/src/pytest_html/resources/main.js index 9419fe76..63c26498 100644 --- a/src/pytest_html/resources/main.js +++ b/src/pytest_html/resources/main.js @@ -61,8 +61,8 @@ function addCollapse() { const resulttable = find('table#results-table'); const showhideall = document.createElement('p'); showhideall.innerHTML = - 'Show all details / ' + - 'Hide all details'; + 'Show all details / ' + + 'Hide all details'; resulttable.parentElement.insertBefore(showhideall, resulttable); // Add show/hide link to each result @@ -82,9 +82,9 @@ function addCollapse() { elem.addEventListener('click', function (event) { if ( - event.currentTarget.parentNode.nextElementSibling.classList.contains( - 'collapsed' - ) + event.currentTarget.parentNode.nextElementSibling.classList.contains( + 'collapsed' + ) ) { showExtras(event.currentTarget); } else { diff --git a/src/pytest_html/resources/old_main.js b/src/pytest_html/resources/old_main.js new file mode 100644 index 00000000..f26513c9 --- /dev/null +++ b/src/pytest_html/resources/old_main.js @@ -0,0 +1,246 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +function toArray(iter) { + if (iter === null) { + return null; + } + return Array.prototype.slice.call(iter); +} + +function find(selector, elem) { // eslint-disable-line no-redeclare + if (!elem) { + elem = document; + } + return elem.querySelector(selector); +} + +function findAll(selector, elem) { + if (!elem) { + elem = document; + } + return toArray(elem.querySelectorAll(selector)); +} + +function sortColumn(elem) { + toggleSortStates(elem); + const colIndex = toArray(elem.parentNode.childNodes).indexOf(elem); + let key; + if (elem.classList.contains('result')) { + key = keyResult; + } else if (elem.classList.contains('links')) { + key = keyLink; + } else { + key = keyAlpha; + } + sortTable(elem, key(colIndex)); +} + +function showAllExtras() { // eslint-disable-line no-unused-vars + findAll('.col-result').forEach(showExtras); +} + +function hideAllExtras() { // eslint-disable-line no-unused-vars + findAll('.col-result').forEach(hideExtras); +} + +function showExtras(colresultElem) { + const extras = colresultElem.parentNode.nextElementSibling; + const expandcollapse = colresultElem.firstElementChild; + extras.classList.remove('collapsed'); + expandcollapse.classList.remove('expander'); + expandcollapse.classList.add('collapser'); +} + +function hideExtras(colresultElem) { + const extras = colresultElem.parentNode.nextElementSibling; + const expandcollapse = colresultElem.firstElementChild; + extras.classList.add('collapsed'); + expandcollapse.classList.remove('collapser'); + expandcollapse.classList.add('expander'); +} + +function showFilters() { + let visibleString = getQueryParameter('visible') || 'all'; + visibleString = visibleString.toLowerCase(); + const checkedItems = visibleString.split(','); + + const filterItems = document.getElementsByClassName('filter'); + for (let i = 0; i < filterItems.length; i++) { + filterItems[i].hidden = false; + + if (visibleString != 'all') { + filterItems[i].checked = checkedItems.includes(filterItems[i].getAttribute('data-test-result')); + filterTable(filterItems[i]); + } + } +} + +function addCollapse() { + // Add links for show/hide all + const resulttable = find('table#results-table'); + const showhideall = document.createElement('p'); + showhideall.innerHTML = 'Show all details / ' + + 'Hide all details'; + resulttable.parentElement.insertBefore(showhideall, resulttable); + + // Add show/hide link to each result + findAll('.col-result').forEach(function(elem) { + const collapsed = getQueryParameter('collapsed') || 'Passed'; + const extras = elem.parentNode.nextElementSibling; + const expandcollapse = document.createElement('span'); + if (extras.classList.contains('collapsed')) { + expandcollapse.classList.add('expander'); + } else if (collapsed.includes(elem.innerHTML)) { + extras.classList.add('collapsed'); + expandcollapse.classList.add('expander'); + } else { + expandcollapse.classList.add('collapser'); + } + elem.appendChild(expandcollapse); + + elem.addEventListener('click', function(event) { + if (event.currentTarget.parentNode.nextElementSibling.classList.contains('collapsed')) { + showExtras(event.currentTarget); + } else { + hideExtras(event.currentTarget); + } + }); + }); +} + +function getQueryParameter(name) { + const match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); + return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); +} + +function init () { // eslint-disable-line no-unused-vars + resetSortHeaders(); + + addCollapse(); + + showFilters(); + + sortColumn(find('.initial-sort')); + + findAll('.sortable').forEach(function(elem) { + elem.addEventListener('click', + function() { + sortColumn(elem); + }, false); + }); +} + +function sortTable(clicked, keyFunc) { + const rows = findAll('.results-table-row'); + const reversed = !clicked.classList.contains('asc'); + const sortedRows = sort(rows, keyFunc, reversed); + /* Whole table is removed here because browsers acts much slower + * when appending existing elements. + */ + const thead = document.getElementById('results-table-head'); + document.getElementById('results-table').remove(); + const parent = document.createElement('table'); + parent.id = 'results-table'; + parent.appendChild(thead); + sortedRows.forEach(function(elem) { + parent.appendChild(elem); + }); + document.getElementsByTagName('BODY')[0].appendChild(parent); +} + +function sort(items, keyFunc, reversed) { + const sortArray = items.map(function(item, i) { + return [keyFunc(item), i]; + }); + + sortArray.sort(function(a, b) { + const keyA = a[0]; + const keyB = b[0]; + + if (keyA == keyB) return 0; + + if (reversed) { + return keyA < keyB ? 1 : -1; + } else { + return keyA > keyB ? 1 : -1; + } + }); + + return sortArray.map(function(item) { + const index = item[1]; + return items[index]; + }); +} + +function keyAlpha(colIndex) { + return function(elem) { + return elem.childNodes[1].childNodes[colIndex].firstChild.data.toLowerCase(); + }; +} + +function keyLink(colIndex) { + return function(elem) { + const dataCell = elem.childNodes[1].childNodes[colIndex].firstChild; + return dataCell == null ? '' : dataCell.innerText.toLowerCase(); + }; +} + +function keyResult(colIndex) { + return function(elem) { + const strings = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed', + 'Skipped', 'Passed']; + return strings.indexOf(elem.childNodes[1].childNodes[colIndex].firstChild.data); + }; +} + +function resetSortHeaders() { + findAll('.sort-icon').forEach(function(elem) { + elem.parentNode.removeChild(elem); + }); + findAll('.sortable').forEach(function(elem) { + const icon = document.createElement('div'); + icon.className = 'sort-icon'; + icon.textContent = 'vvv'; + elem.insertBefore(icon, elem.firstChild); + elem.classList.remove('desc', 'active'); + elem.classList.add('asc', 'inactive'); + }); +} + +function toggleSortStates(elem) { + //if active, toggle between asc and desc + if (elem.classList.contains('active')) { + elem.classList.toggle('asc'); + elem.classList.toggle('desc'); + } + + //if inactive, reset all other functions and add ascending active + if (elem.classList.contains('inactive')) { + resetSortHeaders(); + elem.classList.remove('inactive'); + elem.classList.add('active'); + } +} + +function isAllRowsHidden(value) { + return value.hidden == false; +} + +function filterTable(elem) { // eslint-disable-line no-unused-vars + const outcomeAtt = 'data-test-result'; + const outcome = elem.getAttribute(outcomeAtt); + const classOutcome = outcome + ' results-table-row'; + const outcomeRows = document.getElementsByClassName(classOutcome); + + for(let i = 0; i < outcomeRows.length; i++){ + outcomeRows[i].hidden = !elem.checked; + } + + const rows = findAll('.results-table-row').filter(isAllRowsHidden); + const allRowsHidden = rows.length == 0 ? true : false; + const notFoundMessage = document.getElementById('not-found-message'); + notFoundMessage.hidden = !allRowsHidden; +} diff --git a/testing/js_test_report.html b/testing/js_test_report.html index 5b4fae82..205fab29 100644 --- a/testing/js_test_report.html +++ b/testing/js_test_report.html @@ -12,7 +12,7 @@ - +
diff --git a/testing/test_pytest_html.py b/testing/test_pytest_html.py index 69341caf..aaa7bd2e 100644 --- a/testing/test_pytest_html.py +++ b/testing/test_pytest_html.py @@ -369,7 +369,7 @@ def test_resources(self, testdir): assert result.ret == 0 content = pkg_resources.resource_string( - "pytest_html", os.path.join("resources", "main.js") + "pytest_html", os.path.join("resources", "old_main.js") ) content = content.decode("utf-8") assert content