Skip to content

Fix: Initial sort and query param #637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions docs/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -254,16 +254,16 @@ By setting the query parameter to empty string :code:`?collapsed=""` **none** of

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).
You can also set the collapsed behaviour by setting :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 = failed,error

Controlling Test Result Visibility Via Query Params
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Controlling Test Result Visibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default, all tests are visible, regardless of their results. It is possible to control which tests are visible on
page load by passing the :code:`visible` query parameter. To use this parameter, please pass a comma separated list
Expand All @@ -272,7 +272,7 @@ tests in the report that have outcome :code:`passed` or :code:`skipped`.

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

The following query parameters may be passed:
The following values may be passed:

* :code:`passed`
* :code:`skipped`
Expand All @@ -282,9 +282,29 @@ The following query parameters may be passed:
* :code:`xpassed`
* :code:`rerun`

Results Table Sorting
~~~~~~~~~~~~~~~~~~~~~

You can change the sort order of the results table on page load by passing the :code:`sort` query parameter.

The following values may be passed:

* :code:`result`
* :code:`testId`
* :code:`duration`
* :code:`original`

Note that the values are case *sensitive*.

``original`` means that a best effort is made to sort the table in the order of execution.
If tests are run in parallel (with `pytest-xdist`_ for example), then the order may not be
in the correct order.


.. [email protected](tryfirst=True): https://docs.pytest.org/en/stable/writing_plugins.html#hook-function-ordering-call-example
.. _ansi2html: https://pypi.python.org/pypi/ansi2html/
.. _Content Security Policy (CSP): https://developer.mozilla.org/docs/Web/Security/CSP/
.. _JSON: https://json.org/
.. _pytest-metadata: https://pypi.python.org/pypi/pytest-metadata/
.. _pytest-xdist: https://pypi.python.org/pypi/pytest-xdist/
.. _time.strftime: https://docs.python.org/3/library/time.html#time.strftime
28 changes: 24 additions & 4 deletions src/pytest_html/scripts/sort.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
const { manager } = require('./datamanager.js')
const storageModule = require('./storage.js')

const genericSort = (list, key, ascending) => {
const sorted = list.sort((a, b) => a[key] === b[key] ? 0 : a[key] > b[key] ? 1 : -1)
const genericSort = (list, key, ascending, customOrder) => {
let sorted
if (customOrder) {
sorted = list.sort((a, b) => {
const aValue = a.result.toLowerCase()
const bValue = b.result.toLowerCase()

const aIndex = customOrder.findIndex(item => item.toLowerCase() === aValue)
const bIndex = customOrder.findIndex(item => item.toLowerCase() === bValue)

// Compare the indices to determine the sort order
return aIndex - bIndex
})
} else {
sorted = list.sort((a, b) => a[key] === b[key] ? 0 : a[key] > b[key] ? 1 : -1)
}

if (ascending) {
sorted.reverse()
Expand All @@ -14,8 +28,14 @@ const doInitSort = () => {
const type = storageModule.getSort()
const ascending = storageModule.getSortDirection()
const list = manager.testSubset
const sortedList = genericSort(list, type, ascending)
manager.setRender(sortedList)
const initialOrder = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed', 'Skipped', 'Passed']
console.log(list)
if (type?.toLowerCase() === 'original') {
manager.setRender(list)
} else {
const sortedList = genericSort(list, type, ascending, initialOrder)
manager.setRender(sortedList)
}
}

const doSort = (type) => {
Expand Down
16 changes: 8 additions & 8 deletions src/pytest_html/scripts/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ const getCollapsedCategory = (config) => {
const collapsedItems = new URLSearchParams(url.search).get('collapsed')
switch (true) {
case !config && collapsedItems === null:
categories = ['passed'];
break;
categories = ['passed']
break
case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems):
categories = [];
break;
categories = []
break
case /^all$/.test(collapsedItems) || (collapsedItems === null && /^all$/.test(config)):
categories = [...possibleFilters];
break;
categories = [...possibleFilters]
break
default:
categories = collapsedItems?.split(',').map(item => item.toLowerCase()) || config;
break;
categories = collapsedItems?.split(',').map(item => item.toLowerCase()) || config
break
}
} else {
categories = []
Expand Down
13 changes: 12 additions & 1 deletion testing/unittest.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('Sort tests', () => {
doInitSort()
expect(managerSpy.callCount).to.eql(1)
expect(dataModule.manager.testSubset.map(({ result }) => result)).to.eql([
'passed', 'failed', 'passed', 'passed', 'passed', 'passed',
'failed', 'passed', 'passed', 'passed', 'passed', 'passed',
])
})
it('has stored sort preference', () => {
Expand All @@ -116,6 +116,17 @@ describe('Sort tests', () => {
'failed', 'passed', 'passed', 'passed', 'passed', 'passed',
])
})
it('keeps original test execution order', () => {
sortMock = sinon.stub(storageModule, 'getSort').returns('original')
sortDirectionMock = sinon.stub(storageModule, 'getSortDirection').returns(false)
managerSpy = sinon.spy(dataModule.manager, 'setRender')

doInitSort()
expect(managerSpy.callCount).to.eql(1)
expect(dataModule.manager.testSubset.map(({ result }) => result)).to.eql([
'passed', 'failed', 'passed', 'passed', 'passed', 'passed',
])
})
})
describe('doSort', () => {
let getSortMock
Expand Down