├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── images ├── all_tests.png ├── run_all_output.png └── under_cursor.png ├── keymaps └── atom-python-test.cson ├── lib ├── atom-python-test-dock.js ├── atom-python-test.js ├── config-schema.json └── executor │ └── pytest-executor.js ├── menus └── atom-python-test.cson ├── package-lock.json ├── package.json └── styles └── atom-python-test.less /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | notifications: 2 | email: 3 | on_success: never 4 | on_failure: change 5 | 6 | script: 'curl -s https://raw.githubusercontent.com/atom/ci/master/build-package.sh | sh' 7 | 8 | git: 9 | depth: 10 10 | 11 | sudo: false 12 | 13 | os: 14 | - linux 15 | - osx 16 | 17 | env: 18 | global: 19 | - APM_TEST_PACKAGES="" 20 | 21 | matrix: 22 | - ATOM_CHANNEL=stable 23 | - ATOM_CHANNEL=beta 24 | 25 | addons: 26 | apt: 27 | packages: 28 | - build-essential 29 | - git 30 | - libgnome-keyring-dev 31 | - fakeroot 32 | 33 | branches: 34 | only: 35 | - master 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 - First Release 2 | * Every feature added 3 | * Every bug fixed 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | * Run py.tests and unitest.TestCase tests on Atom. 4 | 5 | ## Requirements 6 | 7 | * You need py.test installed to use this package: 8 | 9 | ``` 10 | pip install pytest 11 | ``` 12 | 13 | When using virtualenv, the recommended workflow is: 14 | 15 | * Activate your virtualenv on terminal. 16 | * Run atom editor, so this plug-in will get py.test from virtualenv (or use atom-python-virtualenv plug-in). 17 | 18 | ## configuration 19 | 20 | On settings you can configure the path to the python executable, so you can choose your python executable from virtualenv, miniconda, pyenv, etc. You can configure additionalArgs to the pytest 21 | command line executor too. 22 | 23 | ## Usage 24 | 25 | 1) Running all tests ```(Ctrl + Alt + T)``` 26 | 27 | 2) Run test under cursor ```(Ctrl + Alt + C)``` 28 | 29 | 3) Toggle (on/off) the tests panel ```(Ctrl + Alt + H)``` 30 | -------------------------------------------------------------------------------- /images/all_tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pghilardi/atom-python-test/0b81ed7b8481a34e6712db5eb5c4a72ff0eb5308/images/all_tests.png -------------------------------------------------------------------------------- /images/run_all_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pghilardi/atom-python-test/0b81ed7b8481a34e6712db5eb5c4a72ff0eb5308/images/run_all_output.png -------------------------------------------------------------------------------- /images/under_cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pghilardi/atom-python-test/0b81ed7b8481a34e6712db5eb5c4a72ff0eb5308/images/under_cursor.png -------------------------------------------------------------------------------- /keymaps/atom-python-test.cson: -------------------------------------------------------------------------------- 1 | # Keybindings require three things to be fully defined: A selector that is 2 | # matched against the focused element, the keystroke and the command to 3 | # execute. 4 | # 5 | # Below is a basic keybinding which registers on all platforms by applying to 6 | # the root workspace element. 7 | 8 | # For more detailed documentation see 9 | # https://atom.io/docs/latest/behind-atom-keymaps-in-depth 10 | 'atom-workspace': 11 | 'ctrl-alt-t': 'atom-python-test:run-all-tests' 12 | 'ctrl-alt-c': 'atom-python-test:run-test-under-cursor' 13 | 'ctrl-alt-h': 'atom-python-test:toggle-test-results' 14 | -------------------------------------------------------------------------------- /lib/atom-python-test-dock.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | export default class AtomPythonTestViewDock { 4 | 5 | constructor(serializedState) { 6 | // Create root element 7 | this.element = document.createElement('div'); 8 | this.element.classList.add('atom-python-test'); 9 | this.tableResults = null; 10 | 11 | this.message = document.createElement('div'); 12 | this.element.appendChild(this.message); 13 | this.message.innerHTML = ""; 14 | } 15 | 16 | removeTable(){ 17 | if (this.tableResults){ 18 | this.element.removeChild(this.tableResults); 19 | } 20 | } 21 | 22 | createTable(){ 23 | this.tableResults = document.createElement('table'); 24 | this.tableResults.classList.add('tests'); 25 | this.element.appendChild(this.tableResults); 26 | } 27 | 28 | createTableHeader() { 29 | header = this.tableResults.createTHead(); 30 | var row = header.insertRow(0); 31 | 32 | testName = row.insertCell(); 33 | testName.innerHTML = "Name"; 34 | testTime = row.insertCell(); 35 | testTime.innerHTML = "Time"; 36 | testResult = row.insertCell(); 37 | testResult.innerHTML = "Result"; 38 | testResult = row.insertCell(); 39 | testResult.innerHTML = "Exception"; 40 | } 41 | 42 | printError(){ 43 | this.removeTable(error); 44 | this.message.innerHTML = "There was an error executing the tests: " + error; 45 | } 46 | 47 | printOutput(junitOutput){ 48 | 49 | console.log(junitOutput); 50 | 51 | numberOfTests = junitOutput.junit_info.tests.count !== undefined ? junitOutput.junit_info.tests.count : 0 52 | passedTests = junitOutput.junit_info.tests.passed !== undefined ? junitOutput.junit_info.tests.passed : 0 53 | failedTests = junitOutput.junit_info.tests.failure !== undefined ? junitOutput.junit_info.tests.failure : 0 54 | this.message.innerHTML = "

