├── .env ├── .github ├── ISSUE_TEMPLATE │ └── issue.md └── workflows │ └── main.yml ├── .gitignore ├── .npmignore ├── LICENCE ├── README.md ├── SECURITY.md ├── XunitViewerIcon.png ├── XunitViewerIcon.svg ├── bin └── xunit-viewer.js ├── component └── icon-map.jsx ├── data ├── class_not_classname.xml ├── complete_no_suite.xml ├── complete_no_suite_multi_cases.xml ├── complete_no_suite_single_suite.xml ├── complete_single_case_only.xml ├── complete_single_suite.xml ├── defect_suite.xml ├── duplicate_name_unique_classanme.xml ├── embedded_html_sysout.xml ├── error_suite.xml ├── failing_suite.xml ├── invalid.xml ├── issue_2.xml ├── issue_3.xml ├── lots-of-results.xml ├── malformed.xml ├── most_complex.xml ├── multi-name-unique-classname.xml ├── multi_cases.xml ├── multi_error_test_with_system_out.xml ├── multi_suite.xml ├── name.has.dots.xml ├── nested-nested.xml ├── no_class_name.xml ├── passing_suite.xml ├── properties_in_test_meta.xml ├── pytest_testcase_properties.xml ├── russian-unicode.xml ├── semi-colon.xml ├── skipped_suite.xml ├── special_chars_suite.xml ├── subfolder │ └── _thingy.xml ├── suite-system-out.xml ├── test-system-out.xml ├── test.xml ├── thing.txt ├── utf-16.xml ├── with_html.xml ├── xunit-2-2.xml └── xunit-2.xml ├── example-header.png ├── gh-pages ├── favicon.ico ├── icon.png ├── index.html └── xunit-viewer-results.html ├── index.html ├── junit.xml ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── icon.png └── index.html ├── release.sh ├── sample-usage.js ├── src ├── app │ ├── __snapshots__ │ │ ├── hero.test.js.snap │ │ ├── logo.test.js.snap │ │ ├── properties-options.test.js.snap │ │ ├── suite-options.test.js.snap │ │ ├── test-options.test.js.snap │ │ └── toggle.test.js.snap │ ├── app.js │ ├── error.js │ ├── files.js │ ├── hero.js │ ├── index.css │ ├── initial-state.js │ ├── loading.js │ ├── logo.js │ ├── logo.test.js │ ├── parse-all.js │ ├── parse.js │ ├── properties-options.js │ ├── properties-options.test.js │ ├── reducer.js │ ├── suite-count.js │ ├── suite-options.js │ ├── suite-options.test.js │ ├── suite.js │ ├── test-options.js │ ├── test-options.test.js │ ├── toggle.js │ ├── toggle.test.js │ └── visible.js ├── cli │ ├── args.js │ ├── get-description.js │ ├── get-description.test.js │ ├── get-files.js │ ├── get-files.test.js │ ├── get-suites-expected.json │ ├── get-suites.js │ ├── get-suites.test.js │ ├── index.html │ ├── logger.js │ ├── parse-expected.json │ ├── parse.js │ ├── parse.test.js │ ├── render.js │ ├── server.js │ ├── static │ │ ├── css │ │ │ ├── main.4b451922.css │ │ │ └── main.4b451922.css.map │ │ └── js │ │ │ ├── main.4e6e0818.js │ │ │ ├── main.4e6e0818.js.LICENSE.txt │ │ │ └── main.4e6e0818.js.map │ ├── terminal.js │ ├── update-expected.js │ └── watch.js └── index.js └── xunit-viewer.js /.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue 3 | about: Raise an issue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Raise any issues using GitHub and provide sample data where possible. 11 | 12 | To help debug any issues please provide the following info 13 | 14 | * node and npm version 15 | * xunit viewer version 16 | * browser 17 | * sample xml 18 | 19 | If you have issue migrating from Junit Viewer or older version of Xunit Viewer please feel free to raise an issue titled **MIGRATION HELP** 20 | 21 | There is a `v5` branch which maintained through Open Source PRs, this branch will not maintain `npm audit` issues 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-node@v1 9 | with: 10 | node-version: '12.x' 11 | - run: npm install 12 | - run: npm run lint 13 | - run: npm run test:ci -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # IDEs 4 | .idea 5 | 6 | # dependencies 7 | /node_modules 8 | /.pnp 9 | .pnp.js 10 | 11 | # testing 12 | /coverage 13 | /output 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/__snapshots__ 2 | src/app 3 | src/index.js 4 | data 5 | public 6 | scripts 7 | .env 8 | build 9 | coverage 10 | gh-pages 11 | junit.xml 12 | sample-usage.js 13 | XunitViewerIcon.png 14 | XunitViewerIcon.svg 15 | xunit-viewer-results.html -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Xunit Viewer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xunit Viewer 2 | 3 | Takes all your XUnit and JUnit XML files and makes them readable 4 | 5 | ![Icon](https://raw.githubusercontent.com/lukejpreston/xunit-viewer/master/XunitViewerIcon.png) 6 | 7 | [![npm version](https://badge.fury.io/js/xunit-viewer.svg)](https://badge.fury.io/js/xunit-viewer) 8 | [![Downloads on npm](http://img.shields.io/npm/dm/xunit-viewer.svg)](https://www.npmjs.com/package/xunit-viewer) 9 | [![CI](https://github.com/lukejpreston/xunit-viewer/workflows/CI/badge.svg?branch=master)](https://github.com/lukejpreston/xunit-viewer/actions?query=workflow%3ACI) 10 | 11 | Have a look at the [demo](https://lukejpreston.github.io/xunit-viewer/) 12 | 13 | ## Features 14 | 15 | * Generate an HTML single file with the ability to search, filter 16 | * Render results out to the console, this comes with the ability to search and filter 17 | * Re-run the above when a file changes 18 | * Start a server with WebSockets to keep the browser in sync with the data 19 | * Add files to the web app without having to re-run xunit viewer 20 | * Adds the metadata to the header so you can share the URL in places such as slack, for example 21 | * Use the query parameter to filter tests 22 | 23 | ![Example](https://raw.githubusercontent.com/lukejpreston/xunit-viewer/master/example-header.png) 24 | 25 | Xunit Viewer supports node LTS version but should work on node 10+ 26 | 27 | ## URL filtering 28 | 29 | You can filter by test status to save time on refreshes, and update the query params 30 | 31 | `FILE|ROUTE/?passed=true&error=false&failure=false&skipped=true&unknown=false` 32 | 33 | ## Usage, CLI 34 | 35 | ```sh 36 | npm i -g xunit-viewer 37 | xunit-viewer --help 38 | ``` 39 | 40 | ### Commands 41 | 42 | ```text 43 | xunit-viewer [command] 44 | 45 | Commands: 46 | xunit-viewer Renders Xunit style xml results 47 | 48 | Options: 49 | --version Show version number [boolean] 50 | -r, --results File/Folder of results [string] [required] 51 | -i, --ignore Ignore patterns [array] 52 | -o, --output Output filename [string] 53 | -t, --title HTML title e.g. "My Tests" [string] 54 | -b, --brand Provide a URL with your own logo [string] 55 | -f, --favicon Provide a URL with your own favicon [string] 56 | -c, --console Render in console [boolean] 57 | -C, --clear Clears the console [boolean] [default: true] 58 | -s, --server Start a server and sockets for live updates 59 | [boolean] [default: false] 60 | -n, --no-color No color in the console [boolean] 61 | -w, --watch Re-run when a file changes [boolean] 62 | -p, --port Starts a server with sockets on that port, if no port is 63 | provided then it will run on port 3000 (or next available) 64 | [number] 65 | --help Show help [boolean] 66 | 67 | Examples: 68 | xunit-viewer -r file.xml a file 69 | xunit-viewer -r folder a folder 70 | xunit-viewer -r folder -i *-broke.xml ignore 71 | xunit-viewer -r folder -o my-tests.html rename output 72 | xunit-viewer -r folder -t "My Tests" change HTML title 73 | xunit-viewer -r folder -b https://image.png change the image 74 | xunit-viewer -r folder -f https://image.favico change the favicon 75 | xunit-viewer -r folder -c render in console 76 | xunit-viewer -r folder -c -s false render in console and do not save 77 | xunit-viewer -r folder -c -n no color in console 78 | xunit-viewer -r folder -w start watch 79 | xunit-viewer -r folder -w -p 5050 watch at 5050 80 | ``` 81 | 82 | ## Usage, Node 83 | 84 | Xunit Viewer is asynchronous so you may need to wrap it up like so. **NOTE** The `script` parameter which will skip all Xunit Viewer's exit codes. 85 | 86 | ```js 87 | import xunitViewer from 'xunit-viewer' 88 | 89 | const main = async () => { 90 | await xunitViewer({ 91 | server: false, 92 | results: 'data', 93 | ignore: ['_thingy', 'invalid'], 94 | title: 'Xunit View Sample Tests', 95 | output: 'output.html', 96 | script: true 97 | }) 98 | } 99 | main() 100 | ``` 101 | 102 | If you are going to run it from a script with no other code 103 | 104 | ```js 105 | import xunitViewer from 'xunit-viewer' 106 | 107 | xunitViewer({ 108 | server: false, 109 | results: 'data', 110 | ignore: ['_thingy', 'invalid'], 111 | title: 'Xunit View Sample Tests', 112 | output: 'output.html', 113 | script: true 114 | }) 115 | ``` 116 | 117 | ## Usage, React 118 | 119 | not available 120 | 121 | ## Contributing 122 | 123 | A list of available commands 124 | 125 | ```sh 126 | npm i 127 | npm start # this starts the dev app 128 | npm release # this updates the code in the cli folder 129 | npm run demo # this generates the demo 130 | ./bin/xunit-viewer # to run the local command line tool 131 | 132 | npm test # runs the tests 133 | npm run test:ci # runs without watch and also generates a html output 134 | npm run lint # runs eslint 135 | npm run update # updates the expected files for you 136 | npm run build:cli # builds the js and copies it to the cli 137 | ``` 138 | 139 | Make sure your tests are running and passing, and the linter is passing as well 140 | 141 | **DO NOT** commit the `src/cli/static` folder or the `junit.xml` file as part of your PR as these are auto-generated and just clutters up the PR, future work will be done to not make them part of the repo but they currently need to be included for the tags 142 | 143 | A suggested workflow for UI changes 144 | 145 | 1. `npm i` to install the project 146 | 2. `npm start` to start the dev application then you can make your changes quickly 147 | 3. `npm test` to run the tests, run `npm run updated` to quickly update expected values 148 | 4. `npm run lint` to make sure all the files and nice and linted 149 | 5. `npm build:cli` in order to update the CLI with your UI changes 150 | 6. `./bin/xunit-viewer -r data -o test-output.html` in order to make sure the commands work as expected 151 | 152 | If your work does not include any UI work then a suggestion is 153 | 154 | 1. `npm i` to install the project 155 | 2. `./bin/xunit-viewer ...` in order to make sure the commands work as expected 156 | 3. `npm test` to run the tests, run `npm run updated` to quickly update expected values 157 | 4. `npm run lint` to make sure all the files and nice and linted 158 | 159 | ## Help Wanted 160 | 161 | I am always looking for sample data. If you have some results which you think are "interesting" then please raise an issue or pull request and we can add this to our sample data. 162 | 163 | ## Issues 164 | 165 | Raise any issues using GitHub and provide sample data where possible. 166 | 167 | To help debug any issues please provide the following info 168 | 169 | * node and npm version, refer to [Node](https://nodejs.org/en/) for LTS 170 | * xunit viewer version 171 | * browser 172 | * sample xml 173 | 174 | 175 | TODO 176 | 177 | 1. Fix CLI filtering 178 | 2. Release v11 179 | 3. Refactorings 180 | * Split components into files 181 | * Split reducer into files 182 | * Test all the things -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /XunitViewerIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/XunitViewerIcon.png -------------------------------------------------------------------------------- /XunitViewerIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /bin/xunit-viewer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import xunitViewer from '../xunit-viewer.js' 4 | import { args } from '../src/cli/args.js' 5 | 6 | xunitViewer(args) 7 | -------------------------------------------------------------------------------- /component/icon-map.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Check from './icons/check' 3 | import Times from './icons/times' 4 | import Exclamation from './icons/exclamation' 5 | import Ban from './icons/ban' 6 | import Question from './icons/question' 7 | import AngleDown from './icons/angle-down' 8 | import AngleUp from './icons/angle-up' 9 | 10 | let Icon = ({ children }) => { 11 | return 12 | {children} 13 | 14 | } 15 | 16 | export default { 17 | pass: , 18 | fail: , 19 | error: , 20 | skip: , 21 | unknown: , 22 | angleDown: , 23 | angleUp: 24 | } 25 | -------------------------------------------------------------------------------- /data/class_not_classname.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 11 | GuestBrowsingProphetBetsPageCest: Navigate and 12 | check test 13 | Failed asserting that two strings are equal. 14 | /usr/share/nginx/html/tests/_support/_generated/AcceptanceTesterActions.php:768 15 | /usr/share/nginx/html/tests/_support/Step/Prophet.php:50 16 | /usr/share/nginx/html/tests/acceptance/Bets/GuestBrowsingProphetBetsPageCest.php:49 17 | 18 | 19 | 24 | GuestBrowsingProphetOfferedPropheciesPageCest: 25 | Navigate and check test 26 | Element located either by name, CSS or XPath element with '#twoLevelTabsMenu' was not found. 27 | /usr/share/nginx/html/tests/_support/_generated/AcceptanceTesterActions.php:334 28 | /usr/share/nginx/html/tests/_support/AcceptanceTester.php:346 29 | /usr/share/nginx/html/tests/_support/Page/Element/UserProfileMenu.php:204 30 | /usr/share/nginx/html/tests/_support/Page/Element/UserProfileMenu.php:298 31 | /usr/share/nginx/html/tests/acceptance/Prophecies/GuestBrowsingProphetOfferedPropheciesPageCest.php:54 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /data/complete_no_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | inner massage 19 | 20 | 21 | inner massage 22 | 23 | 24 | inner massage 25 | 26 | 27 | inner massage 28 | 29 | 30 | inner message 31 | 32 | 33 | 34 | inner message 35 | 36 | 37 | 38 | 39 | inner massage 40 | inner massage 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | <i>inner</i><b>message</b> 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /data/complete_no_suite_multi_cases.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/complete_no_suite_single_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | inner massage 19 | 20 | 21 | inner massage 22 | 23 | 24 | inner massage 25 | 26 | 27 | inner massage 28 | 29 | 30 | inner message 31 | 32 | 33 | 34 | inner message 35 | 36 | 37 | 38 | 39 | inner massage 40 | inner massage 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | <i>inner</i><b>message</b> 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /data/complete_single_case_only.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/complete_single_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | inner massage 20 | 21 | 22 | inner massage 23 | 24 | 25 | inner massage 26 | 27 | 28 | inner massage 29 | 30 | 31 | inner message 32 | 33 | 34 | 35 | inner message 36 | 37 | 38 | 39 | 40 | inner massage 41 | inner massage 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | <i>inner</i><b>message</b> 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | inner massage 71 | 72 | 73 | 74 | 75 | 76 | inner massage 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /data/defect_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | java.lang.RuntimeException: There was an error 11 | 12 | -------------------------------------------------------------------------------- /data/duplicate_name_unique_classanme.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | at Obi.Backend.Tests.CuentaTest.DeberiaInvocarASoaYDevolverHttpOk() in /Users/nicopaez/Projects/esfera/supervielle/obi/bff-obi/Obi.Backend.Tests/CuentaTest.cs:line 27 13 | at NUnit.Framework.Internal.TaskAwaitAdapter.GenericAdapter`1.BlockUntilCompleted() 14 | at NUnit.Framework.Internal.MessagePumpStrategy.NoMessagePumpStrategy.WaitForCompletion(AwaitAdapter awaitable) 15 | at NUnit.Framework.Internal.AsyncToSyncAdapter.Await(Func`1 invoke) 16 | at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(TestExecutionContext context) 17 | at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) 18 | at NUnit.Framework.Internal.Execution.SimpleWorkItem.PerformWork() 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /data/embedded_html_sysout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
8 | ]]> 9 |
10 | 11 | 25 | 26 |
27 |
-------------------------------------------------------------------------------- /data/error_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | java.lang.RuntimeException: There was an error 5 | 6 | -------------------------------------------------------------------------------- /data/failing_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FILENAME:XX Expected <string>: Luke to equal <string>: luke 5 | 6 | -------------------------------------------------------------------------------- /data/invalid.xml: -------------------------------------------------------------------------------- 1 | bacon -------------------------------------------------------------------------------- /data/issue_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /data/issue_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /data/malformed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | java.lang.AssertionError 5 | at org.junit.Assert.fail(Assert.java:86) 6 | at org.junit.Assert.assertTrue(Assert.java:41) 7 | at org.junit.Assert.assertTrue(Assert.java:52) 8 | at com.germaniumhq.germanium.steps.GermaniumFunctionSelectFile.the_file_is_uploaded_successfully(GermaniumFunctionSelectFile.java:26) 9 | at ✽.Then the file is uploaded successfully(features/features/germanium-function-select_file.feature:7) 10 | 11 | 12 | -------------------------------------------------------------------------------- /data/most_complex.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | java.lang.RuntimeException: There was an error 18 | 19 | 20 | <i>WITH</i><b>HTML</b> 21 | 22 | 23 | For some reason a passing message 24 | 25 | 26 | This message has a link github.com/lukejpreston/xunit-viewer and an email example@gmail.com 27 | 28 | 29 | java.lang.RuntimeException: There was an error 1 30 | java.lang.RuntimeException: There was an error 2 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /data/multi-name-unique-classname.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | at Obi.Backend.Tests.CuentaTest.DeberiaInvocarASoaYDevolverHttpOk() in /Users/nicopaez/Projects/esfera/supervielle/obi/bff-obi/Obi.Backend.Tests/CuentaTest.cs:line 27 13 | at NUnit.Framework.Internal.TaskAwaitAdapter.GenericAdapter`1.BlockUntilCompleted() 14 | at NUnit.Framework.Internal.MessagePumpStrategy.NoMessagePumpStrategy.WaitForCompletion(AwaitAdapter awaitable) 15 | at NUnit.Framework.Internal.AsyncToSyncAdapter.Await(Func`1 invoke) 16 | at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(TestExecutionContext context) 17 | at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) 18 | at NUnit.Framework.Internal.Execution.SimpleWorkItem.PerformWork() 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /data/multi_cases.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | java.lang.RuntimeException: There was an error 14 | java.lang.RuntimeException: There was an error 15 | 16 | 17 | FILENAME:XX Expected <string>: Luke to equal <string>: luke 18 | 19 | 20 | 21 | This is a message 22 | This is a message 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/multi_error_test_with_system_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error message 5 | Some messgae 6 | FILENAME:XX 7 | 8 | -------------------------------------------------------------------------------- /data/multi_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 14 | 15 | 20 | 21 | 26 | 27 | 32 | 33 | 38 | 39 | 44 | 45 | 46 | 52 | 57 | 58 | 63 | 64 | 69 | 70 | 75 | 76 | 81 | 82 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /data/name.has.dots.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/nested-nested.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /data/no_class_name.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/passing_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/properties_in_test_meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | [DELETED]/BasicWebViewControllerTests.swift:103 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /data/pytest_testcase_properties.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /data/russian-unicode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | -------------------------------------------------------------------------------- /data/semi-colon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | { 6 | "facts": { 7 | "testscript": { 8 | "Output": "test001 succeeded!\n" 9 | } 10 | }, 11 | "changed": true, 12 | "container": { 13 | "Output": "test001 succeeded!\n" 14 | }, 15 | "result_failed": false 16 | } 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | { 26 | "facts": { 27 | "testscript": { 28 | "Output": "test001 succeeded!\n" 29 | } 30 | }, 31 | "changed": true, 32 | "container": { 33 | "Output": "test001 succeeded!\n" 34 | }, 35 | "result_failed": false 36 | } 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /data/skipped_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/special_chars_suite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /data/subfolder/_thingy.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/data/subfolder/_thingy.xml -------------------------------------------------------------------------------- /data/suite-system-out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Generated test.log (if the file is not UTF-8, then this may be unreadable): 9 | 14 | from XYZ.extractor import Extractor 15 | File "/tmp/text_models/bazel/sandbox/linux-sandbox/8/execroot/text_models/bazel-out/k8-fastbuild/bin/XYZ/e2e_tests.runfiles/text_models/XYZ/extractor.py", line 7, in 16 | from ABC.DEF.helper import join_set 17 | ModuleNotFoundError: No module named 'ABC']]> 18 | 19 | 20 | Generated test.log (if the file is not UTF-8, then this may be unreadable): 21 | 26 | from XYZ.extractor import Extractor 27 | File "/tmp/text_models/bazel/sandbox/linux-sandbox/8/execroot/text_models/bazel-out/k8-fastbuild/bin/XYZ/e2e_tests.runfiles/text_models/XYZ/extractor.py", line 7, in 28 | from ABC.DEF.helper import join_set 29 | ModuleNotFoundError: No module named 'ABC']]> 30 | 31 | 32 | -------------------------------------------------------------------------------- /data/test-system-out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | cwd: /tmp/tmpyn7k46sd emanate --source /tmp/tmpwz2h7glq/src '/tmp/tmpwz2h7glq/src/foo' -> '/tmp/tmpwz2h7glq/dest/foo' cwd: /tmp/tmpetkvkfdw emanate --source src '/tmp/tmpetkvkfdw/src/foo' -> '/tmp/tmpetkvkfdw/dest/foo' cwd: /tmp/tmpq7vws4le/src emanate '/tmp/tmpq7vws4le/src/foo' -> '/tmp/tmpq7vws4le/dest/foo' 8 | 9 | 10 | 11 | 12 | cwd: /tmp/tmpuv0uzm7s emanate --source /tmp/tmp_uh8tzdz/src --dest /tmp/tmp_uh8tzdz/dest '/tmp/tmp_uh8tzdz/src/foo' -> '/tmp/tmp_uh8tzdz/dest/foo' '/tmp/tmp_uh8tzdz/src/bar/baz' -> '/tmp/tmp_uh8tzdz/dest/bar/baz' cwd: /tmp/tmpk99ai9r0 emanate --source src --dest /tmp/tmpk99ai9r0/dest '/tmp/tmpk99ai9r0/src/foo' -> '/tmp/tmpk99ai9r0/dest/foo' '/tmp/tmpk99ai9r0/src/bar/baz' -> '/tmp/tmpk99ai9r0/dest/bar/baz' cwd: /tmp/tmprxyuze4g/src emanate --dest /tmp/tmprxyuze4g/dest '/tmp/tmprxyuze4g/src/foo' -> '/tmp/tmprxyuze4g/dest/foo' '/tmp/tmprxyuze4g/src/bar/baz' -> '/tmp/tmprxyuze4g/dest/bar/baz' 13 | 14 | 15 | 16 | 17 | cwd: /tmp/tmp2gjl2wj_ emanate --source /tmp/tmp1t7j_ote/src --dest /tmp/tmp1t7j_ote/dest '/tmp/tmp1t7j_ote/src/foo' -> '/tmp/tmp1t7j_ote/dest/foo' cwd: /tmp/tmp9b40pw3b emanate --source src --dest /tmp/tmp9b40pw3b/dest '/tmp/tmp9b40pw3b/src/foo' -> '/tmp/tmp9b40pw3b/dest/foo' cwd: /tmp/tmpfmnr88qv/src emanate --dest /tmp/tmpfmnr88qv/dest '/tmp/tmpfmnr88qv/src/foo' -> '/tmp/tmpfmnr88qv/dest/foo' 18 | 19 | 20 | 21 | 22 | cwd: /tmp/tmp9q8tpxi2 emanate --source /tmp/tmpn4lvoqq7/src clean '/tmp/tmpn4lvoqq7/dest/foo' cwd: /tmp/tmp0dzkb_z5 emanate --source src clean '/tmp/tmp0dzkb_z5/dest/foo' cwd: /tmp/tmpsueno4qa/src emanate clean '/tmp/tmpsueno4qa/dest/foo' 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /data/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | value 2 10 | 11 | 12 | value with no name 13 | 14 | 15 | 16 | 17 | 18 | value only 19 | 20 | only a message 21 | 22 | 23 | 24 | 25 | 26 | inner message 27 | 28 | HERE IS SOME TEXT 29 | inner massage 1 30 | 31 | 32 | inner massage 1 33 | inner massage 2 34 | 35 | 36 | inner massage 1 37 | inner massage 2 38 | 39 | 40 | inner massage 1 41 | inner massage 2 42 | 43 | 44 | inner massage 1 45 | inner massage 2 46 | 47 | 48 | error inner massage 1 49 | failure inner massage 2 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | value 2 77 | 78 | 79 | value with no name 80 | 81 | 82 | 83 | 84 | 85 | value only 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /data/thing.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/data/thing.txt -------------------------------------------------------------------------------- /data/utf-16.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/data/utf-16.xml -------------------------------------------------------------------------------- /data/with_html.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <i>ARGG</i><b>BOO</b> 6 | 7 | -------------------------------------------------------------------------------- /example-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/example-header.png -------------------------------------------------------------------------------- /gh-pages/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/gh-pages/favicon.ico -------------------------------------------------------------------------------- /gh-pages/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/gh-pages/icon.png -------------------------------------------------------------------------------- /junit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xunit-viewer", 3 | "type": "module", 4 | "version": "10.6.1", 5 | "description": "parses xunit xml into xunit viewer", 6 | "repository": { 7 | "url": "https://github.com/lukejpreston/xunit-viewer.git", 8 | "type": "git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/lukejpreston/xunit-viewer.git" 12 | }, 13 | "homepage": "./", 14 | "keywords": [ 15 | "test", 16 | "junit", 17 | "xunit", 18 | "viewer", 19 | "parser" 20 | ], 21 | "author": "lukejpreston ", 22 | "license": "MIT", 23 | "main": "xunit-viewer.js", 24 | "bin": { 25 | "xunit-viewer": "bin/xunit-viewer.js" 26 | }, 27 | "directories": { 28 | "bin": "bin", 29 | "cli": "src/cli" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test --reporters=default --reporters=jest-junit", 35 | "update": "node src/cli/update-expected.js", 36 | "eject": "react-scripts eject", 37 | "lint": "eslint xunit-viewer.js src --ignore-pattern src/cli/static/js/**/*", 38 | "test:ci": "echo blah", 39 | "test:document": "./bin/xunit-viewer.js -r junit.xml -o gh-pages/xunit-viewer-results.html", 40 | "test:document:serve": "npm run test:document -- -s", 41 | "demo": "./bin/xunit-viewer.js -r data -o gh-pages/index.html", 42 | "release:demo": "npm run test:document && npm run demo && gh-pages -d gh-pages", 43 | "deploy": "rm -rf src/cli/static && cp -r build/static src/cli/static", 44 | "build:cli": "npm run build && npm run deploy", 45 | "release": "./release.sh" 46 | }, 47 | "dependencies": { 48 | "@uiw/react-codemirror": "^4.21.3", 49 | "chalk": "^5.2.0", 50 | "chokidar": "^3.5.3", 51 | "console-clear": "^1.1.1", 52 | "debounce": "^1.2.1", 53 | "detect-file-encoding-and-language": "^2.4.0", 54 | "express": "^4.18.2", 55 | "get-port": "^7.0.0", 56 | "handlebars": "^4.7.7", 57 | "ip": "^1.1.8", 58 | "lzutf8": "^0.6.3", 59 | "merge": "^2.1.1", 60 | "socket.io": "^4.6.2", 61 | "xml2js": "^0.6.0", 62 | "yargs": "^17.7.2" 63 | }, 64 | "devDependencies": { 65 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11", 66 | "@fortawesome/fontawesome-free": "^6.4.0", 67 | "bulma": "^0.9.4", 68 | "eslint": "^8.43.0", 69 | "eslint-config-standard": "^17.1.0", 70 | "eslint-config-standard-react": "^13.0.0", 71 | "eslint-import-resolver-node": "^0.3.7", 72 | "eslint-plugin-import": "^2.27.5", 73 | "eslint-plugin-node": "^11.1.0", 74 | "eslint-plugin-promise": "^6.1.1", 75 | "eslint-plugin-react": "^7.32.2", 76 | "eslint-plugin-standard": "^5.0.0", 77 | "fuzzy": "^0.1.3", 78 | "gh-pages": "^5.0.0", 79 | "jest-junit": "^16.0.0", 80 | "linkify-html": "^4.1.1", 81 | "linkifyjs": "^4.1.1", 82 | "localforage": "^1.10.0", 83 | "match-sorter": "^6.3.1", 84 | "query-string": "^8.1.0", 85 | "react": "^18.2.0", 86 | "react-dom": "^18.2.0", 87 | "react-linkify": "^1.0.0-alpha", 88 | "react-render-if-visible": "^2.1.1", 89 | "react-router-dom": "^6.13.0", 90 | "react-scripts": "^5.0.1", 91 | "react-test-renderer": "^18.2.0", 92 | "sort-by": "^1.2.0", 93 | "stream": "^0.0.2", 94 | "timers": "^0.1.1" 95 | }, 96 | "browserslist": [ 97 | ">0.2%", 98 | "not dead", 99 | "not ie <= 11", 100 | "not op_mini all" 101 | ], 102 | "eslintIgnore": [ 103 | "cli/static/**/*" 104 | ], 105 | "eslintConfig": { 106 | "extends": [ 107 | "standard", 108 | "standard-react", 109 | "plugin:react/recommended" 110 | ], 111 | "env": { 112 | "browser": true, 113 | "jest": true, 114 | "jasmine": true 115 | }, 116 | "rules": { 117 | "react/prop-types": 0, 118 | "react/jsx-closing-tag-location": 0, 119 | "react/jsx-closing-bracket-location": 0 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukejpreston/xunit-viewer/f41d75ff886ceaacb0c09e1d1feb088b1ebc23de/public/icon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Xunit Viewer 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | npm run lint 6 | npm run build:cli 7 | npm run test:ci 8 | ./bin/xunit-viewer.js -r junit.xml -c -C false 9 | CURRENT=$(echo $(npm version | grep xunit-viewer | cut -d"'" -f4)) 10 | git commit --allow-empty -am "tested $CURRENT" 11 | 12 | npm version ${1-patch} 13 | npm publish 14 | LATEST=$(echo npm version | grep xunit-viewer | cut -d"'" -f4) 15 | 16 | npm run release:demo 17 | 18 | git add -A 19 | git commit --allow-empty -am "release demo $LATEST" 20 | 21 | git push 22 | git push --tags 23 | -------------------------------------------------------------------------------- /sample-usage.js: -------------------------------------------------------------------------------- 1 | import xunitViewer from './xunit-viewer' 2 | 3 | xunitViewer({ 4 | server: false, 5 | results: 'data', 6 | ignore: ['_thingy', 'invalid'], 7 | title: 'Xunit View Sample Tests', 8 | output: 'output.html' 9 | }) 10 | -------------------------------------------------------------------------------- /src/app/__snapshots__/hero.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders hero 1`] = ` 4 |
7 |
10 |
13 |
16 | 27 |
28 |
31 |
34 | 37 |

40 |

41 |
42 |
43 |
44 |
45 | `; 46 | 47 | exports[`renders hero with title and brand 1`] = ` 48 |
51 |
54 |
57 |
60 | 71 |
72 |
75 |
78 | bacon 83 |

86 | bacon 87 |

88 |
89 |
90 |
91 |
92 |
93 | `; 94 | -------------------------------------------------------------------------------- /src/app/__snapshots__/logo.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders logo 1`] = ` 4 | 12 | 17 | 21 | 25 | 31 | 37 | 38 | `; 39 | -------------------------------------------------------------------------------- /src/app/__snapshots__/properties-options.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders properties options 1`] = ` 4 |
7 |
10 |
13 |
16 | 22 |
23 |
24 | 51 |
52 |
55 |
56 | `; 57 | -------------------------------------------------------------------------------- /src/app/__snapshots__/suite-options.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders suite options 1`] = ` 4 |
7 |
10 |
13 |
16 | 22 |
23 |
24 | 51 |
52 |
55 |
56 | `; 57 | -------------------------------------------------------------------------------- /src/app/__snapshots__/test-options.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders test options 1`] = ` 4 |
7 |
10 |
13 |
16 | 22 |
23 |
24 |