Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Feature/test parser#184

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ShMcK merged 5 commits intomasterfromfeature/test-parser
Apr 4, 2020
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletionssrc/services/testRunner/formatOutput.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
// @ts-ignore no declaration files
import * as clc from 'cli-color'
import { ParserOutput } from './parser'

// TODO: implement better success ouput
// export const formatSuccessOutput = (tap: ParserOutput): string => {}

export const formatFailOutput = (tap: ParserOutput): string => {
let output = `'TESTS FAILED\n`
tap.failed.forEach((fail) => {
const details = fail.details ? `\n${fail.details}\n\n` : ''
output += ` ✘ ${fail.message}\n${details}`
})
return output
}
12 changes: 7 additions & 5 deletionssrc/services/testRunner/index.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import parser from './parser'
import { debounce, throttle } from './throttle'
import onError from '../sentry/onError'
import { clearOutput, displayOutput } from './output'
import { formatFailOutput } from './formatOutput'

export interface Payload {
stepId: string
Expand DownExpand Up@@ -52,11 +53,12 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => {

const tap = parser(stdout || '')
if (stderr) {
//failures also trigger stderr
//FAIL also trigger stderr
if (stdout && stdout.length && !tap.ok) {
const message = tap.message ? tap.message : ''
callbacks.onFail(payload, message)
displayOutput(stdout)
const firstFailMessage = tap.failed[0].message
callbacks.onFail(payload, firstFailMessage)
const output = formatFailOutput(tap)
displayOutput(output)
return
} else {
callbacks.onError(payload)
Expand All@@ -66,7 +68,7 @@ const createTestRunner = (config: TestRunnerConfig, callbacks: Callbacks) => {
}
}

//success!
//PASS
if (tap.ok) {
clearOutput()
callbacks.onSuccess(payload)
Expand Down
13 changes: 1 addition & 12 deletionssrc/services/testRunner/output.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,22 +11,11 @@ const getOutputChannel = (name: string): vscode.OutputChannel => {

constoutputChannelName='CodeRoad Output'

constparseOutput=(text:string):string=>{
letresult=''
for(constlineoftext.split(/\r?\n/)){
if(line.match(/^#/)||line.match(/^notok/)){
result+=line+'\n'
}
}
returnresult
}

exportconstdisplayOutput=(text:string)=>{
constchannel=getOutputChannel(outputChannelName)
channel.clear()
channel.show(true)
constoutput=parseOutput(text)
channel.append(output)
channel.append(text)
}

exportconstclearOutput=()=>{
Expand Down
96 changes: 85 additions & 11 deletionssrc/services/testRunner/parser.test.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
importparserfrom'./parser'

describe('parser',()=>{
test('shoulddetect success',()=>{
test('shouldpass single success',()=>{
constexample=`
1..2
1..1
ok 1 - Should pass
ok 2 - Should also pass
`
expect(parser(example)).toEqual({ok:true})
expect(parser(example)).toEqual({ok:true,passed:[{message:'Should pass'}],failed:[]})
})
test('should detectfailure',()=>{
test('should detectmultiple successes',()=>{
constexample=`
1..3
1..2
ok 1 - Should pass
not ok 2 - This one fails
ok 3 - Also passes
ok 2 - Should also pass
`
expect(parser(example).ok).toBe(false)
constresult=parser(example)
expect(result).toEqual({
ok:true,
passed:[{message:'Should pass'},{message:'Should also pass'}],
failed:[],
})
})
test('should detect failure if no tests passed',()=>{
constexample=`
Expand All@@ -26,6 +29,15 @@ ok 3 - Also passes
# FAIL __tests__/sum.test.js
not ok 1 ● sum › should add two numbers together
`
expect(parser(example).ok).toBe(false)
})
test('should detect single failure among successes',()=>{
constexample=`
1..3
ok 1 - Should pass
not ok 2 - This one fails
ok 3 - Also passes
`
expect(parser(example).ok).toBe(false)
})
Expand All@@ -37,7 +49,7 @@ not ok 2 - First to fail
ok 3 - Also passes
not ok 4 - Second to fail
`
expect(parser(example).message).toBe('First to fail')
expect(parser(example).failed).toEqual([{message:'First to fail'},{message:'Second to fail'}])
})

test('should parse mocha tap example',()=>{
Expand DownExpand Up@@ -65,6 +77,68 @@ ok 3 sumItems should total numbers accurately
# fail 1
# skip 0
`
expect(parser(example).message).toBe("sumItems shouldn't return NaN")
expect(parser(example).failed).toEqual([{message:"sumItems shouldn't return NaN"}])
})
test('should capture single error details',()=>{
constexample=`
not ok 1 package.json should have a valid "author" key
# AssertionError [ERR_ASSERTION]: no "author" key provided
# at Context.<anonymous> (test/packagejson.test.js:11:12)
# at processImmediate (internal/timers.js:439:21)
# tests 1
# pass 0
# fail 1
# skip 0
`
constresult=parser(example)
expect(result.failed[0].message).toBe('package.json should have a valid "author" key')
expect(result.failed[0].details).toBe(`AssertionError [ERR_ASSERTION]: no "author" key provided
at Context.<anonymous> (test/packagejson.test.js:11:12)
at processImmediate (internal/timers.js:439:21)`)
})
test('should capture multiple error details',()=>{
constexample=`
not ok 1 package.json should have a valid "author" key
# AssertionError [ERR_ASSERTION]: no "author" key provided
# at Context.<anonymous> (test/packagejson.test.js:11:12)
# at processImmediate (internal/timers.js:439:21)
not ok 2 package.json should have a valid "description" key
# AssertionError [ERR_ASSERTION]: no "description" key provided
# tests 1
# pass 0
# fail 1
# skip 0
`
constresult=parser(example)
expect(result.failed[0].message).toBe('package.json should have a valid "author" key')
expect(result.failed[0].details).toBe(`AssertionError [ERR_ASSERTION]: no "author" key provided
at Context.<anonymous> (test/packagejson.test.js:11:12)
at processImmediate (internal/timers.js:439:21)`)
expect(result.failed[1].message).toBe('package.json should have a valid "description" key')
expect(result.failed[1].details).toBe(`AssertionError [ERR_ASSERTION]: no "description" key provided`)
})
test('should capture multiple error details between successes',()=>{
constexample=`
ok 1 first passing test
not ok 2 package.json should have a valid "author" key
# AssertionError [ERR_ASSERTION]: no "author" key provided
# at Context.<anonymous> (test/packagejson.test.js:11:12)
# at processImmediate (internal/timers.js:439:21)
ok 3 some passing test
not ok 4 package.json should have a valid "description" key
# AssertionError [ERR_ASSERTION]: no "description" key provided
ok 5 some passing test
# tests 1
# pass 0
# fail 1
# skip 0
`
constresult=parser(example)
expect(result.failed[0].message).toBe('package.json should have a valid "author" key')
expect(result.failed[0].details).toBe(`AssertionError [ERR_ASSERTION]: no "author" key provided
at Context.<anonymous> (test/packagejson.test.js:11:12)
at processImmediate (internal/timers.js:439:21)`)
expect(result.failed[1].message).toBe('package.json should have a valid "description" key')
expect(result.failed[1].details).toBe(`AssertionError [ERR_ASSERTION]: no "description" key provided`)
})
})
75 changes: 59 additions & 16 deletionssrc/services/testRunner/parser.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,72 @@
interface ParserOutput {
exportinterface ParserOutput {
ok: boolean
message?: string
passed: Array<{ message: string }>
failed: Array<{ message: string; details?: string }>
}

const fail = /^not ok \d+\s(\-\s)?(.+)+$/
const ok = /^ok/
const r = {
fail: /^not ok \d+\s(\-\s)?(.+)+$/,
pass: /^ok \d+\s(\-\s)?(.+)+$/,
details: /^#\s{2}(.+)$/,
}

const detect = (type: 'fail' | 'pass' | 'details', text: string) => r[type].exec(text)

const parser = (text: string): ParserOutput => {
const lines = text.split('\n')
let hasPass = false

const result: ParserOutput = {
ok: true,
passed: [],
failed: [],
}

// temporary holder of error detail strings
let currentDetails: string | null = null

const addCurrentDetails = () => {
const failLength: number = result.failed.length
if (currentDetails && !!failLength) {
result.failed[failLength - 1].details = currentDetails
currentDetails = null
}
}

for (const line of lines) {
if (line.length) {
// parse failed test
const failRegex = fail.exec(line)
if (!!failRegex) {
return { ok: false, message: failRegex[2] }
}
if (!hasPass) {
if (!!ok.exec(line)) {
hasPass = true
}
if (!line.length) {
continue
}
// be optimistic! check for success
const isPass = detect('pass', line)
if (!!isPass) {
result.passed.push({ message: isPass[2].trim() })
addCurrentDetails()
continue
}

// check for failure
const isFail = detect('fail', line)
if (!!isFail) {
result.ok = false
addCurrentDetails()
result.failed.push({ message: isFail[2].trim() })
continue
}

// check for error details
const isDetails = detect('details', line)
if (!!isDetails) {
const lineDetails: string = isDetails[1].trim()
if (!currentDetails) {
currentDetails = lineDetails
} else {
// @ts-ignore ignore as it must be a string
currentDetails += `\n${lineDetails}`
}
}
}
return { ok: hasPass }
addCurrentDetails()
return result
}

export default parser

[8]ページ先頭

©2009-2025 Movatter.jp