From 03e72163dab70b97bbe7d11cf2378b7ba00992ba Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 10 Nov 2019 17:43:07 -0800 Subject: [PATCH 1/6] remove unused --- src/actions/setupActions.ts | 108 +++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts index fed92c67..43ec5a8d 100644 --- a/src/actions/setupActions.ts +++ b/src/actions/setupActions.ts @@ -4,34 +4,34 @@ import * as vscode from 'vscode' import * as git from '../services/git' import node from '../services/node' -interface ErrorMessageFilter { - [lang: string]: { - [key: string]: string - } -} +// interface ErrorMessageFilter { +// [lang: string]: { +// [key: string]: string +// } +// } // TODO: should be loaded on startup based on language -const commandErrorMessageFilter: ErrorMessageFilter = { - JAVASCRIPT: { - 'node-gyp': 'Error running npm setup command' - } -} +// const commandErrorMessageFilter: ErrorMessageFilter = { +// JAVASCRIPT: { +// 'node-gyp': 'Error running npm setup command' +// } +// } // TODO: pass command and command name down for filtering. Eg. JAVASCRIPT, 'npm install' -const runCommands = async (commands: string[], language: string = 'JAVASCRIPT') => { +const runCommands = async (commands: string[]) => { for (const command of commands) { const {stdout, stderr} = await node.exec(command) if (stderr) { console.error(stderr) // language specific error messages from running commands - const filteredMessages = Object.keys(commandErrorMessageFilter[language]) - for (const message of filteredMessages) { - if (stderr.match(message)) { - // ignored error - throw new Error('Error running setup command') - } - } + // const filteredMessages = Object.keys(commandErrorMessageFilter[language]) + // for (const message of filteredMessages) { + // if (stderr.match(message)) { + // // ignored error + // throw new Error('Error running setup command') + // } + // } } console.log(`run command: ${command}`, stdout) } @@ -45,7 +45,8 @@ const disposeWatcher = (listener: string) => { delete watchers[listener] } -const setupActions = async (workspaceRoot: vscode.WorkspaceFolder, {commands, commits, files, listeners}: G.StepActions): Promise => { +const setupActions = async (workspaceRoot: vscode.WorkspaceFolder, actions: G.StepActions): Promise => { + const {commands, commits, files, listeners} = actions // run commits if (commits) { for (const commit of commits) { @@ -54,31 +55,50 @@ const setupActions = async (workspaceRoot: vscode.WorkspaceFolder, {commands, co } // run file watchers (listeners) - if (listeners) { - for (const listener of listeners) { - if (!watchers[listener]) { - const pattern = new vscode.RelativePattern( - vscode.workspace.getWorkspaceFolder(workspaceRoot.uri)!, - listener - ) - watchers[listener] = vscode.workspace.createFileSystemWatcher( - pattern - ) - watchers[listener].onDidChange(() => { - // trigger save - vscode.commands.executeCommand('coderoad.run_test', null, () => { - // cleanup watcher on success - disposeWatcher(listener) - }) - }) - } - } - } else { - // remove all watchers - for (const listener of Object.keys(watchers)) { - disposeWatcher(listener) - } - } + // if (listeners) { + // console.log('listeners') + // for (const listener of listeners) { + // if (!watchers[listener]) { + // const pattern = new vscode.RelativePattern( + // vscode.workspace.getWorkspaceFolder(workspaceRoot.uri)!, + // listener + // ) + // console.log(pattern) + // watchers[listener] = vscode.workspace.createFileSystemWatcher( + // pattern + // ) + // watchers[listener].onDidChange(() => { + // console.log('onDidChange') + // // trigger save + // vscode.commands.executeCommand('coderoad.run_test', null, () => { + // // cleanup watcher on success + // disposeWatcher(listener) + // }) + // }) + // watchers[listener].onDidCreate(() => { + // console.log('onDidCreate') + // // trigger save + // vscode.commands.executeCommand('coderoad.run_test', null, () => { + // // cleanup watcher on success + // disposeWatcher(listener) + // }) + // }) + // watchers[listener].onDidDelete(() => { + // console.log('onDidDelete') + // // trigger save + // vscode.commands.executeCommand('coderoad.run_test', null, () => { + // // cleanup watcher on success + // disposeWatcher(listener) + // }) + // }) + // } + // } + // } else { + // // remove all watchers + // for (const listener of Object.keys(watchers)) { + // disposeWatcher(listener) + // } + // } // run command if (commands) { From ab13f524e58d84e26e4416e7499a54a5823a6f68 Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 12 Nov 2019 19:28:56 -0800 Subject: [PATCH 2/6] createTestRunner in progress --- src/actions/{runTest.ts => runTest/index.ts} | 113 +++++++++++-------- src/actions/setupActions.ts | 89 +++++++-------- typings/index.d.ts | 1 + web-app/.vscode/settings.json | 1 + web-app/src/services/state/machine.ts | 8 +- 5 files changed, 118 insertions(+), 94 deletions(-) rename src/actions/{runTest.ts => runTest/index.ts} (52%) create mode 100644 web-app/.vscode/settings.json diff --git a/src/actions/runTest.ts b/src/actions/runTest/index.ts similarity index 52% rename from src/actions/runTest.ts rename to src/actions/runTest/index.ts index 5af4183e..4cdf1f8a 100644 --- a/src/actions/runTest.ts +++ b/src/actions/runTest/index.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode' -import node from '../services/node' +import node from '../../services/node' // TODO: use tap parser to make it easier to support other test runners @@ -21,31 +21,49 @@ const getOutputChannel = (name: string): vscode.OutputChannel => { return channel } -interface Props { +interface Callbacks { onSuccess(): void onFail(): void onRun(): void onError(): void } -async function runTest({onSuccess, onFail, onRun, onError}: Props): Promise { - console.log('------------------- run test ------------------') - // increment process id - const processId = ++currentId +interface TestRunnerConfig { + command: string + parser(output: string): boolean +} + +export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { + + const outputChannelName = 'TEST_OUTPUT' + + return { + run() { + console.log('------------------- run test ------------------') + const processId = ++currentId + callbacks.onRun() + + try { + const {stdout} = await node.exec(config.command) + } + } + } +} + +async function runTest({onSuccess, onFail, onRun, onError}: Callbacks): Promise { + - onRun() - const outputChannelName = 'Test Output' // TODO: verify test runner for args // jest CLI docs https://jestjs.io/docs/en/cli - const testArgs = [ - '--json', - '--onlyChanged', - '--env=node', - '--maxConcurrency=4', - '--maxWorkers=4' - ] + // const testArgs = [ + // '--json', + // '--onlyChanged', + // '--env=node', + // '--maxConcurrency=4', + // '--maxWorkers=4' + // ] const commandLine = `npm test -- ${testArgs.join(' ')}` @@ -61,23 +79,22 @@ async function runTest({onSuccess, onFail, onRun, onError}: Props): Promise 0) { + const regExp = /^{\"numFailedTestSuites/ + const matches = regExp.exec(line) + if (matches && matches.length) { + const result = JSON.parse(line) + + if (result.success) { + if (shouldExitEarly(processId)) { + // exit early + return + } + console.log('success!') + onSuccess() + } else { + console.log('NOT SUCCESS?') } - onSuccess() - } else { - console.log('NOT SUCCESS?') } } } @@ -104,25 +121,23 @@ async function runTest({onSuccess, onFail, onRun, onError}: Props): Promise t.status === 'failed') - - if (firstError) { - if (shouldExitEarly(processId)) { - // exit early - return + if (line.length > 0) { + const dataRegExp = /^{\"numFailedTestSuites"/ + const matches = dataRegExp.exec(line) + + if (matches && matches.length) { + const result = JSON.parse(line) + const firstError = result.testResults.find((t: any) => t.status === 'failed') + + if (firstError) { + if (shouldExitEarly(processId)) { + // exit early + return + } + onFail() + } else { + console.error('NOTE: PARSER DID NOT WORK FOR ', line) } - onFail() - } else { - console.error('NOTE: PARSER DID NOT WORK FOR ', line) } } } diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts index 43ec5a8d..33aab5fa 100644 --- a/src/actions/setupActions.ts +++ b/src/actions/setupActions.ts @@ -55,50 +55,51 @@ const setupActions = async (workspaceRoot: vscode.WorkspaceFolder, actions: G.St } // run file watchers (listeners) - // if (listeners) { - // console.log('listeners') - // for (const listener of listeners) { - // if (!watchers[listener]) { - // const pattern = new vscode.RelativePattern( - // vscode.workspace.getWorkspaceFolder(workspaceRoot.uri)!, - // listener - // ) - // console.log(pattern) - // watchers[listener] = vscode.workspace.createFileSystemWatcher( - // pattern - // ) - // watchers[listener].onDidChange(() => { - // console.log('onDidChange') - // // trigger save - // vscode.commands.executeCommand('coderoad.run_test', null, () => { - // // cleanup watcher on success - // disposeWatcher(listener) - // }) - // }) - // watchers[listener].onDidCreate(() => { - // console.log('onDidCreate') - // // trigger save - // vscode.commands.executeCommand('coderoad.run_test', null, () => { - // // cleanup watcher on success - // disposeWatcher(listener) - // }) - // }) - // watchers[listener].onDidDelete(() => { - // console.log('onDidDelete') - // // trigger save - // vscode.commands.executeCommand('coderoad.run_test', null, () => { - // // cleanup watcher on success - // disposeWatcher(listener) - // }) - // }) - // } - // } - // } else { - // // remove all watchers - // for (const listener of Object.keys(watchers)) { - // disposeWatcher(listener) - // } - // } + if (listeners) { + console.log('listeners') + for (const listener of listeners) { + if (!watchers[listener]) { + const pattern = new vscode.RelativePattern( + vscode.workspace.getWorkspaceFolder(workspaceRoot.uri)!, + listener + ) + console.log(pattern) + const listen = vscode.workspace.createFileSystemWatcher( + pattern + ) + watchers[listener] = listen + watchers[listener].onDidChange(() => { + console.log('onDidChange') + // trigger save + vscode.commands.executeCommand('coderoad.run_test', null, () => { + // cleanup watcher on success + disposeWatcher(listener) + }) + }) + watchers[listener].onDidCreate(() => { + console.log('onDidCreate') + // trigger save + vscode.commands.executeCommand('coderoad.run_test', null, () => { + // cleanup watcher on success + disposeWatcher(listener) + }) + }) + watchers[listener].onDidDelete(() => { + console.log('onDidDelete') + // trigger save + vscode.commands.executeCommand('coderoad.run_test', null, () => { + // cleanup watcher on success + disposeWatcher(listener) + }) + }) + } + } + } else { + // remove all watchers + for (const listener of Object.keys(watchers)) { + disposeWatcher(listener) + } + } // run command if (commands) { diff --git a/typings/index.d.ts b/typings/index.d.ts index fb075999..8edb29f4 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -74,6 +74,7 @@ export interface MachineStateSchema { TestRunning: {} TestPass: {} TestFail: {} + TestError: {} StepNext: {} LevelComplete: {} } diff --git a/web-app/.vscode/settings.json b/web-app/.vscode/settings.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/web-app/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index db5ab0f0..a15e8eae 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -134,9 +134,15 @@ export const machine = Machine Date: Tue, 12 Nov 2019 22:18:26 -0800 Subject: [PATCH 3/6] setup Test Runner --- src/actions/runTest/channel.ts | 10 ++ src/actions/runTest/index.ts | 153 ------------------------------ src/actions/runTest/testRunner.ts | 69 ++++++++++++++ src/actions/runTest/throttle.ts | 8 ++ 4 files changed, 87 insertions(+), 153 deletions(-) create mode 100644 src/actions/runTest/channel.ts create mode 100644 src/actions/runTest/testRunner.ts create mode 100644 src/actions/runTest/throttle.ts diff --git a/src/actions/runTest/channel.ts b/src/actions/runTest/channel.ts new file mode 100644 index 00000000..a2eeb224 --- /dev/null +++ b/src/actions/runTest/channel.ts @@ -0,0 +1,10 @@ +import * as vscode from 'vscode' + +let channel: vscode.OutputChannel + +export const getOutputChannel = (name: string): vscode.OutputChannel => { + if (!channel) { + channel = vscode.window.createOutputChannel(name) + } + return channel +} \ No newline at end of file diff --git a/src/actions/runTest/index.ts b/src/actions/runTest/index.ts index 4cdf1f8a..e69de29b 100644 --- a/src/actions/runTest/index.ts +++ b/src/actions/runTest/index.ts @@ -1,153 +0,0 @@ -import * as vscode from 'vscode' -import node from '../../services/node' - -// TODO: use tap parser to make it easier to support other test runners - -// ensure only latest run_test action is taken -let currentId = 0 - -// quick solution to prevent processing multiple results -// NOTE: may be possible to kill child process early -const shouldExitEarly = (processId: number): boolean => { - return currentId !== processId -} - -let channel: vscode.OutputChannel - -const getOutputChannel = (name: string): vscode.OutputChannel => { - if (!channel) { - channel = vscode.window.createOutputChannel(name) - } - return channel -} - -interface Callbacks { - onSuccess(): void - onFail(): void - onRun(): void - onError(): void -} - -interface TestRunnerConfig { - command: string - parser(output: string): boolean -} - -export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { - - const outputChannelName = 'TEST_OUTPUT' - - return { - run() { - console.log('------------------- run test ------------------') - const processId = ++currentId - callbacks.onRun() - - try { - const {stdout} = await node.exec(config.command) - } - } - } -} - -async function runTest({onSuccess, onFail, onRun, onError}: Callbacks): Promise { - - - - - // TODO: verify test runner for args - // jest CLI docs https://jestjs.io/docs/en/cli - // const testArgs = [ - // '--json', - // '--onlyChanged', - // '--env=node', - // '--maxConcurrency=4', - // '--maxWorkers=4' - // ] - - const commandLine = `npm test -- ${testArgs.join(' ')}` - - try { - // capture position early on test start - // in case position changes - const {stdout} = await node.exec(commandLine) - if (shouldExitEarly(processId)) { - // exit early - return - } - - if (stdout) { - const lines = stdout.split(/\r{0,1}\n/) - for (const line of lines) { - if (line.length > 0) { - const regExp = /^{\"numFailedTestSuites/ - const matches = regExp.exec(line) - if (matches && matches.length) { - const result = JSON.parse(line) - - if (result.success) { - if (shouldExitEarly(processId)) { - // exit early - return - } - console.log('success!') - onSuccess() - } else { - console.log('NOT SUCCESS?') - } - } - } - } - } - } catch (err) { - if (shouldExitEarly(processId)) { - // exit early - return - } - // error contains output & error message - // output can be parsed as json - const {stdout, stderr} = err - console.log('TEST FAILED', stdout) - - if (!stdout) { - console.error('SOMETHING WENT WRONG WITH A PASSING TEST') - onError() - return - } - // test runner failed - channel = getOutputChannel(outputChannelName) - - if (stdout) { - const lines = stdout.split(/\r{0,1}\n/) - - for (const line of lines) { - if (line.length > 0) { - const dataRegExp = /^{\"numFailedTestSuites"/ - const matches = dataRegExp.exec(line) - - if (matches && matches.length) { - const result = JSON.parse(line) - const firstError = result.testResults.find((t: any) => t.status === 'failed') - - if (firstError) { - if (shouldExitEarly(processId)) { - // exit early - return - } - onFail() - } else { - console.error('NOTE: PARSER DID NOT WORK FOR ', line) - } - } - } - } - } - - if (stderr) { - channel.show(false) - channel.appendLine(stderr) - } - } -} - -export default runTest \ No newline at end of file diff --git a/src/actions/runTest/testRunner.ts b/src/actions/runTest/testRunner.ts new file mode 100644 index 00000000..0b5349ab --- /dev/null +++ b/src/actions/runTest/testRunner.ts @@ -0,0 +1,69 @@ +import node from '../../services/node' +import {getOutputChannel} from './channel' +import {setLatestProcess, isLatestProcess} from './throttle' + +// TODO: use tap parser to make it easier to support other test runners +// TODO: how to load test runner parser +// TODO: where to instantiate test runner + + +interface Callbacks { + onSuccess(): void + onFail(): void + onRun(): void + onError(): void +} + +interface TestRunnerConfig { + command: string + parser(output: string): Error | null +} + +export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { + + const outputChannelName = 'TEST_OUTPUT' + + return async () => { + console.log('------------------- run test ------------------') + + // track processId to prevent multiple + const processId = setLatestProcess() + if (!isLatestProcess(processId)) {return } + + // flag as running + callbacks.onRun() + + let result: {stdout: string | undefined, stderr: string | undefined} + try { + result = await node.exec(config.command) + } catch (err) { + result = err + } + const {stdout, stderr} = result + + // simple way to throttle requests + if (!stdout || !isLatestProcess(processId)) {return } + + if (stderr) { + callbacks.onError() + + // open terminal with error string + const channel = getOutputChannel(outputChannelName) + channel.show(false) + channel.appendLine(stderr) + return + } + + // pass or fail? + const testsFailed = config.parser(stdout) + if (testsFailed === null) { + callbacks.onSuccess() + } else { + // open terminal with failed test string + const channel = getOutputChannel(outputChannelName) + channel.show(false) + channel.appendLine(testsFailed.message) + callbacks.onFail() + } + } +} diff --git a/src/actions/runTest/throttle.ts b/src/actions/runTest/throttle.ts new file mode 100644 index 00000000..d5e8eba9 --- /dev/null +++ b/src/actions/runTest/throttle.ts @@ -0,0 +1,8 @@ +// ensure only latest run_test action is taken +let currentId = 0 + +export const setLatestProcess = () => currentId++ + +// quick solution to prevent processing multiple results +// NOTE: may be possible to kill child process early +export const isLatestProcess = (processId: number): boolean => currentId === processId \ No newline at end of file From 284e1f7b0e8a0162ba7e8887aa5ccd5564f9a282 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 13 Nov 2019 21:34:32 -0800 Subject: [PATCH 4/6] reconfigure test runner --- package-lock.json | 57 +++++++++++++++++++ package.json | 3 +- src/actions/runTest/index.ts | 0 src/actions/tutorialConfig.ts | 23 +++++++- src/editor/ReactWebView.ts | 1 - src/editor/commands.ts | 42 +++++++------- src/editor/index.ts | 1 - .../channel.ts => editor/outputChannel.ts} | 0 .../testRunner/index.ts} | 45 ++++++++------- src/services/testRunner/parser.ts | 10 ++++ .../testRunner}/throttle.ts | 2 +- typings/graphql.d.ts | 28 ++++++--- typings/lib.d.ts | 13 +++++ 13 files changed, 170 insertions(+), 55 deletions(-) delete mode 100644 src/actions/runTest/index.ts rename src/{actions/runTest/channel.ts => editor/outputChannel.ts} (100%) rename src/{actions/runTest/testRunner.ts => services/testRunner/index.ts} (55%) create mode 100644 src/services/testRunner/parser.ts rename src/{actions/runTest => services/testRunner}/throttle.ts (92%) create mode 100644 typings/lib.d.ts diff --git a/package-lock.json b/package-lock.json index d7f71e03..fb56f581 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,14 @@ "js-tokens": "^4.0.0" } }, + "@babel/runtime": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", + "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, "@types/assert": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.4.3.tgz", @@ -617,6 +625,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "events-to-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", + "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=" + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -1166,6 +1179,14 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, + "minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "requires": { + "yallist": "^4.0.0" + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -1634,6 +1655,11 @@ "pify": "^3.0.0" } }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1947,6 +1973,24 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "tap-parser": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.0.1.tgz", + "integrity": "sha512-qdT15H0DoJIi7zOqVXDn9X0gSM68JjNy1w3VemwTJlDnETjbi6SutnqmBfjDJAwkFS79NJ97gZKqie00ZCGmzg==", + "requires": { + "events-to-array": "^1.0.1", + "minipass": "^3.0.0", + "tap-yaml": "^1.0.0" + } + }, + "tap-yaml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz", + "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==", + "requires": { + "yaml": "^1.5.0" + } + }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", @@ -2341,6 +2385,19 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz", + "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==", + "requires": { + "@babel/runtime": "^7.6.3" + } + }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", diff --git a/package.json b/package.json index ffca5f5e..00a01a9e 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "jsdom": "^15.2.1" + "jsdom": "^15.2.1", + "tap-parser": "^10.0.1" }, "devDependencies": { "@types/assert": "^1.4.3", diff --git a/src/actions/runTest/index.ts b/src/actions/runTest/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts index 9093cfe6..d8a11343 100644 --- a/src/actions/tutorialConfig.ts +++ b/src/actions/tutorialConfig.ts @@ -1,7 +1,7 @@ import * as G from 'typings/graphql' import * as vscode from 'vscode' import * as git from '../services/git' -import langaugeMap from '../editor/languageMap' +import languageMap from '../editor/languageMap' interface TutorialConfigParams { config: G.TutorialConfig, @@ -19,10 +19,27 @@ const tutorialConfig = async ({config, alreadyConfigured, }: TutorialConfigParam await git.setupRemote(config.repo.uri) } + vscode.commands.executeCommand('coderoad.config_test_runner', config.testRunner) + + const fileFormats = config.testRunner.fileFormats + + // verify if file test should run based on document saved + const shouldRun = (document: vscode.TextDocument): boolean => { + if (document.uri.scheme !== 'file') { + return false + } + if (fileFormats && fileFormats.length) { + const fileFormat: G.FileFormat = languageMap[document.languageId] + if (!fileFormats.includes(fileFormat)) { + return false + } + } + return true + } + // setup onSave hook vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { - const fileFormat: G.FileFormat = langaugeMap[document.languageId] - if (document.uri.scheme === 'file' && config.fileFormats.includes(fileFormat)) { + if (shouldRun(document)) { vscode.commands.executeCommand('coderoad.run_test') } }) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 91483acb..ae49424f 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -161,7 +161,6 @@ class ReactWebView { } } - // set CSP (content security policy) to grant permission to local files const cspMeta: HTMLMetaElement = document.createElement('meta') cspMeta.httpEquiv = 'Content-Security-Policy' diff --git a/src/editor/commands.ts b/src/editor/commands.ts index 2ed22d99..dfb345f2 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -1,10 +1,12 @@ +import * as G from 'typings/graphql' import * as vscode from 'vscode' import ReactWebView from './ReactWebView' -import runTest from '../actions/runTest' +import createTestRunner, {Payload} from '../services/testRunner' const COMMANDS = { START: 'coderoad.start', OPEN_WEBVIEW: 'coderoad.open_webview', + CONFIG_TEST_RUNNER: 'coderoad.config_test_runner', RUN_TEST: 'coderoad.run_test', SET_CURRENT_STEP: 'coderoad.set_current_step', } @@ -19,6 +21,7 @@ export const createCommands = ({extensionPath, workspaceState, workspaceRoot}: C // React panel webview let webview: any let currentStepId = '' + let testRunner: any return { // initialize @@ -49,37 +52,38 @@ export const createCommands = ({extensionPath, workspaceState, workspaceRoot}: C // setup 1x1 horizontal layout webview.createOrShow() }, - [COMMANDS.SET_CURRENT_STEP]: ({stepId}: {stepId: string}) => { - // NOTE: as async, may sometimes be inaccurate - // set from last setup stepAction - currentStepId = stepId - }, - [COMMANDS.RUN_TEST]: (current: {stepId: string} | undefined, onSuccess: () => void) => { - console.log('-------- command.run_test ------ ') - // use stepId from client, or last set stepId - const payload = {stepId: current ? current.stepId : currentStepId} - runTest({ - onSuccess: () => { + [COMMANDS.CONFIG_TEST_RUNNER]: (config: G.TutorialTestRunner) => { + testRunner = createTestRunner(config, { + onSuccess: (payload: Payload) => { // send test pass message back to client - webview.send({type: 'TEST_PASS', payload}) - onSuccess() vscode.window.showInformationMessage('PASS') + webview.send({type: 'TEST_PASS', payload}) }, - onFail: () => { + onFail: (payload: Payload) => { // send test fail message back to client - webview.send({type: 'TEST_FAIL', payload}) vscode.window.showWarningMessage('FAIL') + webview.send({type: 'TEST_FAIL', payload}) }, - onError: () => { - console.log('COMMAND TEST_ERROR') + onError: (payload: Payload) => { // send test error message back to client webview.send({type: 'TEST_ERROR', payload}) }, - onRun: () => { + onRun: (payload: Payload) => { // send test run message back to client webview.send({type: 'TEST_RUNNING', payload}) } }) }, + [COMMANDS.SET_CURRENT_STEP]: ({stepId}: Payload) => { + // NOTE: as async, may sometimes be inaccurate + // set from last setup stepAction + currentStepId = stepId + }, + [COMMANDS.RUN_TEST]: (current: Payload | undefined, onSuccess: () => void) => { + console.log('-------- command.run_test ------ ') + // use stepId from client, or last set stepId + const payload: Payload = {stepId: current ? current.stepId : currentStepId} + testRunner(payload, onSuccess) + }, } } diff --git a/src/editor/index.ts b/src/editor/index.ts index d35a7ab5..7d6a48b1 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -29,7 +29,6 @@ class Editor { } private activateCommands = (): void => { - // set workspace root for node executions const workspaceRoots: vscode.WorkspaceFolder[] | undefined = vscode.workspace.workspaceFolders if (!workspaceRoots || !workspaceRoots.length) { diff --git a/src/actions/runTest/channel.ts b/src/editor/outputChannel.ts similarity index 100% rename from src/actions/runTest/channel.ts rename to src/editor/outputChannel.ts diff --git a/src/actions/runTest/testRunner.ts b/src/services/testRunner/index.ts similarity index 55% rename from src/actions/runTest/testRunner.ts rename to src/services/testRunner/index.ts index 0b5349ab..c19a7a83 100644 --- a/src/actions/runTest/testRunner.ts +++ b/src/services/testRunner/index.ts @@ -1,29 +1,28 @@ import node from '../../services/node' -import {getOutputChannel} from './channel' +import {getOutputChannel} from '../../editor/outputChannel' +import parser from './parser' import {setLatestProcess, isLatestProcess} from './throttle' -// TODO: use tap parser to make it easier to support other test runners -// TODO: how to load test runner parser -// TODO: where to instantiate test runner - +export interface Payload { + stepId: string +} interface Callbacks { - onSuccess(): void - onFail(): void - onRun(): void - onError(): void + onSuccess(payload: Payload): void + onFail(payload: Payload): void + onRun(payload: Payload): void + onError(payload: Payload): void } interface TestRunnerConfig { command: string - parser(output: string): Error | null } -export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { +const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { const outputChannelName = 'TEST_OUTPUT' - return async () => { + return async (payload: Payload, onSuccess?: () => void) => { console.log('------------------- run test ------------------') // track processId to prevent multiple @@ -31,7 +30,7 @@ export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) if (!isLatestProcess(processId)) {return } // flag as running - callbacks.onRun() + callbacks.onRun(payload) let result: {stdout: string | undefined, stderr: string | undefined} try { @@ -45,7 +44,7 @@ export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) if (!stdout || !isLatestProcess(processId)) {return } if (stderr) { - callbacks.onError() + callbacks.onError(payload) // open terminal with error string const channel = getOutputChannel(outputChannelName) @@ -55,15 +54,19 @@ export const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) } // pass or fail? - const testsFailed = config.parser(stdout) - if (testsFailed === null) { - callbacks.onSuccess() + const {ok} = parser(stdout) + if (ok) { + callbacks.onSuccess(payload) + if (onSuccess) {onSuccess()} } else { + // TODO: parse failure message // open terminal with failed test string - const channel = getOutputChannel(outputChannelName) - channel.show(false) - channel.appendLine(testsFailed.message) - callbacks.onFail() + // const channel = getOutputChannel(outputChannelName) + // channel.show(false) + // channel.appendLine(testsFailed.message) + callbacks.onFail(payload) } } } + +export default createTestRunner \ No newline at end of file diff --git a/src/services/testRunner/parser.ts b/src/services/testRunner/parser.ts new file mode 100644 index 00000000..5e6f7c0e --- /dev/null +++ b/src/services/testRunner/parser.ts @@ -0,0 +1,10 @@ +import TapParser from 'tap-parser' + +// https://github.com/tapjs/tap-parser#var-p--new-parseroptions-cb +const options = { + bail: true, +} + +const parser = new TapParser(options) + +export default parser \ No newline at end of file diff --git a/src/actions/runTest/throttle.ts b/src/services/testRunner/throttle.ts similarity index 92% rename from src/actions/runTest/throttle.ts rename to src/services/testRunner/throttle.ts index d5e8eba9..cf096b93 100644 --- a/src/actions/runTest/throttle.ts +++ b/src/services/testRunner/throttle.ts @@ -5,4 +5,4 @@ export const setLatestProcess = () => currentId++ // quick solution to prevent processing multiple results // NOTE: may be possible to kill child process early -export const isLatestProcess = (processId: number): boolean => currentId === processId \ No newline at end of file +export const isLatestProcess = (processId: number): boolean => currentId === processId diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index 42a04d09..76f3d893 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -136,8 +136,6 @@ export type StepActions = { listeners?: Maybe> } -export type TestRunner = 'JEST' - /** A tutorial for use in VSCode CodeRoad */ export type Tutorial = { __typename?: 'Tutorial' @@ -157,8 +155,7 @@ export type TutorialVersionArgs = { /** Configure environment in editor for git, testing & parsing files */ export type TutorialConfig = { __typename?: 'TutorialConfig' - testRunner: TestRunner - fileFormats: Array + testRunner: TutorialTestRunner repo: TutorialRepo } @@ -197,6 +194,12 @@ export type TutorialSummary = { description: Scalars['String'] } +export type TutorialTestRunner = { + __typename?: 'TutorialTestRunner' + command: Scalars['String'] + fileFormats?: Maybe> +} + /** A version of a tutorial */ export type TutorialVersion = { __typename?: 'TutorialVersion' @@ -308,7 +311,7 @@ export type ResolversTypes = { TutorialSummary: ResolverTypeWrapper TutorialData: ResolverTypeWrapper TutorialConfig: ResolverTypeWrapper - TestRunner: TestRunner + TutorialTestRunner: ResolverTypeWrapper FileFormat: FileFormat TutorialRepo: ResolverTypeWrapper TutorialInit: ResolverTypeWrapper @@ -345,7 +348,7 @@ export type ResolversParentTypes = { TutorialSummary: TutorialSummary TutorialData: TutorialData TutorialConfig: TutorialConfig - TestRunner: TestRunner + TutorialTestRunner: TutorialTestRunner FileFormat: FileFormat TutorialRepo: TutorialRepo TutorialInit: TutorialInit @@ -514,8 +517,7 @@ export type TutorialConfigResolvers< ContextType = any, ParentType extends ResolversParentTypes['TutorialConfig'] = ResolversParentTypes['TutorialConfig'] > = { - testRunner?: Resolver - fileFormats?: Resolver, ParentType, ContextType> + testRunner?: Resolver repo?: Resolver } @@ -553,6 +555,14 @@ export type TutorialSummaryResolvers< description?: Resolver } +export type TutorialTestRunnerResolvers< + ContextType = any, + ParentType extends ResolversParentTypes['TutorialTestRunner'] = ResolversParentTypes['TutorialTestRunner'] + > = { + command?: Resolver + fileFormats?: Resolver>, ParentType, ContextType> + } + export type TutorialVersionResolvers< ContextType = any, ParentType extends ResolversParentTypes['TutorialVersion'] = ResolversParentTypes['TutorialVersion'] @@ -604,6 +614,7 @@ export type Resolvers = { TutorialInit?: TutorialInitResolvers TutorialRepo?: TutorialRepoResolvers TutorialSummary?: TutorialSummaryResolvers + TutorialTestRunner?: TutorialTestRunnerResolvers TutorialVersion?: TutorialVersionResolvers User?: UserResolvers } @@ -634,3 +645,4 @@ export interface IntrospectionResultData { }[] } } + diff --git a/typings/lib.d.ts b/typings/lib.d.ts new file mode 100644 index 00000000..f8f66f94 --- /dev/null +++ b/typings/lib.d.ts @@ -0,0 +1,13 @@ +declare module 'tap-parser' { + type TapParserOutput = { + ok: boolean + count: number + pass: number + plan: { + start: number + end: number + } + } + const Parser: any + export default Parser +} From 9b9ed40a86c542bd4becd114596c161e18223eef Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 13 Nov 2019 22:14:03 -0800 Subject: [PATCH 5/6] configure tutorial progress --- src/actions/tutorialConfig.ts | 9 ++++++--- src/editor/commands.ts | 2 +- src/services/testRunner/index.ts | 2 +- src/services/testRunner/parser.ts | 2 +- web-app/src/services/apollo/queries/tutorial.ts | 6 ++++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts index d8a11343..058cf93a 100644 --- a/src/actions/tutorialConfig.ts +++ b/src/actions/tutorialConfig.ts @@ -2,6 +2,7 @@ import * as G from 'typings/graphql' import * as vscode from 'vscode' import * as git from '../services/git' import languageMap from '../editor/languageMap' +import {COMMANDS} from '../editor/commands' interface TutorialConfigParams { config: G.TutorialConfig, @@ -19,15 +20,17 @@ const tutorialConfig = async ({config, alreadyConfigured, }: TutorialConfigParam await git.setupRemote(config.repo.uri) } - vscode.commands.executeCommand('coderoad.config_test_runner', config.testRunner) + vscode.commands.executeCommand(COMMANDS.CONFIG_TEST_RUNNER, config.testRunner) const fileFormats = config.testRunner.fileFormats // verify if file test should run based on document saved - const shouldRun = (document: vscode.TextDocument): boolean => { + const shouldRunTest = (document: vscode.TextDocument): boolean => { + // must be a file if (document.uri.scheme !== 'file') { return false } + // must configure with file formatss if (fileFormats && fileFormats.length) { const fileFormat: G.FileFormat = languageMap[document.languageId] if (!fileFormats.includes(fileFormat)) { @@ -39,7 +42,7 @@ const tutorialConfig = async ({config, alreadyConfigured, }: TutorialConfigParam // setup onSave hook vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { - if (shouldRun(document)) { + if (shouldRunTest(document)) { vscode.commands.executeCommand('coderoad.run_test') } }) diff --git a/src/editor/commands.ts b/src/editor/commands.ts index dfb345f2..da7b226c 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode' import ReactWebView from './ReactWebView' import createTestRunner, {Payload} from '../services/testRunner' -const COMMANDS = { +export const COMMANDS = { START: 'coderoad.start', OPEN_WEBVIEW: 'coderoad.open_webview', CONFIG_TEST_RUNNER: 'coderoad.config_test_runner', diff --git a/src/services/testRunner/index.ts b/src/services/testRunner/index.ts index c19a7a83..17d09fa9 100644 --- a/src/services/testRunner/index.ts +++ b/src/services/testRunner/index.ts @@ -22,7 +22,7 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { const outputChannelName = 'TEST_OUTPUT' - return async (payload: Payload, onSuccess?: () => void) => { + return async (payload: Payload, onSuccess?: () => void): Promise => { console.log('------------------- run test ------------------') // track processId to prevent multiple diff --git a/src/services/testRunner/parser.ts b/src/services/testRunner/parser.ts index 5e6f7c0e..1e77c21e 100644 --- a/src/services/testRunner/parser.ts +++ b/src/services/testRunner/parser.ts @@ -1,4 +1,4 @@ -import TapParser from 'tap-parser' +const TapParser = require('tap-parser') // https://github.com/tapjs/tap-parser#var-p--new-parseroptions-cb const options = { diff --git a/web-app/src/services/apollo/queries/tutorial.ts b/web-app/src/services/apollo/queries/tutorial.ts index a364b4cb..c339f914 100644 --- a/web-app/src/services/apollo/queries/tutorial.ts +++ b/web-app/src/services/apollo/queries/tutorial.ts @@ -12,8 +12,10 @@ export default gql` } data { config { - testRunner - fileFormats + testRunner { + command + fileFormats + } repo { uri branch From ea29d2333044c9053d78a2a91f44a2eff81f2457 Mon Sep 17 00:00:00 2001 From: shmck Date: Thu, 14 Nov 2019 08:21:46 -0800 Subject: [PATCH 6/6] create basic tap-parser --- package-lock.json | 57 ------------------------------- package.json | 3 +- src/editor/commands.ts | 1 - src/services/testRunner/index.ts | 10 ++---- src/services/testRunner/parser.ts | 17 +++++---- 5 files changed, 15 insertions(+), 73 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb56f581..d7f71e03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,14 +24,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/runtime": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", - "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, "@types/assert": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.4.3.tgz", @@ -625,11 +617,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "events-to-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", - "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=" - }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -1179,14 +1166,6 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, - "minipass": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", - "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", - "requires": { - "yallist": "^4.0.0" - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -1655,11 +1634,6 @@ "pify": "^3.0.0" } }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" - }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1973,24 +1947,6 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, - "tap-parser": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.0.1.tgz", - "integrity": "sha512-qdT15H0DoJIi7zOqVXDn9X0gSM68JjNy1w3VemwTJlDnETjbi6SutnqmBfjDJAwkFS79NJ97gZKqie00ZCGmzg==", - "requires": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - } - }, - "tap-yaml": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz", - "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==", - "requires": { - "yaml": "^1.5.0" - } - }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", @@ -2385,19 +2341,6 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yaml": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz", - "integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==", - "requires": { - "@babel/runtime": "^7.6.3" - } - }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", diff --git a/package.json b/package.json index 00a01a9e..ffca5f5e 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,7 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "jsdom": "^15.2.1", - "tap-parser": "^10.0.1" + "jsdom": "^15.2.1" }, "devDependencies": { "@types/assert": "^1.4.3", diff --git a/src/editor/commands.ts b/src/editor/commands.ts index da7b226c..1b157364 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -80,7 +80,6 @@ export const createCommands = ({extensionPath, workspaceState, workspaceRoot}: C currentStepId = stepId }, [COMMANDS.RUN_TEST]: (current: Payload | undefined, onSuccess: () => void) => { - console.log('-------- command.run_test ------ ') // use stepId from client, or last set stepId const payload: Payload = {stepId: current ? current.stepId : currentStepId} testRunner(payload, onSuccess) diff --git a/src/services/testRunner/index.ts b/src/services/testRunner/index.ts index 17d09fa9..ad32b1c6 100644 --- a/src/services/testRunner/index.ts +++ b/src/services/testRunner/index.ts @@ -25,10 +25,6 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { return async (payload: Payload, onSuccess?: () => void): Promise => { console.log('------------------- run test ------------------') - // track processId to prevent multiple - const processId = setLatestProcess() - if (!isLatestProcess(processId)) {return } - // flag as running callbacks.onRun(payload) @@ -41,7 +37,7 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { const {stdout, stderr} = result // simple way to throttle requests - if (!stdout || !isLatestProcess(processId)) {return } + if (!stdout) {return } if (stderr) { callbacks.onError(payload) @@ -54,8 +50,8 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => { } // pass or fail? - const {ok} = parser(stdout) - if (ok) { + const tap = parser(stdout) + if (tap.ok) { callbacks.onSuccess(payload) if (onSuccess) {onSuccess()} } else { diff --git a/src/services/testRunner/parser.ts b/src/services/testRunner/parser.ts index 1e77c21e..e5f6967b 100644 --- a/src/services/testRunner/parser.ts +++ b/src/services/testRunner/parser.ts @@ -1,10 +1,15 @@ -const TapParser = require('tap-parser') - -// https://github.com/tapjs/tap-parser#var-p--new-parseroptions-cb -const options = { - bail: true, +interface ParserOutput { + ok: boolean } -const parser = new TapParser(options) +const parser = (text: string): ParserOutput => { + const lines = text.split('\n') + for (const line of lines) { + if (line.match(/^not ok /)) { + return {ok: false} + } + } + return {ok: true} +} export default parser \ No newline at end of file