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

Commitd2e80e3

Browse files
authored
Merge pull requestcoderoad#340 from coderoad/feature/subtasks
Feature/subtasks
2 parents865070f +fde741b commitd2e80e3

File tree

27 files changed

+432
-229
lines changed

27 files changed

+432
-229
lines changed

‎CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,33 @@ CODEROAD_TUTORIAL_URL='path/to/tutorial_config_file.json' // will load directly
125125
## [0.6.1]
126126

127127
- Replace checkboxes with icons
128+
129+
## [0.7.0]
130+
131+
- Support loading subtasks (#340). Subtasks are a list of tests that need to pass before a task is complete. They can be loaded by:
132+
133+
1. filtering down to a subset of tests by setting the `step.setup.filter` to a regex pattern that matches the tests you're targeting
134+
2. setting the `step.setup.subtasks` variable to true
135+
136+
- Change for the test runner config. Changes are backwards compatible.
137+
138+
1. `testRunner.path`=> `testRunner.directory`
139+
2. `testRunner.actions` => `testRunner.setup`
140+
3. Change command to capture `args` for "TAP" support, and test "filter"ing support. These changes will help lead to specific test suite presets in the future.
141+
142+
```json
143+
{
144+
"testRunner": {
145+
"command":"mocha",
146+
"args": {
147+
"filter":"--grep",
148+
"tap":"--reporter=mocha-tap-reporter"
149+
},
150+
"directory":".coderoad",
151+
"setup": {
152+
"commits": ["410bd4f"],
153+
"commands": ["npm install"]
154+
}
155+
}
156+
}
157+
```

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"@typescript-eslint/parser":"^2.33.0",
4646
"chokidar":"^3.4.0",
4747
"dotenv":"^8.2.0",
48-
"eslint":"^7.0.0",
48+
"eslint":"^6.8.0",
4949
"eslint-config-prettier":"^6.11.0",
5050
"eslint-plugin-prettier":"^3.1.3",
5151
"git-url-parse":"^11.1.2",

‎src/actions/setupActions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import logger from '../services/logger'
1010
interfaceSetupActions{
1111
actions:TT.StepActions
1212
send:(action:T.Action)=>void// send messages to client
13-
path?:string
13+
dir?:string
1414
}
1515

16-
exportconstsetupActions=async({ actions, send,path}:SetupActions):Promise<void>=>{
16+
exportconstsetupActions=async({ actions, send,dir}:SetupActions):Promise<void>=>{
1717
if(!actions){
1818
return
1919
}
@@ -45,7 +45,7 @@ export const setupActions = async ({ actions, send, path }: SetupActions): Promi
4545

4646
// 4. run command
4747
if(!alreadyLoaded){
48-
awaitrunCommands({commands:commands||[], send,path}).catch(onError)
48+
awaitrunCommands({commands:commands||[], send,dir}).catch(onError)
4949
}
5050
}
5151

‎src/actions/tutorialConfig.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import * as git from '../services/git'
66
import{DISABLE_RUN_ON_SAVE}from'../environment'
77

88
interfaceTutorialConfigParams{
9-
config:TT.TutorialConfig
9+
data:TT.Tutorial
1010
alreadyConfigured?:boolean
1111
onComplete?():void
1212
}
1313

14-
consttutorialConfig=async({config, alreadyConfigured}:TutorialConfigParams):Promise<E.ErrorMessage|void>=>{
14+
consttutorialConfig=async({data, alreadyConfigured}:TutorialConfigParams):Promise<E.ErrorMessage|void>=>{
1515
if(!alreadyConfigured){
1616
// setup git, add remote
1717
constinitError:E.ErrorMessage|void=awaitgit.initIfNotExists().catch(
@@ -27,7 +27,7 @@ const tutorialConfig = async ({ config, alreadyConfigured }: TutorialConfigParam
2727
}
2828

2929
// verify that internet is connected, remote exists and branch exists
30-
constremoteConnectError:E.ErrorMessage|void=awaitgit.checkRemoteConnects(config.repo).catch(
30+
constremoteConnectError:E.ErrorMessage|void=awaitgit.checkRemoteConnects(data.config.repo).catch(
3131
(error:Error):E.ErrorMessage=>({
3232
type:'FailedToConnectToGitRepo',
3333
message:error.message,
@@ -40,7 +40,7 @@ const tutorialConfig = async ({ config, alreadyConfigured }: TutorialConfigParam
4040
}
4141

4242
// TODO if remote not already set
43-
constcoderoadRemoteError:E.ErrorMessage|void=awaitgit.setupCodeRoadRemote(config.repo.uri).catch(
43+
constcoderoadRemoteError:E.ErrorMessage|void=awaitgit.setupCodeRoadRemote(data.config.repo.uri).catch(
4444
(error:Error):E.ErrorMessage=>({
4545
type:'GitRemoteAlreadyExists',
4646
message:error.message,
@@ -52,7 +52,7 @@ const tutorialConfig = async ({ config, alreadyConfigured }: TutorialConfigParam
5252
}
5353
}
5454

55-
awaitvscode.commands.executeCommand(COMMANDS.CONFIG_TEST_RUNNER,config.testRunner)
55+
awaitvscode.commands.executeCommand(COMMANDS.CONFIG_TEST_RUNNER,data)
5656

5757
if(!DISABLE_RUN_ON_SAVE){
5858
// verify if file test should run based on document saved

‎src/actions/utils/loadWatchers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ const loadWatchers = (watchers: string[]) => {
3838
constnow=+newDate()
3939
if(!lastFire||lastFire-now>1000){
4040
vscode.commands.executeCommand(COMMANDS.RUN_TEST,{
41-
onSuccess:()=>{
42-
// cleanup watcher on success
43-
disposeWatcher(watcher)
41+
callbacks:{
42+
onSuccess:()=>{
43+
// cleanup watcher on success
44+
disposeWatcher(watcher)
45+
},
4446
},
4547
})
4648
}

‎src/actions/utils/runCommands.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { exec } from '../../services/node'
44
interfaceRunCommands{
55
commands:string[]
66
send:(action:T.Action)=>void
7-
path?:string
7+
dir?:string
88
}
99

10-
construnCommands=async({ commands, send,path}:RunCommands)=>{
10+
construnCommands=async({ commands, send,dir}:RunCommands)=>{
1111
if(!commands.length){
1212
return
1313
}
@@ -19,7 +19,7 @@ const runCommands = async ({ commands, send, path }: RunCommands) => {
1919
send({type:'COMMAND_START',payload:{process:{ ...process,status:'RUNNING'}}})
2020
letresult:{stdout:string;stderr:string}
2121
try{
22-
result=awaitexec({ command,path})
22+
result=awaitexec({ command,dir})
2323
console.log(result)
2424
}catch(error){
2525
console.log(`Test failed:${error.message}`)

‎src/channel/index.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ class Channel implements Channel {
204204
}
205205
}
206206

207-
consterror:E.ErrorMessage|void=awaittutorialConfig({config:data.config}).catch((error:Error)=>({
207+
consterror:E.ErrorMessage|void=awaittutorialConfig({ data}).catch((error:Error)=>({
208208
type:'UnknownError',
209209
message:`Location: tutorial config.\n\n${error.message}`,
210210
}))
@@ -231,9 +231,8 @@ class Channel implements Channel {
231231
if(!tutorialContinue){
232232
thrownewError('Invalid tutorial to continue')
233233
}
234-
constcontinueConfig:TT.TutorialConfig=tutorialContinue.config
235234
awaittutorialConfig({
236-
config:continueConfig,
235+
data:tutorialContinue,
237236
alreadyConfigured:true,
238237
})
239238
// update the current stepId on startup
@@ -307,7 +306,7 @@ class Channel implements Channel {
307306
awaitvscode.commands.executeCommand(COMMANDS.SET_CURRENT_POSITION,action.payload.position)
308307
awaitsolutionActions({actions:action.payload.actions,send:this.send})
309308
// run test following solution to update position
310-
vscode.commands.executeCommand(COMMANDS.RUN_TEST)
309+
vscode.commands.executeCommand(COMMANDS.RUN_TEST,{subtasks:true})
311310
return
312311
case'EDITOR_SYNC_PROGRESS':
313312
// update progress when a level is deemed complete in the client
@@ -318,7 +317,7 @@ class Channel implements Channel {
318317
awaitshowOutput(channel)
319318
return
320319
case'EDITOR_RUN_TEST':
321-
vscode.commands.executeCommand(COMMANDS.RUN_TEST)
320+
vscode.commands.executeCommand(COMMANDS.RUN_TEST,action?.payload)
322321
return
323322
default:
324323
logger(`No match for action type:${actionType}`)

‎src/editor/commands.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,19 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP
5050
// setup 1x1 horizontal layout
5151
webview.createOrShow()
5252
},
53-
[COMMANDS.CONFIG_TEST_RUNNER]:async(config:TT.TutorialTestRunnerConfig)=>{
54-
if(config.actions){
53+
[COMMANDS.CONFIG_TEST_RUNNER]:async(data:TT.Tutorial)=>{
54+
consttestRunnerConfig=data.config.testRunner
55+
constsetup=testRunnerConfig.setup||testRunnerConfig.actions// TODO: deprecate and remove config.actions
56+
if(setup){
5557
// setup tutorial test runner commits
5658
// assumes git already exists
57-
awaitsetupActions({actions:config.actions,send:webview.send,path:config.path})
59+
awaitsetupActions({
60+
actions:setup,
61+
send:webview.send,
62+
dir:testRunnerConfig.directory||testRunnerConfig.path,
63+
})// TODO: deprecate and remove config.path
5864
}
59-
testRunner=createTestRunner(config,{
65+
testRunner=createTestRunner(data,{
6066
onSuccess:(position:T.Position)=>{
6167
logger('test pass position',position)
6268
// send test pass message back to client
@@ -75,20 +81,27 @@ export const createCommands = ({ extensionPath, workspaceState }: CreateCommandP
7581
// send test run message back to client
7682
webview.send({type:'TEST_RUNNING',payload:{ position}})
7783
},
84+
onLoadSubtasks:({ summary})=>{
85+
webview.send({type:'LOAD_TEST_SUBTASKS',payload:{ summary}})
86+
},
7887
})
7988
},
8089
[COMMANDS.SET_CURRENT_POSITION]:(position:T.Position)=>{
8190
// set from last setup stepAction
8291
currentPosition=position
8392
},
84-
[COMMANDS.RUN_TEST]:(callback?:{onSuccess:()=>void})=>{
93+
[COMMANDS.RUN_TEST]:({
94+
subtasks,
95+
callbacks,
96+
}:{subtasks?:boolean;callbacks?:{onSuccess:()=>void}}={})=>{
8597
logger('run test current',currentPosition)
8698
// use stepId from client, or last set stepId
8799
// const position: T.Position = {
88100
// ...current,
89101
// stepId: current && current.position.stepId?.length ? current.position.stepId : currentPosition.stepId,
90102
// }
91-
testRunner(currentPosition,callback?.onSuccess)
103+
logger('currentPosition',currentPosition)
104+
testRunner({position:currentPosition,onSuccess:callbacks?.onSuccess, subtasks})
92105
},
93106
}
94107
}

‎src/services/node/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ const asyncExec = promisify(cpExec)
88

99
interfaceExecParams{
1010
command:string
11-
path?:string
11+
dir?:string
1212
}
1313

1414
exportconstexec=(params:ExecParams):Promise<{stdout:string;stderr:string}>|never=>{
15-
constcwd=join(WORKSPACE_ROOT,params.path||'')
15+
constcwd=join(WORKSPACE_ROOT,params.dir||'')
1616
returnasyncExec(params.command,{ cwd})
1717
}
1818

‎src/services/testRunner/index.ts

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as T from 'typings'
22
import*asTTfrom'typings/tutorial'
33
import{exec}from'../node'
44
importloggerfrom'../logger'
5-
importparserfrom'./parser'
5+
importparser,{ParserOutput}from'./parser'
66
import{debounce,throttle}from'./throttle'
77
importonErrorfrom'../sentry/onError'
88
import{clearOutput,addOutput}from'./output'
@@ -13,14 +13,22 @@ interface Callbacks {
1313
onFail(position:T.Position,failSummary:T.TestFail):void
1414
onRun(position:T.Position):void
1515
onError(position:T.Position):void
16+
onLoadSubtasks({ summary}:{summary:{[testName:string]:boolean}}):void
1617
}
1718

1819
constfailChannelName='CodeRoad (Tests)'
1920
constlogChannelName='CodeRoad (Logs)'
2021

21-
constcreateTestRunner=(config:TT.TutorialTestRunnerConfig,callbacks:Callbacks)=>{
22-
returnasync(position:T.Position,onSuccess?:()=>void):Promise<void>=>{
23-
logger('createTestRunner',position)
22+
interfaceTestRunnerParams{
23+
position:T.Position
24+
subtasks?:boolean
25+
onSuccess?:()=>void
26+
}
27+
28+
constcreateTestRunner=(data:TT.Tutorial,callbacks:Callbacks)=>{
29+
consttestRunnerConfig=data.config.testRunner
30+
consttestRunnerFilterArg=testRunnerConfig.args?.filter
31+
returnasync({ position, onSuccess, subtasks}:TestRunnerParams):Promise<void>=>{
2432
conststartTime=throttle()
2533
// throttle time early
2634
if(!startTime){
@@ -30,11 +38,35 @@ const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callba
3038
logger('------------------- RUN TEST -------------------')
3139

3240
// flag as running
33-
callbacks.onRun(position)
41+
if(!subtasks){
42+
callbacks.onRun(position)
43+
}
3444

3545
letresult:{stdout:string|undefined;stderr:string|undefined}
3646
try{
37-
result=awaitexec({command:config.command,path:config.path})
47+
letcommand=testRunnerConfig.args
48+
?`${testRunnerConfig.command}${testRunnerConfig?.args.tap}`
49+
:testRunnerConfig.command// TODO: enforce TAP
50+
51+
// filter tests if requested
52+
if(testRunnerFilterArg){
53+
// get tutorial step from position
54+
// check the step actions for specific command
55+
// NOTE: cannot just pass in step actions as the test can be called by:
56+
// - onEditorSave, onWatcher, onSolution, onRunTest, onSubTask
57+
constlevels=data.levels
58+
constlevel=levels.find((l)=>l.id===position.levelId)
59+
conststep=level?.steps.find((s)=>s.id===position.stepId)
60+
consttestFilter=step?.setup?.filter
61+
if(testFilter){
62+
// append filter commands
63+
command=[command,testRunnerFilterArg,testFilter].join(' ')
64+
}else{
65+
thrownewError('Test Runner filter not configured')
66+
}
67+
}
68+
logger('COMMAND',command)
69+
result=awaitexec({ command,dir:testRunnerConfig.directory||testRunnerConfig.path})// TODO: remove config.path later
3870
}catch(err){
3971
result={stdout:err.stdout,stderr:err.stack}
4072
}
@@ -49,7 +81,13 @@ const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callba
4981

5082
const{ stdout, stderr}=result
5183

52-
consttap=parser(stdout||'')
84+
consttap:ParserOutput=parser(stdout||'')
85+
86+
if(subtasks){
87+
callbacks.onLoadSubtasks({summary:tap.summary})
88+
// exit early
89+
return
90+
}
5391

5492
addOutput({channel:logChannelName,text:tap.logs.join('\n'),show:false})
5593

@@ -60,6 +98,7 @@ const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callba
6098
constfailSummary={
6199
title:firstFail.message||'Test Failed',
62100
description:firstFail.details||'Unknown error',
101+
summary:tap.summary,
63102
}
64103
callbacks.onFail(position,failSummary)
65104
constoutput=formatFailOutput(tap)
@@ -76,7 +115,9 @@ const createTestRunner = (config: TT.TutorialTestRunnerConfig, callbacks: Callba
76115
// PASS
77116
if(tap.ok){
78117
clearOutput(failChannelName)
118+
79119
callbacks.onSuccess(position)
120+
80121
if(onSuccess){
81122
onSuccess()
82123
}

‎src/services/testRunner/parser.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ describe('parser', () => {
66
1..1
77
ok 1 - Should pass
88
`
9-
expect(parser(example)).toEqual({ok:true,passed:[{message:'Should pass'}],failed:[],logs:[]})
9+
expect(parser(example)).toEqual({
10+
ok:true,
11+
passed:[{message:'Should pass'}],
12+
failed:[],
13+
logs:[],
14+
summary:{'Should pass':true},
15+
})
1016
})
1117
test('should detect multiple successes',()=>{
1218
constexample=`
@@ -20,6 +26,10 @@ ok 2 - Should also pass
2026
passed:[{message:'Should pass'},{message:'Should also pass'}],
2127
failed:[],
2228
logs:[],
29+
summary:{
30+
'Should pass':true,
31+
'Should also pass':true,
32+
},
2333
})
2434
})
2535
test('should detect failure if no tests passed',()=>{
@@ -170,6 +180,10 @@ at processImmediate (internal/timers.js:439:21)`,
170180
},
171181
],
172182
logs:['log 1','log 2'],
183+
summary:{
184+
'package.json should have "express" installed':true,
185+
'server should log "Hello World"':false,
186+
},
173187
})
174188
})
175189
})

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp