Skip to content

Feature/refactor test runner #53

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
reconfigure test runner
  • Loading branch information
ShMcK committed Nov 14, 2019
commit 284e1f7b0e8a0162ba7e8887aa5ccd5564f9a282
57 changes: 57 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Empty file removed src/actions/runTest/index.ts
Empty file.
23 changes: 20 additions & 3 deletions src/actions/tutorialConfig.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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')
}
})
Expand Down
1 change: 0 additions & 1 deletion src/editor/ReactWebView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
42 changes: 23 additions & 19 deletions src/editor/commands.ts
Original file line number Diff line number Diff line change
@@ -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',
}
Expand All @@ -19,6 +21,7 @@ export const createCommands = ({extensionPath, workspaceState, workspaceRoot}: C
// React panel webview
let webview: any
let currentStepId = ''
let testRunner: any

return {
// initialize
Expand Down Expand Up @@ -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)
},
}
}
1 change: 0 additions & 1 deletion src/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
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
const processId = setLatestProcess()
if (!isLatestProcess(processId)) {return }

// flag as running
callbacks.onRun()
callbacks.onRun(payload)

let result: {stdout: string | undefined, stderr: string | undefined}
try {
Expand All @@ -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)
Expand All @@ -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
10 changes: 10 additions & 0 deletions src/services/testRunner/parser.ts
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
export const isLatestProcess = (processId: number): boolean => currentId === processId
Loading