Summary: " + numberOfTests + " tests were executed: passed (" 55 | + passedTests + ") failed (" + failedTests + ")

"; 56 | 57 | this.removeTable(); 58 | this.createTable(); 59 | 60 | suite = junitOutput.suites[0] 61 | 62 | for (index in suite.testCases){ 63 | test = suite.testCases[index]; 64 | testResult = this.tableResults.insertRow(); 65 | 66 | if (test.type == 'passed'){ 67 | cssClass = 'success-line'; 68 | } else { 69 | cssClass = 'failure-line'; 70 | } 71 | testNameCell = testResult.insertCell(); 72 | testNameCell.innerHTML = `${test.name}` 73 | testNameCell.classList.add(cssClass); 74 | testNameCell.classList.add('row-name') 75 | 76 | testTimeCell = testResult.insertCell(); 77 | testTimeCell.innerHTML = `${test.time}` 78 | testTimeCell.classList.add(cssClass); 79 | testNameCell.classList.add('row-time') 80 | 81 | testResultCell = testResult.insertCell(); 82 | testResultCell.innerHTML = `${test.type}` 83 | testResultCell.classList.add(cssClass); 84 | testNameCell.classList.add('row-type') 85 | 86 | testExceptionCell = testResult.insertCell(); 87 | 88 | if (test.type == 'failure'){ 89 | exception = test.messages.values[0].value; 90 | 91 | lines = exception.split("\n"); 92 | console.log(lines); 93 | 94 | testExceptionCell.innerHTML = `${exception}` 95 | testExceptionCell.classList.add(cssClass); 96 | testNameCell.classList.add('row-exception') 97 | 98 | } 99 | 100 | } 101 | 102 | this.createTableHeader(); 103 | } 104 | 105 | getTitle() { 106 | // Used by Atom for tab text 107 | return 'Atom Python Test - Results'; 108 | } 109 | 110 | getDefaultLocation() { 111 | // This location will be used if the user hasn't overridden it by dragging the item elsewhere. 112 | // Valid values are "left", "right", "bottom", and "center" (the default). 113 | return 'right'; 114 | } 115 | 116 | getAllowedLocations() { 117 | // The locations into which the item can be moved. 118 | return ['left', 'right', 'bottom']; 119 | } 120 | 121 | getURI() { 122 | // Used by Atom to identify the view when toggling. 123 | return 'atom://atom-python-test-dock' 124 | } 125 | 126 | // Returns an object that can be retrieved when package is activated 127 | serialize() { 128 | return { 129 | deserializer: 'atom-python-test/AtomPythonTestViewDock' 130 | }; 131 | } 132 | 133 | // Tear down any state and detach 134 | destroy() { 135 | this.element.remove(); 136 | } 137 | 138 | getElement() { 139 | return this.element; 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /lib/atom-python-test.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | const { CompositeDisposable, Disposable } = require('atom'); 4 | const config = require('./config-schema.json'); 5 | const AtomPythonTestViewDock = require('./atom-python-test-dock'); 6 | const PytestExecutor = require('./executor/pytest-executor'); 7 | 8 | let subscriptions = null; 9 | let dock = new AtomPythonTestViewDock(); 10 | 11 | const activate = () => { 12 | 13 | subscriptions = new CompositeDisposable( 14 | // Add an opener for our view. 15 | atom.workspace.addOpener(uri => { 16 | if (uri === 'atom://atom-python-test-dock') { 17 | return dock; 18 | } 19 | }), 20 | 21 | // Register command that toggles this view 22 | atom.commands.add('atom-workspace', { 23 | 'atom-python-test:run-all-tests': () => { 24 | 25 | // Force the opening 26 | atom.workspace.open('atom://atom-python-test-dock'); 27 | 28 | runAllTests(); 29 | } 30 | }), 31 | 32 | atom.commands.add('atom-workspace', { 33 | 'atom-python-test:run-test-under-cursor': () => { 34 | 35 | // Force the opening 36 | atom.workspace.open('atom://atom-python-test-dock'); 37 | 38 | runTestUnderCursor(); 39 | } 40 | }), 41 | 42 | atom.commands.add('atom-workspace', { 43 | 'atom-python-test:toggle-test-results': () => { 44 | pane = atom.workspace.toggle('atom://atom-python-test-dock') 45 | } 46 | }), 47 | 48 | // Destroy any ActiveEditorInfoViews when the package is deactivated. 49 | new Disposable(() => { 50 | atom.workspace.getPaneItems().forEach(item => { 51 | if (item instanceof AtomPythonTestViewDock) { 52 | item.destroy(); 53 | } 54 | }); 55 | }) 56 | ); 57 | }; 58 | 59 | const deactivate = () => { 60 | subscriptions.dispose(); 61 | }; 62 | 63 | const runAllTests = () => { 64 | editor = atom.workspace.getActivePaneItem() 65 | file = editor.buffer.file 66 | filePath = file.path 67 | 68 | executor = new PytestExecutor(dock); 69 | additionalArgs = atom.config.get('atom-python-test.additionalArgs').toString(); 70 | pythonExecutableDirectory = atom.config.get('atom-python-test.pythonExecutableDirectory').toString(); 71 | executor.executePyTest(filePath, pythonExecutableDirectory, additionalArgs); 72 | }; 73 | 74 | const runTestUnderCursor = () => { 75 | const editor = atom.workspace.getActiveTextEditor(); 76 | const file = editor != null ? editor.buffer.file : undefined; 77 | let filePath = file != null ? file.path : undefined; 78 | const selectedText = editor.getSelectedText(); 79 | 80 | const testLineNumber = editor.getCursorBufferPosition().row; 81 | const testIndentation = editor.indentationForBufferRow(testLineNumber); 82 | 83 | const class_re = /class \w*\((\w*.*\w*)*\):/; 84 | const buffer = editor.buffer; 85 | 86 | // Starts searching backwards from the test line until we find a class. This 87 | // guarantee that the class is a Test class, not an utility one. 88 | const reversedLines = buffer.getLines().slice(0, testLineNumber).reverse(); 89 | 90 | for (let i = 0; i < reversedLines.length; i++) { 91 | var endIndex; 92 | const line = reversedLines[i]; 93 | const isClassLine = line.startsWith("class"); 94 | 95 | const classLineNumber = testLineNumber - i - 1; 96 | 97 | // We think that we have found a Test class, but this is guaranteed only if 98 | // the test indentation is greater than the class indentation. 99 | const classIndentation = editor.indentationForBufferRow(classLineNumber); 100 | // if startIndex != -1 and testIndentation > classIndentation 101 | if (isClassLine && (testIndentation > classIndentation)) { 102 | if (line.includes('(')) { 103 | endIndex = line.indexOf('('); 104 | } else { 105 | endIndex = line.indexOf(':'); 106 | } 107 | const className = line.slice(6, endIndex); 108 | filePath = filePath + '::' + className; 109 | break; 110 | } 111 | } 112 | 113 | const re = /test(\w*|\W*)/; 114 | const content = editor.buffer.getLines()[testLineNumber]; 115 | endIndex = content.indexOf('('); 116 | const startIndex = content.search(re); 117 | const testName = content.slice(startIndex, endIndex); 118 | 119 | if (testName) { 120 | filePath = filePath + '::' + testName; 121 | additionalArgs = atom.config.get('atom-python-test.additionalArgs'); 122 | pythonExecutableDirectory = atom.config.get('atom-python-test.pythonExecutableDirectory') 123 | executor = new PytestExecutor(dock); 124 | executor.executePyTest(filePath, pythonExecutableDirectory, additionalArgs); 125 | } 126 | } 127 | 128 | module.exports = { 129 | activate, 130 | deactivate, 131 | config, 132 | subscriptions 133 | }; 134 | -------------------------------------------------------------------------------- /lib/config-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "pythonExecutableDirectory": { 3 | "description": "Path of python executable. May be set if you have a setting that is not supported by the plugin default configuration. Example: /usr/bin/python3'", 4 | "type": "string", 5 | "default": "python" 6 | }, 7 | "additionalArgs": { 8 | "description": "Additional arguments for the pytest command", 9 | "type": "string", 10 | "default": "" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/executor/pytest-executor.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | const {BufferedProcess} = require('atom'); 4 | 5 | export default class PytestExecutor { 6 | 7 | constructor(dock){ 8 | this.dock = dock; 9 | } 10 | 11 | executePyTest(filePath, pythonCommandPath, additionalArgs){ 12 | tmp = require('tmp'); 13 | testResultsFilename = tmp.fileSync({prefix: 'results', keep : true, postfix: '.xml'}); 14 | args = ['-m', 'pytest', filePath, '--junit-xml=' + testResultsFilename.name]; 15 | 16 | if (additionalArgs) { 17 | console.log('Considering the additional args...') 18 | var args = args.concat(additionalArgs.split(" ")); 19 | } 20 | 21 | error = null; 22 | 23 | command = pythonCommandPath; 24 | process = new BufferedProcess({ 25 | command, 26 | args, 27 | stdout: (out) => { 28 | }, 29 | stderr: (out) => { 30 | error = out; 31 | }, 32 | exit: (status) => { 33 | if (!error){ 34 | junitViewer = require('junit-viewer'); 35 | parsedResults = junitViewer.parse(testResultsFilename.name); 36 | this.dock.printOutput(parsedResults); 37 | } else { 38 | this.dock.printError(error); 39 | } 40 | 41 | } 42 | }); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /menus/atom-python-test.cson: -------------------------------------------------------------------------------- 1 | 'context-menu': 2 | 'atom-text-editor': [ 3 | { 4 | 'label': 'Py.test' 5 | 'submenu': [ 6 | { 7 | 'label': 'Run test under cursor' 8 | 'command': 'atom-python-test:run-test-under-cursor' 9 | } 10 | { 11 | 'label': 'Run all tests on file' 12 | 'command': 'atom-python-test:run-all-tests' 13 | } 14 | ] 15 | } 16 | ] 17 | 'menu': [ 18 | { 19 | 'label': 'Packages' 20 | 'submenu': [ 21 | 'label': 'Atom Python Test' 22 | 'submenu': [ 23 | { 24 | 'label': 'Toggle tests results' 25 | 'command': 'atom-python-test:toggle-test-results' 26 | } 27 | ] 28 | ] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-python-test", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "2.1.26", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "align-text": { 17 | "version": "0.1.4", 18 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 19 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 20 | "requires": { 21 | "kind-of": "3.2.2", 22 | "longest": "1.0.1", 23 | "repeat-string": "1.6.1" 24 | } 25 | }, 26 | "amdefine": { 27 | "version": "1.0.1", 28 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 29 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" 30 | }, 31 | "array-flatten": { 32 | "version": "1.1.1", 33 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 34 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 35 | }, 36 | "async": { 37 | "version": "0.2.10", 38 | "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", 39 | "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" 40 | }, 41 | "balanced-match": { 42 | "version": "1.0.0", 43 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 44 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 45 | }, 46 | "body-parser": { 47 | "version": "1.19.0", 48 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 49 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 50 | "requires": { 51 | "bytes": "3.1.0", 52 | "content-type": "1.0.4", 53 | "debug": "2.6.9", 54 | "depd": "1.1.2", 55 | "http-errors": "1.7.2", 56 | "iconv-lite": "0.4.24", 57 | "on-finished": "2.3.0", 58 | "qs": "6.7.0", 59 | "raw-body": "2.4.0", 60 | "type-is": "1.6.18" 61 | } 62 | }, 63 | "brace-expansion": { 64 | "version": "1.1.11", 65 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 66 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 67 | "requires": { 68 | "balanced-match": "1.0.0", 69 | "concat-map": "0.0.1" 70 | } 71 | }, 72 | "bytes": { 73 | "version": "3.1.0", 74 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 75 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 76 | }, 77 | "camelcase": { 78 | "version": "1.2.1", 79 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 80 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" 81 | }, 82 | "center-align": { 83 | "version": "0.1.3", 84 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 85 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 86 | "requires": { 87 | "align-text": "0.1.4", 88 | "lazy-cache": "1.0.4" 89 | } 90 | }, 91 | "clean-css": { 92 | "version": "3.4.28", 93 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", 94 | "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", 95 | "requires": { 96 | "commander": "2.8.1", 97 | "source-map": "0.4.4" 98 | }, 99 | "dependencies": { 100 | "commander": { 101 | "version": "2.8.1", 102 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", 103 | "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", 104 | "requires": { 105 | "graceful-readlink": "1.0.1" 106 | } 107 | } 108 | } 109 | }, 110 | "cliui": { 111 | "version": "2.1.0", 112 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 113 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 114 | "requires": { 115 | "center-align": "0.1.3", 116 | "right-align": "0.1.3", 117 | "wordwrap": "0.0.2" 118 | } 119 | }, 120 | "commander": { 121 | "version": "2.9.0", 122 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 123 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", 124 | "requires": { 125 | "graceful-readlink": "1.0.1" 126 | } 127 | }, 128 | "concat-map": { 129 | "version": "0.0.1", 130 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 131 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 132 | }, 133 | "content-disposition": { 134 | "version": "0.5.3", 135 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 136 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 137 | "requires": { 138 | "safe-buffer": "5.1.2" 139 | } 140 | }, 141 | "content-type": { 142 | "version": "1.0.4", 143 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 144 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 145 | }, 146 | "cookie": { 147 | "version": "0.4.0", 148 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 149 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 150 | }, 151 | "cookie-signature": { 152 | "version": "1.0.6", 153 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 154 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 155 | }, 156 | "debug": { 157 | "version": "2.6.9", 158 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 159 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 160 | "requires": { 161 | "ms": "2.0.0" 162 | } 163 | }, 164 | "decamelize": { 165 | "version": "1.2.0", 166 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 167 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 168 | }, 169 | "depd": { 170 | "version": "1.1.2", 171 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 172 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 173 | }, 174 | "destroy": { 175 | "version": "1.0.4", 176 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 177 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 178 | }, 179 | "ee-first": { 180 | "version": "1.1.1", 181 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 182 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 183 | }, 184 | "encodeurl": { 185 | "version": "1.0.2", 186 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 187 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 188 | }, 189 | "escape-html": { 190 | "version": "1.0.3", 191 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 192 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 193 | }, 194 | "etag": { 195 | "version": "1.8.1", 196 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 197 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 198 | }, 199 | "express": { 200 | "version": "4.17.1", 201 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 202 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 203 | "requires": { 204 | "accepts": "1.3.7", 205 | "array-flatten": "1.1.1", 206 | "body-parser": "1.19.0", 207 | "content-disposition": "0.5.3", 208 | "content-type": "1.0.4", 209 | "cookie": "0.4.0", 210 | "cookie-signature": "1.0.6", 211 | "debug": "2.6.9", 212 | "depd": "1.1.2", 213 | "encodeurl": "1.0.2", 214 | "escape-html": "1.0.3", 215 | "etag": "1.8.1", 216 | "finalhandler": "1.1.2", 217 | "fresh": "0.5.2", 218 | "merge-descriptors": "1.0.1", 219 | "methods": "1.1.2", 220 | "on-finished": "2.3.0", 221 | "parseurl": "1.3.3", 222 | "path-to-regexp": "0.1.7", 223 | "proxy-addr": "2.0.5", 224 | "qs": "6.7.0", 225 | "range-parser": "1.2.1", 226 | "safe-buffer": "5.1.2", 227 | "send": "0.17.1", 228 | "serve-static": "1.14.1", 229 | "setprototypeof": "1.1.1", 230 | "statuses": "1.5.0", 231 | "type-is": "1.6.18", 232 | "utils-merge": "1.0.1", 233 | "vary": "1.1.2" 234 | } 235 | }, 236 | "finalhandler": { 237 | "version": "1.1.2", 238 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 239 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 240 | "requires": { 241 | "debug": "2.6.9", 242 | "encodeurl": "1.0.2", 243 | "escape-html": "1.0.3", 244 | "on-finished": "2.3.0", 245 | "parseurl": "1.3.3", 246 | "statuses": "1.5.0", 247 | "unpipe": "1.0.0" 248 | } 249 | }, 250 | "forwarded": { 251 | "version": "0.1.2", 252 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 253 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 254 | }, 255 | "fresh": { 256 | "version": "0.5.2", 257 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 258 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 259 | }, 260 | "fs.realpath": { 261 | "version": "1.0.0", 262 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 263 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 264 | }, 265 | "glob": { 266 | "version": "7.1.6", 267 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 268 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 269 | "requires": { 270 | "fs.realpath": "1.0.0", 271 | "inflight": "1.0.6", 272 | "inherits": "2.0.3", 273 | "minimatch": "3.0.4", 274 | "once": "1.4.0", 275 | "path-is-absolute": "1.0.1" 276 | } 277 | }, 278 | "graceful-readlink": { 279 | "version": "1.0.1", 280 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", 281 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" 282 | }, 283 | "html-minify": { 284 | "version": "0.3.2", 285 | "resolved": "https://registry.npmjs.org/html-minify/-/html-minify-0.3.2.tgz", 286 | "integrity": "sha1-MmBLI7Jn6i5nmX4IFM3NQlATnfA=", 287 | "requires": { 288 | "clean-css": "3.4.28", 289 | "commander": "2.9.0", 290 | "iconv-lite": "0.4.24", 291 | "uglify-js": "2.6.4" 292 | } 293 | }, 294 | "http-errors": { 295 | "version": "1.7.2", 296 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 297 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 298 | "requires": { 299 | "depd": "1.1.2", 300 | "inherits": "2.0.3", 301 | "setprototypeof": "1.1.1", 302 | "statuses": "1.5.0", 303 | "toidentifier": "1.0.0" 304 | } 305 | }, 306 | "iconv-lite": { 307 | "version": "0.4.24", 308 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 309 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 310 | "requires": { 311 | "safer-buffer": "2.1.2" 312 | } 313 | }, 314 | "inflight": { 315 | "version": "1.0.6", 316 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 317 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 318 | "requires": { 319 | "once": "1.4.0", 320 | "wrappy": "1.0.2" 321 | } 322 | }, 323 | "inherits": { 324 | "version": "2.0.3", 325 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 326 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 327 | }, 328 | "ipaddr.js": { 329 | "version": "1.9.0", 330 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 331 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 332 | }, 333 | "is-buffer": { 334 | "version": "1.1.6", 335 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 336 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 337 | }, 338 | "junit-viewer": { 339 | "version": "4.11.1", 340 | "resolved": "https://registry.npmjs.org/junit-viewer/-/junit-viewer-4.11.1.tgz", 341 | "integrity": "sha1-MfcSeJqSqBVgX7Erwr6fazd8NPc=", 342 | "requires": { 343 | "express": "4.17.1", 344 | "html-minify": "0.3.2", 345 | "mustache": "2.3.2", 346 | "xml2js": "0.4.23" 347 | } 348 | }, 349 | "kind-of": { 350 | "version": "3.2.2", 351 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 352 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 353 | "requires": { 354 | "is-buffer": "1.1.6" 355 | } 356 | }, 357 | "lazy-cache": { 358 | "version": "1.0.4", 359 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 360 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" 361 | }, 362 | "longest": { 363 | "version": "1.0.1", 364 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 365 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" 366 | }, 367 | "media-typer": { 368 | "version": "0.3.0", 369 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 370 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 371 | }, 372 | "merge-descriptors": { 373 | "version": "1.0.1", 374 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 375 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 376 | }, 377 | "methods": { 378 | "version": "1.1.2", 379 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 380 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 381 | }, 382 | "mime": { 383 | "version": "1.6.0", 384 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 385 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 386 | }, 387 | "mime-db": { 388 | "version": "1.43.0", 389 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", 390 | "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" 391 | }, 392 | "mime-types": { 393 | "version": "2.1.26", 394 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", 395 | "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", 396 | "requires": { 397 | "mime-db": "1.43.0" 398 | } 399 | }, 400 | "minimatch": { 401 | "version": "3.0.4", 402 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 403 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 404 | "requires": { 405 | "brace-expansion": "1.1.11" 406 | } 407 | }, 408 | "ms": { 409 | "version": "2.0.0", 410 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 411 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 412 | }, 413 | "mustache": { 414 | "version": "2.3.2", 415 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz", 416 | "integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==" 417 | }, 418 | "negotiator": { 419 | "version": "0.6.2", 420 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 421 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 422 | }, 423 | "on-finished": { 424 | "version": "2.3.0", 425 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 426 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 427 | "requires": { 428 | "ee-first": "1.1.1" 429 | } 430 | }, 431 | "once": { 432 | "version": "1.4.0", 433 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 434 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 435 | "requires": { 436 | "wrappy": "1.0.2" 437 | } 438 | }, 439 | "parseurl": { 440 | "version": "1.3.3", 441 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 442 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 443 | }, 444 | "path-is-absolute": { 445 | "version": "1.0.1", 446 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 447 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 448 | }, 449 | "path-to-regexp": { 450 | "version": "0.1.7", 451 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 452 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 453 | }, 454 | "proxy-addr": { 455 | "version": "2.0.5", 456 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 457 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 458 | "requires": { 459 | "forwarded": "0.1.2", 460 | "ipaddr.js": "1.9.0" 461 | } 462 | }, 463 | "qs": { 464 | "version": "6.7.0", 465 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 466 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 467 | }, 468 | "range-parser": { 469 | "version": "1.2.1", 470 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 471 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 472 | }, 473 | "raw-body": { 474 | "version": "2.4.0", 475 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 476 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 477 | "requires": { 478 | "bytes": "3.1.0", 479 | "http-errors": "1.7.2", 480 | "iconv-lite": "0.4.24", 481 | "unpipe": "1.0.0" 482 | } 483 | }, 484 | "repeat-string": { 485 | "version": "1.6.1", 486 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 487 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" 488 | }, 489 | "right-align": { 490 | "version": "0.1.3", 491 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 492 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 493 | "requires": { 494 | "align-text": "0.1.4" 495 | } 496 | }, 497 | "rimraf": { 498 | "version": "2.7.1", 499 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 500 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 501 | "requires": { 502 | "glob": "7.1.6" 503 | } 504 | }, 505 | "safe-buffer": { 506 | "version": "5.1.2", 507 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 508 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 509 | }, 510 | "safer-buffer": { 511 | "version": "2.1.2", 512 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 513 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 514 | }, 515 | "sax": { 516 | "version": "1.2.4", 517 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 518 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 519 | }, 520 | "send": { 521 | "version": "0.17.1", 522 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 523 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 524 | "requires": { 525 | "debug": "2.6.9", 526 | "depd": "1.1.2", 527 | "destroy": "1.0.4", 528 | "encodeurl": "1.0.2", 529 | "escape-html": "1.0.3", 530 | "etag": "1.8.1", 531 | "fresh": "0.5.2", 532 | "http-errors": "1.7.2", 533 | "mime": "1.6.0", 534 | "ms": "2.1.1", 535 | "on-finished": "2.3.0", 536 | "range-parser": "1.2.1", 537 | "statuses": "1.5.0" 538 | }, 539 | "dependencies": { 540 | "ms": { 541 | "version": "2.1.1", 542 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 543 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 544 | } 545 | } 546 | }, 547 | "serve-static": { 548 | "version": "1.14.1", 549 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 550 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 551 | "requires": { 552 | "encodeurl": "1.0.2", 553 | "escape-html": "1.0.3", 554 | "parseurl": "1.3.3", 555 | "send": "0.17.1" 556 | } 557 | }, 558 | "setprototypeof": { 559 | "version": "1.1.1", 560 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 561 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 562 | }, 563 | "source-map": { 564 | "version": "0.4.4", 565 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 566 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 567 | "requires": { 568 | "amdefine": "1.0.1" 569 | } 570 | }, 571 | "statuses": { 572 | "version": "1.5.0", 573 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 574 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 575 | }, 576 | "tmp": { 577 | "version": "0.1.0", 578 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", 579 | "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", 580 | "requires": { 581 | "rimraf": "2.7.1" 582 | } 583 | }, 584 | "toidentifier": { 585 | "version": "1.0.0", 586 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 587 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 588 | }, 589 | "type-is": { 590 | "version": "1.6.18", 591 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 592 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 593 | "requires": { 594 | "media-typer": "0.3.0", 595 | "mime-types": "2.1.26" 596 | } 597 | }, 598 | "uglify-js": { 599 | "version": "2.6.4", 600 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", 601 | "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", 602 | "requires": { 603 | "async": "0.2.10", 604 | "source-map": "0.5.7", 605 | "uglify-to-browserify": "1.0.2", 606 | "yargs": "3.10.0" 607 | }, 608 | "dependencies": { 609 | "source-map": { 610 | "version": "0.5.7", 611 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 612 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 613 | } 614 | } 615 | }, 616 | "uglify-to-browserify": { 617 | "version": "1.0.2", 618 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 619 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=" 620 | }, 621 | "unpipe": { 622 | "version": "1.0.0", 623 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 624 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 625 | }, 626 | "utils-merge": { 627 | "version": "1.0.1", 628 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 629 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 630 | }, 631 | "vary": { 632 | "version": "1.1.2", 633 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 634 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 635 | }, 636 | "window-size": { 637 | "version": "0.1.0", 638 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 639 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" 640 | }, 641 | "wordwrap": { 642 | "version": "0.0.2", 643 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 644 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" 645 | }, 646 | "wrappy": { 647 | "version": "1.0.2", 648 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 649 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 650 | }, 651 | "xml2js": { 652 | "version": "0.4.23", 653 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", 654 | "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", 655 | "requires": { 656 | "sax": "1.2.4", 657 | "xmlbuilder": "11.0.1" 658 | } 659 | }, 660 | "xmlbuilder": { 661 | "version": "11.0.1", 662 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 663 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" 664 | }, 665 | "yargs": { 666 | "version": "3.10.0", 667 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 668 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 669 | "requires": { 670 | "camelcase": "1.2.1", 671 | "cliui": "2.1.0", 672 | "decamelize": "1.2.0", 673 | "window-size": "0.1.0" 674 | } 675 | } 676 | } 677 | } 678 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-python-test", 3 | "main": "./lib/atom-python-test", 4 | "version": "1.0.1", 5 | "description": "Run py.test tests using Python", 6 | "keywords": [ 7 | "python", 8 | "tests", 9 | "runner", 10 | "py.test", 11 | "pytest" 12 | ], 13 | "repository": "https://github.com/pghilardi/atom-python-test", 14 | "license": "MIT", 15 | "engines": { 16 | "atom": ">=1.0.0 <2.0.0" 17 | }, 18 | "dependencies": { 19 | "tmp": "*", 20 | "junit-viewer": "*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /styles/atom-python-test.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | // 3 | // See https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less 4 | // for a full listing of what's available. 5 | @import "ui-variables"; 6 | 7 | .atom-python-test { 8 | overflow-y: scroll; 9 | } 10 | 11 | .tests { 12 | table-layout: fixed; 13 | border-collapse: collapse; 14 | width: 100%; 15 | } 16 | 17 | .tests tr { 18 | border-bottom: 0.25px solid #383838; 19 | } 20 | 21 | .tests td { 22 | white-space:pre-wrap; 23 | } 24 | 25 | .tests thead { 26 | background-color: #525452; 27 | color: white; 28 | } 29 | 30 | .tests td { 31 | // white-space: nowrap; 32 | overflow: hidden; 33 | text-overflow: ellipsis; 34 | } 35 | 36 | td.failure-line { 37 | color: #ed766b; 38 | } 39 | 40 | td.success-line { 41 | color: #83e695; 42 | } 43 | --------------------------------------------------------------------------------