11import log from '../log' ;
2+ import request from 'request' ;
23import Archiver from '../utils/archiver' ;
34import Uploader from '../utils/uploader' ;
45import Poller , { IRun , ITest } from '../utils/poller' ;
@@ -7,20 +8,25 @@ import Tunnel from '../utils/tunnel';
78import ora from 'ora' ;
89import chalk from 'chalk' ;
910import io from 'socket.io-client' ;
10- import { runInThisContext } from 'vm' ;
1111
1212interface Arguments {
1313 [ x : string ] : unknown ;
1414 cf : string | boolean ;
1515}
1616
17+ interface ISocketData {
18+ id : number
19+ payload : string
20+ }
21+
1722export default class RunProject {
1823 private archiver : Archiver | undefined = undefined ;
1924 private uploader : Uploader | undefined = undefined ;
2025 private poller : Poller | undefined = undefined ;
2126 private tunnel : Tunnel | undefined = undefined ;
2227 private configFilePath : string | undefined = undefined ;
2328 private config : IConfig | undefined = undefined ;
29+ private projectId : number | undefined = undefined ;
2430
2531 constructor ( argv : Arguments ) {
2632 if ( typeof ( argv . cf ) === 'string' ) {
@@ -29,20 +35,52 @@ export default class RunProject {
2935 }
3036
3137 public exitHandler ( ) : void {
38+ this . stopJob ( ) ;
3239 if ( this . config && this . config . run_settings . start_tunnel ) {
3340 if ( this . tunnel ) {
3441 this . tunnel . stop ( ) . then ( ( ) => {
3542 process . exit ( ) ;
36- } ) . catch ( console . error ) ;
43+ } ) . catch ( log . error ) ;
3744 this . tunnel = undefined ;
3845 }
3946 } else {
4047 process . exit ( )
4148 }
4249 }
4350
44- public errorHandler ( ) : void {
45- console . error ( chalk . white . bgRed . bold ( `A fatal error occurred, please report this to testingbot.com` ) ) ;
51+ private async stopJob ( ) : Promise < boolean > {
52+ if ( ! this . config ) {
53+ return false ;
54+ }
55+
56+ if ( ! this . projectId ) {
57+ return false ;
58+ }
59+
60+ return new Promise ( ( resolve , reject ) => {
61+ const requestOptions = {
62+ method : 'POST' ,
63+ uri : `https://api.testingbot.com/v1/cypress/${ this . projectId } /stop_project` ,
64+ auth : {
65+ user : this . config ? this . config . auth . key : '' ,
66+ pass : this . config ? this . config . auth . secret : '' ,
67+ sendImmediately : true ,
68+ }
69+ } ;
70+
71+ request ( requestOptions , ( error ) => {
72+ if ( error ) {
73+ return reject ( error ) ;
74+ }
75+
76+ resolve ( true ) ;
77+ } ) ;
78+ } ) ;
79+ }
80+
81+ public errorHandler ( err : Error ) : void {
82+ log . error ( chalk . white . bgRed . bold ( `A fatal error occurred, please report this to testingbot.com` ) ) ;
83+ log . error ( err ) ;
4684 this . exitHandler ( ) ;
4785 }
4886
@@ -52,30 +90,30 @@ export default class RunProject {
5290 process . on ( 'SIGINT' , this . exitHandler . bind ( this , { exit :true } ) ) ;
5391 process . on ( 'SIGUSR1' , this . exitHandler . bind ( this , { exit :true } ) ) ;
5492 process . on ( 'SIGUSR2' , this . exitHandler . bind ( this , { exit :true } ) ) ;
55- process . on ( 'uncaughtException' , this . errorHandler . bind ( this , { exit : true } ) ) ;
93+ process . on ( 'uncaughtException' , this . errorHandler . bind ( this ) ) ;
5694 }
5795
5896 private realTimeMessage ( message : string ) : void {
59- console . log ( message ) ;
97+ const data : ISocketData = JSON . parse ( message ) ;
98+ log . info ( data . payload ) ;
6099 }
61100
62101 private realTimeError ( message : string ) : void {
63- console . error ( message ) ;
102+ const data : ISocketData = JSON . parse ( message ) ;
103+ log . error ( data . payload ) ;
64104 }
65105
66- private parseErrors ( runs : IRun [ ] ) : string [ ] {
67- let errors : string [ ] = [ ]
106+ private parseSuccess ( runs : IRun [ ] ) : boolean {
107+ let success = true ;
68108 for ( let i = 0 ; i < runs . length ; i ++ ) {
69- if ( runs [ i ] . errors . length > 0 ) {
70- errors = errors . concat ( runs [ i ] . errors ) ;
71- }
109+ success = success && runs [ i ] . success ;
72110 }
73111
74- return errors ;
112+ return success ;
75113 }
76114
77115 private parseTestCases ( runs : IRun [ ] ) : ITest [ ] {
78- let testCases : ITest [ ] = [ ]
116+ const testCases : ITest [ ] = [ ]
79117 for ( let i = 0 ; i < runs . length ; i ++ ) {
80118 const testCase = runs [ i ] . test ;
81119 if ( testCase ) {
@@ -91,14 +129,14 @@ export default class RunProject {
91129 try {
92130 config = await Config . getConfig ( this . configFilePath || `testingbot.json` ) ;
93131 } catch ( e ) {
94- console . error ( chalk . white . bgRed . bold ( `Configuration file problem: ${ e . message } for Config File: ${ this . configFilePath || `testingbot.json` } ` ) ) ;
132+ log . error ( chalk . white . bgRed . bold ( `Configuration file problem: ${ e . message } for Config File: ${ this . configFilePath || `testingbot.json` } ` ) ) ;
95133 return ;
96134 }
97135
98136 const configValidationErrors = Config . validate ( config ) ;
99137
100138 if ( configValidationErrors . length > 0 ) {
101- console . error ( chalk . white . bgRed . bold ( `Configuration errors: ${ configValidationErrors . join ( '\n' ) } ` ) ) ;
139+ log . error ( chalk . white . bgRed . bold ( `Configuration errors: ${ configValidationErrors . join ( '\n' ) } ` ) ) ;
102140 return ;
103141 }
104142
@@ -112,7 +150,7 @@ export default class RunProject {
112150 let zipFile : string ;
113151
114152 if ( ! this . archiver || ! this . uploader ) {
115- console . error ( chalk . white . bgRed . bold ( `Invalid state, please try again` ) ) ;
153+ log . error ( chalk . white . bgRed . bold ( `Invalid state, please try again` ) ) ;
116154 return ;
117155 }
118156
@@ -122,31 +160,31 @@ export default class RunProject {
122160 tunnelSpinner . succeed ( 'TestingBot Tunnel Ready' ) ;
123161 }
124162
125- const uploadSpinner = ora ( 'Starting Project on TestingBot' ) . start ( ) ;
163+ const uploadSpinner = ora ( 'Starting Cypress Project on TestingBot' ) . start ( ) ;
126164 try {
127165 zipFile = await this . archiver . start ( ) ;
128166 } catch ( err ) {
129- console . error ( err ) ;
167+ log . error ( err ) ;
130168 return ;
131169 }
132170
133171 this . registerCloseHandlers ( ) ;
134172
135173 try {
136174 const response = await this . uploader . start ( zipFile ) ;
137- uploadSpinner . succeed ( 'Cypress is now running on TestingBot' )
138- const realTime = io . connect ( 'https://hub.testingbot.com:3031' ) ;
139- realTime . emit ( 'join' , `cypress_${ response . id } ` )
140- realTime . on ( 'cypress_data' , ( msg : string ) => this . realTimeMessage . bind ( this , msg ) ) ;
141- realTime . on ( 'cypress_error' , ( msg : string ) => this . realTimeError . bind ( this , msg ) ) ;
175+ this . projectId = response . id ;
176+ uploadSpinner . succeed ( 'Cypress Project is now running on TestingBot' ) ;
177+
178+ if ( config . run_settings . realTimeLogs ) {
179+ const realTime = io . connect ( 'https://hub.testingbot.com:3031' ) ;
180+ realTime . emit ( 'join' , `cypress_${ response . id } ` )
181+ realTime . on ( 'cypress_data' , this . realTimeMessage . bind ( this ) ) ;
182+ realTime . on ( 'cypress_error' , this . realTimeError . bind ( this ) ) ;
183+ }
142184
143185 const poller = await this . poller . check ( response . id , uploadSpinner ) ;
144186 const testCases = this . parseTestCases ( poller . runs ) ;
145- const errors = this . parseErrors ( poller . runs ) ;
146-
147- if ( errors . length > 0 ) {
148- console . error ( chalk . white . bgRed . bold ( `Errors occurred:` + errors . join ( `\n` ) ) ) ;
149- }
187+ const success = this . parseSuccess ( poller . runs ) ;
150188
151189 if ( process . env . TESTINGBOT_CI && testCases . length > 0 ) {
152190 for ( let i = 0 ; i < testCases . length ; i ++ ) {
@@ -155,10 +193,10 @@ export default class RunProject {
155193 }
156194 }
157195
158- process . exit ( errors . length === 0 ? 0 : 1 ) ;
196+ process . exit ( success === true ? 0 : 1 ) ;
159197
160198 } catch ( err ) {
161- console . error ( chalk . white . bgRed . bold ( err ) ) ;
199+ log . error ( chalk . white . bgRed . bold ( err ) ) ;
162200 if ( config . run_settings . start_tunnel ) {
163201 await this . tunnel . stop ( ) ;
164202 }
0 commit comments