8000 Merge pull request #311 from coderoad/feature/test-failure · dcmade01/coderoad-vscode@e8d10b8 · GitHub
[go: up one dir, main page]

Skip to content

Commit e8d10b8

Browse files
authored
Merge pull request coderoad#311 from coderoad/feature/test-failure
Feature/test failure
2 parents 7fdc351 + 623c737 commit e8d10b8

File tree

20 files changed

+93
-36
lines changed
  • stories
  • 20 files changed

    +93
    -36
    lines changed

    CHANGELOG.md

    Lines changed: 6 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -101,3 +101,9 @@ Resulting in a folder structure like the following:
    101101
    - Continue an incomplete tutorial started in the same workspace. Choose the "continue" path from the start screen. Progress is stored in local storage in the workspace.
    102102

    103103
    ![continue tutorial](./docs/images/continue-tutorial.png)
    104+
    105+
    ## [0.5.0]
    106+
    107+
    - Show error messages in the webview UI
    108+
    109+
    ![fail message in webview](./do F438 cs/images/fail-message-in-webview.png)
    96.9 KB
    Loading

    src/channel/index.ts

    Lines changed: 4 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -14,6 +14,7 @@ import { openWorkspace, checkWorkspaceEmpty } from '../services/workspace'
    1414
    import { readFile } from 'fs'
    1515
    import { join } from 'path'
    1616
    import { promisify } from 'util'
    17+
    import { showOutput } from '../services/testRunner/output'
    1718
    import { WORKSPACE_ROOT } from '../environment'
    1819

    1920
    const readFileAsync = promisify(readFile)
    @@ -300,7 +301,9 @@ class Channel implements Channel {
    300301
    // update progress when a level is deemed complete in the client
    301302
    await this.context.progress.syncProgress(action.payload.progress)
    302303
    return
    303-
    304+
    case 'EDITOR_OPEN_LOGS':
    305+
    const channel = action.payload.channel
    306+
    await showOutput(channel)
    304307
    default:
    305308
    logger(`No match for action type: ${actionType}`)
    306309
    return

    src/editor/commands.ts

    Lines changed: 3 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -3,7 +3,7 @@ import * as TT from 'typings/tutorial'
    33
    import * as vscode from 'vscode'
    44
    import createTestRunner from '../services/testRunner'
    55
    import { setupActions } from '../actions/setupActions'
    6-
    import createWebView from '../webview'
    6+
    import createWebView from '../services/webview'
    77
    import logger from '../services/logger'
    88

    99
    export const COMMANDS = {
    @@ -62,9 +62,9 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP
    6262
    // send test pass message back to client
    6363
    webview.send({ type: 'TEST_PASS', payload: { position } })
    6464
    },
    65-
    onFail: (position: T.Position, message: string) => {
    65+
    onFail: (position: T.Position, failSummary: T.TestFail): void => {
    6666
    // send test fail message back to client with failure message
    67-
    webview.send({ type: 'TEST_FAIL', payload: { position, message } })
    67+
    webview.send({ type: 'TEST_FAIL', payload: { position, fail: failSummary } })
    6868
    },
    6969
    onError: (position: T.Position) => {
    7070
    // TODO: send test error message back to client

    src/environment.ts

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -10,7 +10,7 @@ export type Env = 'test' | 'local' | 'development' | 'production'
    1010
    export const NODE_ENV: Env = process.env.NODE_ENV || 'production'
    1111

    1212
    // toggle logging in development
    13-
    export const LOG = false
    13+
    export const LOG = true
    1414

    1515
    // error logging tool
    1616
    export const SENTRY_DSN: string | null = null

    src/services/testRunner/formatOutput.ts

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -4,7 +4,7 @@ import { ParserOutput, Fail } from './parser'
    44
    // export const formatSuccessOutput = (tap: ParserOutput): string => {}
    55

    66
    export const formatFailOutput = (tap: ParserOutput): string => {
    7-
    let output = `FAILED TESTS\n`
    7+
    let output = `FAILED TEST LOG\n`
    88
    tap.failed.forEach((fail: Fail) => {
    99
    const details = fail.details ? `\n${fail.details}\n` : ''
    1010
    const logs = fail.logs ? `\n${fail.logs.join('\n')}\n` : ''

    src/services/testRunner/index.ts

    Lines changed: 11 additions & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,12 +5,12 @@ import logger from '../logger'
    55
    import parser from './parser'
    66
    import { debounce, throttle } from './throttle'
    77
    import onError from '../sentry/onError'
    8-
    import { clearOutput, displayOutput } from './output'
    8+
    import { clearOutput, addOutput } from './output'
    99
    import { formatFailOutput } from './formatOutput'
    1010

    1111
    interface Callbacks {
    1212
    onSuccess(position: T.Position): void
    13-
    onFail(position: T.Position, message: string): void
    13+
    onFail(position: T.Position, failSummary: T.TestFail): void
    1414
    onRun(position: T.Position): void
    1515
    onError(position: T.Position): void
    1616
    }
    @@ -51,20 +51,24 @@ const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callba
    5151

    5252
    const tap = parser(stdout || '')
    5353

    54-
    displayOutput({ channel: logChannelName, text: tap.logs.join('\n'), show: false })
    54+
    addOutput({ channel: logChannelName, text: tap.logs.join('\n'), show: false })
    5555

    5656
    if (stderr) {
    5757
    // FAIL also trigger stderr
    5858
    if (stdout && stdout.length && !tap.ok) {
    59-
    const firstFailMessage = tap.failed[0].message
    60-
    callbacks.onFail(position, firstFailMessage)
    59+
    const firstFail = tap.failed[0]
    60+
    const failSummary = {
    61+
    title: firstFail.message || 'Test Failed',
    62+
    description: firstFail.details || 'Unknown error',
    63+
    }
    64+
    callbacks.onFail(position, failSummary)
    6165
    const output = formatFailOutput(tap)
    62-
    displayOutput({ channel: failChannelName, text: output, show: true })
    66+
    addOutput({ channel: failChannelName, text: output, show: true })
    6367
    return
    6468
    } else {
    6569
    callbacks.onError(position)
    6670
    // open terminal with error string
    67-
    displayOutput({ channel: failChannelName, text: stderr, show: true })
    71+
    addOutput({ channel: failChannelName, text: stderr, show: true })
    6872
    return
    6973
    }
    7074
    }

    src/services/testRunner/output.ts

    Lines changed: 7 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -9,22 +9,25 @@ const getOutputChannel = (name: string): vscode.OutputChannel => {
    99
    return channels[name]
    1010
    }
    1111

    12-
    interface DisplayOutput {
    12+
    interface ChannelOutput {
    1313
    channel: string
    1414
    text: string
    1515
    show?: boolean
    1616
    }
    1717

    18-
    export const displayOutput = (params: DisplayOutput) => {
    18+
    export const addOutput = (params: ChannelOutput) => {
    1919
    const channel = getOutputChannel(params.channel)
    2020
    channel.clear()
    21-
    channel.show(params.show || false)
    2221
    channel.append(params.text)
    2322
    }
    2423

    24+
    export const showOutput = (channelName: string) => {
    25+
    const channel = getOutputChannel(channelName)
    26+
    channel.show()
    27+
    }
    28+
    2529
    export const clearOutput = (channelName: string) => {
    2630
    const channel = getOutputChannel(channelName)
    27-
    channel.show(false)
    2831
    channel.clear()
    2932
    channel.hide()
    3033
    }

    src/webview/index.ts renamed to src/services/webview/index.ts

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,7 +1,7 @@
    11
    import * as path from 'path'
    22
    import { Action } from 'typings'
    33
    import * as vscode from 'vscode'
    4-
    import Channel from '../channel'
    4+
    import Channel from '../../channel'
    55
    import render from './render'
    66

    77
    interface ReactWebViewProps {

    src/webview/render.ts renamed to src/services/webview/render.ts

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,7 +1,7 @@
    11
    import { JSDOM } from 'jsdom'
    22
    import * as path from 'path'
    33
    import * as vscode from 'vscode'
    4-
    import onError from '../services/sentry/onError'
    4+
    import onError from '../sentry/onError'
    55

    66
    const getNonce = (): string => {
    77
    let text = ''

    typings/index.d.ts

    Lines changed: 6 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -42,6 +42,7 @@ export interface TestStatus {
    4242
    type: 'success' | 'warning' | 'error' | 'loading'
    4343
    title: string
    4444
    content?: string
    45+
    timeout?: number
    4546
    }
    4647

    4748
    export interface MachineContext {
    @@ -116,3 +117,8 @@ export interface ProcessEvent {
    116117
    description: string
    117118
    status: 'RUNNING' | 'SUCCESS' | 'FAIL' | 'ERROR'
    118119
    }
    120+
    121+
    export type TestFail = {
    122+
    title: string
    123+
    description: string
    124+
    }

    web-app/src/components/Message/index.tsx

    Lines changed: 5 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -11,6 +11,7 @@ interface Props {
    1111
    closeable?: boolean
    1212
    onClose?: () => void
    1313
    handleClose?: () => void
    14+
    children?: React.ReactElement | null
    1415
    }
    1516

    1617
    const Message = (props: Props) => {
    @@ -30,7 +31,10 @@ const Message = (props: Props) => {
    3031
    onClose={onClose}
    3132
    shape={props.shape}
    3233
    >
    33-
    {props.content}
    34+
    <div>
    35+
    <div>{props.content}</div>
    36+
    <div>{props.children}</div>
    37+
    </div>
    3438
    </AlifdMessage>
    3539
    )
    3640
    }

    web-app/src/components/ProcessMessages/TestMessage.tsx

    Lines changed: 5 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,7 +5,7 @@ import { css, jsx } from '@emotion/core'
    55

    66
    const durations = {
    77
    success: 1000,
    8-
    warning: 4500,
    8+
    warning: 20000,
    99
    error: 4500,
    1010
    loading: 300000,
    1111
    }
    @@ -24,7 +24,7 @@ const useTimeout = ({ duration, key }: { duration: number; key: string }) => {
    2424
    return timeoutClose
    2525
    }
    2626

    27-
    const TestMessage = (props: T.TestStatus) => {
    27+
    const TestMessage = (props: T.TestStatus & { children?: React.ReactElement | null }) => {
    2828
    const duration = durations[props.type]
    2929
    const timeoutClose = useTimeout({ duration, key: props.title })
    3030
    return (
    @@ -36,7 +36,9 @@ const TestMessage = (props: T.TestStatus) => {
    3636
    size="medium"
    3737
    closeable={props.type !== 'loading'}
    3838
    content={props.content}
    39-
    />
    39+
    >
    40+
    {props.children}
    41+
    </Message>
    4042
    )
    4143
    }
    4244

    web-app/src/components/ProcessMessages/index.tsx

    Lines changed: 16 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,12 +1,14 @@
    11
    import Message from '../Message'
    22
    import * as React from 'react'
    33
    import * as T from 'typings'
    4+
    import Button from '../Button'
    45
    import { css, jsx } from '@emotion/core'
    56
    import TestMessage from './TestMessage'
    67

    78
    interface Props {
    89
    testStatus?: T.TestStatus | null
    910
    processes: T.ProcessEvent[]
    11+
    onOpenLogs?: (channel: string) => void
    1012
    }
    1113

    1214
    const styles = {
    @@ -17,9 +19,21 @@ const styles = {
    1719
    }
    1820

    1921
    // display a list of active processes
    20-
    const ProcessMessages = ({ processes, testStatus }: Props) => {
    22+
    const ProcessMessages = ({ processes, testStatus, onOpenLogs }: Props) => {
    2123
    if (testStatus) {
    22-
    return <TestMessage {...testStatus} />
    24+
    return (
    25+
    <TestMessage {...testStatus}>
    26+
    {testStatus.type === 'warning' ? (
    27+
    <Button
    28+
    onClick={() => onOpenLogs && onOpenLogs('CodeRoad (Tests)')}
    29+
    type="normal"
    30+
    style={{ marginTop: '0.8rem' }}
    31+
    >
    32+
    Open Logs
    33+
    </Button>
    34+
    ) : null}
    35+
    </TestMessage>
    36+
    )
    2337
    }
    2438
    if (!processes.length) {
    2539
    return null

    web-app/src/containers/Tutorial/components/Level.tsx

    Lines changed: 3 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -96,6 +96,7 @@ interface Props {
    9696
    testStatus: T.TestStatus | null
    9797
    onContinue(): void
    9898
    onLoadSolution(): void
    99+
    onOpenLogs(channel: string): void
    99100
    }
    100101

    101102
    const Level = ({
    @@ -107,6 +108,7 @@ const Level = ({
    107108
    status,
    108109
    onContinue,
    109110
    onLoadSolution,
    111+
    onOpenLogs,
    110112
    processes,
    111113
    testStatus,
    112114
    }: Props) => {
    @@ -170,7 +172,7 @@ const Level = ({
    170172

    171173
    {(testStatus || processes.length > 0) && (
    172174
    <div css={styles.processes}>
    173-
    <ProcessMessages processes={processes} testStatus={testStatus} />
    175+
    <ProcessMessages processes={processes} testStatus={testStatus} onOpenLogs={onOpenLogs} />
    174176
    </div>
    175177
    )}
    176178

    web-app/src/containers/Tutorial/index.tsx

    Lines changed: 5 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -32,6 +32,10 @@ const TutorialPage = (props: PageProps) => {
    3232
    props.send({ type: 'STEP_SOLUTION_LOAD' })
    3333
    }
    3434

    35+
    const onOpenLogs = (channel: string): void => {
    36+
    props.send({ type: 'OPEN_LOGS', payload: { channel } })
    37+
    }
    38+
    3539
    const steps = levelData.steps.map((step: TT.Step) => {
    3640
    // label step status for step component
    3741
    let status: T.ProgressStatus = 'INCOMPLETE'
    @@ -61,6 +65,7 @@ const TutorialPage = (props: PageProps) => {
    6165
    status={progress.levels[position.levelId] ? 'COMPLETE' : 'ACTIVE'}
    6266
    onContinue={onContinue}
    6367
    onLoadSolution={onLoadSolution}
    68+
    onOpenLogs={onOpenLogs}
    6469
    processes={processes}
    6570
    testStatus={testStatus}
    6671
    />

    web-app/src/services/state/actions/editor.ts

    Lines changed: 13 additions & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,4 +1,4 @@
    1-
    import * as CR from 'typings'
    1+
    import * as T from 'typings'
    22
    import * as TT from 'typings/tutorial'
    33
    import * as selectors from '../../selectors'
    44

    @@ -8,7 +8,7 @@ export default (editorSend: any) => ({
    88
    type: 'EDITOR_STARTUP',
    99
    })
    1010
    },
    11-
    configureNewTutorial(context: CR.MachineContext) {
    11+
    configureNewTutorial(context: T.MachineContext) {
    1212
    editorSend({
    1313
    type: 'EDITOR_TUTORIAL_CONFIG',
    1414
    payload: {
    @@ -17,7 +17,7 @@ export default (editorSend: any) => ({
    1717
    },
    1818
    })
    1919
    },
    20-
    continueConfig(context: CR.MachineContext) {
    20+
    continueConfig(context: T.MachineContext) {
    2121
    editorSend({
    2222
    type: 'EDITOR_TUTORIAL_CONTINUE_CONFIG',
    2323
    payload: {
    @@ -26,7 +26,7 @@ export default (editorSend: any) => ({
    2626
    },
    2727
    })
    2828
    },
    29-
    loadLevel(context: CR.MachineContext): void {
    29+
    loadLevel(context: T.MachineContext): void {
    3030
    const level: TT.Level = selectors.currentLevel(context)
    3131
    const step: TT.Step | null = selectors.currentStep(context)
    3232
    // load step actions
    @@ -41,7 +41,7 @@ export default (editorSend: any) => ({
    4141
    },
    4242
    })
    4343
    },
    44-
    loadStep(context: CR.MachineContext): void {
    44+
    loadStep(context: T.MachineContext): void {
    4545
    const step: TT.Step | null = selectors.currentStep(context)
    4646
    if (step && step.setup) {
    4747
    // load step actions
    @@ -58,7 +58,7 @@ export default (editorSend: any) => ({
    5858
    })
    5959
    }
    6060
    },
    61-
    editorLoadSolution(context: CR.MachineContext): void {
    61+
    editorLoadSolution(context: T.MachineContext): void {
    6262
    const step: TT.Step | null = selectors.currentStep(context)
    6363
    // tell editor to load solution commit
    6464
    if (step && step.solution) {
    @@ -74,7 +74,7 @@ export default (editorSend: any) => ({
    7474
    })
    7575
    }
    7676
    },
    77-
    syncLevelProgress(context: CR.MachineContext): void {
    77+
    syncLevelProgress(context: T.MachineContext): void {
    7878
    editorSend({
    7979
    type: 'EDITOR_SYNC_PROGRESS',
    8080
    payload: {
    @@ -95,4 +95,10 @@ export default (editorSend: any) => ({
    9595
    type: 'EDITOR_REQUEST_WORKSPACE',
    9696
    })
    9797
    },
    98+
    editorOpenLogs(context: T.MachineContext, event: T.MachineEvent): void {
    99+
    editorSend({
    100+
    type: 'EDITOR_OPEN_LOGS',
    101+
    payload: { channel: event.payload.channel },
    102+
    })
    103+
    },
    98104
    })

    web-app/src/services/state/actions/testNotify.ts

    Lines changed: 2 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -20,8 +20,8 @@ const testActions: ActionFunctionMap<CR.MachineContext, CR.MachineEvent> = {
    2020
    testFail: assign({
    2121
    testStatus: (context, event) => ({
    2222
    type: 'warning',
    23-
    title: 'Fail!',
    24-
    content: event.payload.message,
    23+
    title: event.payload.fail.title,
    24+
    content: event.payload.fail.description,
    2525
    }),
    2626
    }),
    2727
    // @ts-ignore

    0 commit comments

    Comments
     (0)
    0