11/// <reference types="node" />
22// tslint:disable:no-null-keyword
33
4+ import minimist = require( "minimist" ) ;
45import http = require( "http" ) ;
56import fs = require( "fs" ) ;
67import path = require( "path" ) ;
@@ -20,7 +21,8 @@ const baseUrl = new URL(`http://localhost:${port}/`);
2021const rootDir = path . dirname ( __dirname ) ;
2122const useCaseSensitiveFileNames = isFileSystemCaseSensitive ( ) ;
2223
23- let browser = "IE" ;
24+ const defaultBrowser = os . platform ( ) === "win32" ? "edge" : "chrome" ;
25+ let browser : "edge" | "chrome" | "none" = defaultBrowser ;
2426let grep : string | undefined ;
2527let verbose = false ;
2628
@@ -862,93 +864,137 @@ function startServer() {
862864 return http . createServer ( handleRequest ) . listen ( port ) ;
863865}
864866
867+ const REG_COLUMN_PADDING = 4 ;
868+
869+ function queryRegistryValue ( keyPath : string , callback : ( error : Error | null , value : string ) => void ) {
870+ const args = [ "query" , keyPath ] ;
871+ child_process . execFile ( "reg" , [ "query" , keyPath , "/ve" ] , { encoding : "utf8" } , ( error , stdout ) => {
872+ if ( error ) return callback ( error , null ) ;
873+
874+ const valueLine = stdout . replace ( / ^ \r \n .+ ?\r \n | \r \n \r \n $ / g, "" ) ;
875+ if ( ! valueLine ) {
876+ return callback ( new Error ( "Unable to retrieve value." ) , null ) ;
877+ }
878+
879+ const valueNameColumnOffset = REG_COLUMN_PADDING ;
880+ if ( valueLine . lastIndexOf ( "(Default)" , valueNameColumnOffset ) !== valueNameColumnOffset ) {
881+ return callback ( new Error ( "Unable to retrieve value." ) , null ) ;
882+ }
883+
884+ const dataTypeColumnOffset = valueNameColumnOffset + "(Default)" . length + REG_COLUMN_PADDING ;
885+ if ( valueLine . lastIndexOf ( "REG_SZ" , dataTypeColumnOffset ) !== dataTypeColumnOffset ) {
886+ return callback ( new Error ( "Unable to retrieve value." ) , null ) ;
887+ }
888+
889+ const valueColumnOffset = dataTypeColumnOffset + "REG_SZ" . length + REG_COLUMN_PADDING ;
890+ const value = valueLine . slice ( valueColumnOffset ) ;
891+ return callback ( null , value ) ;
892+ } ) ;
893+ }
894+
895+ interface Browser {
896+ description : string ;
897+ command : string ;
898+ }
899+
900+ function createBrowserFromPath ( path : string ) : Browser {
901+ return { description : path , command : path } ;
902+ }
903+
904+ function getChromePath ( callback : ( error : Error | null , browser : Browser | string | null ) => void ) {
905+ switch ( os . platform ( ) ) {
906+ case "win32" :
907+ return queryRegistryValue ( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe" , ( error , value ) => {
908+ if ( error ) return callback ( null , "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" ) ;
909+ return callback ( null , createBrowserFromPath ( value ) ) ;
910+ } ) ;
911+ case "darwin" : return callback ( null , "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ) ;
912+ case "linux" : return callback ( null , "/opt/google/chrome/chrome" ) ;
913+ default : return callback ( new Error ( `Chrome location is unknown for platform '${ os . platform ( ) } '` ) , null ) ;
914+ }
915+ }
916+
917+ function getEdgePath ( callback : ( error : Error | null , browser : Browser | null ) => void ) {
918+ switch ( os . platform ( ) ) {
919+ case "win32" : return callback ( null , { description : "Microsoft Edge" , command : "cmd /c start microsoft-edge:%1" } ) ;
920+ default : return callback ( new Error ( `Edge location is unknown for platform '${ os . platform ( ) } '` ) , null ) ;
921+ }
922+ }
923+
924+ function getBrowserPath ( callback : ( error : Error | null , browser : Browser | null ) => void ) {
925+ switch ( browser ) {
926+ case "chrome" : return getChromePath ( afterGetBrowserPath ) ;
927+ case "edge" : return getEdgePath ( afterGetBrowserPath ) ;
928+ default : return callback ( new Error ( `Browser location is unknown for '${ browser } '` ) , null ) ;
929+ }
930+
931+ function afterGetBrowserPath ( error : Error | null , browser : Browser | string | null ) {
932+ if ( error ) return callback ( error , null ) ;
933+ if ( typeof browser === "object" ) return callback ( null , browser ) ;
934+ return fs . stat ( browser , ( error , stats ) => {
935+ if ( ! error && stats . isFile ( ) ) {
936+ return callback ( null , createBrowserFromPath ( browser ) ) ;
937+ }
938+ if ( browser === "chrome" ) return callback ( null , createBrowserFromPath ( "chrome" ) ) ;
939+ return callback ( new Error ( `Browser location is unknown for '${ browser } '` ) , null ) ;
940+ } ) ;
941+ }
942+ }
943+
865944function startClient ( server : http . Server ) {
866945 let browserPath : string ;
867946 if ( browser === "none" ) {
868947 return ;
869948 }
870949
871- if ( browser === "chrome" ) {
872- let defaultChromePath = "" ;
873- switch ( os . platform ( ) ) {
874- case "win32" :
875- defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" ;
876- break ;
877- case "darwin" :
878- defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ;
879- break ;
880- case "linux" :
881- defaultChromePath = "/opt/google/chrome/chrome" ;
882- break ;
883- default :
884- console . log ( `default Chrome location is unknown for platform '${ os . platform ( ) } '` ) ;
885- break ;
886- }
887- if ( fs . existsSync ( defaultChromePath ) ) {
888- browserPath = defaultChromePath ;
889- }
890- else {
891- browserPath = browser ;
892- }
893- }
894- else {
895- const defaultIEPath = "C:/Program Files/Internet Explorer/iexplore.exe" ;
896- if ( fs . existsSync ( defaultIEPath ) ) {
897- browserPath = defaultIEPath ;
950+ getBrowserPath ( ( error , browser ) => {
951+ if ( error ) return console . error ( error ) ;
952+ console . log ( `Using browser: ${ browser . description } ` ) ;
953+ const queryString = grep ? `?grep=${ grep } ` : "" ;
954+ const args = [ `http://localhost:${ port } /tests/webTestResults.html${ queryString } ` ] ;
955+ if ( browser . command . indexOf ( "%" ) === - 1 ) {
956+ child_process . spawn ( browser . command , args ) ;
898957 }
899958 else {
900- browserPath = browser ;
959+ const command = browser . command . replace ( / % ( \d + ) / g, ( _ , offset ) => args [ + offset - 1 ] ) ;
960+ child_process . exec ( command ) ;
901961 }
902- }
903-
904- console . log ( `Using browser: ${ browserPath } ` ) ;
905-
906- const queryString = grep ? `?grep=${ grep } ` : "" ;
907- const child = child_process . spawn ( browserPath , [ `http://localhost:${ port } /tests/webTestResults.html${ queryString } ` ] , {
908- stdio : "inherit"
909962 } ) ;
910963}
911964
912965function printHelp ( ) {
913966 console . log ( "Runs an http server on port 8888, looking for tests folder in the current directory\n" ) ;
914967 console . log ( "Syntax: node webTestServer.js [browser] [tests] [--verbose]\n" ) ;
915968 console . log ( "Options:" ) ;
916- console . log ( " <browser> The browser to launch. One of 'IE ', 'chrome', or 'none' (default 'IE' )." ) ;
969+ console . log ( " <browser> The browser to launch. One of 'edge ', 'chrome', or 'none' (default 'edge' on Windows, otherwise `chrome` )." ) ;
917970 console . log ( " <tests> A regular expression to pass to Mocha." ) ;
918971 console . log ( " --verbose Enables verbose logging." ) ;
919972}
920973
921974function parseCommandLine ( args : string [ ] ) {
922- let offset = 0 ;
923- for ( const arg of args ) {
924- const argLower = arg . toLowerCase ( ) ;
925- if ( argLower === "--help" ) {
926- printHelp ( ) ;
927- return false ;
928- }
929- else if ( argLower === "--verbose" ) {
930- verbose = true ;
931- }
932- else {
933- if ( offset === 0 ) {
934- browser = arg ;
935- }
936- else if ( offset === 1 ) {
937- grep = arg ;
938- }
939- else {
940- console . log ( `Unrecognized argument: ${ arg } \n` ) ;
941- return false ;
942- }
943- offset ++ ;
944- }
975+ const parsed = minimist ( args , { boolean : [ "help" , "verbose" ] } ) ;
976+ if ( parsed . help ) {
977+ printHelp ( ) ;
978+ return false ;
979+ }
980+
981+ if ( parsed . verbose ) {
982+ verbose = true ;
983+ }
984+
985+ const [ parsedBrowser = defaultBrowser , parsedGrep , ...unrecognized ] = parsed . _ ;
986+ if ( parsedBrowser !== "edge" && parsedBrowser !== "chrome" && parsedBrowser !== "none" ) {
987+ console . log ( `Unrecognized browser '${ parsedBrowser } ', expected 'edge', 'chrome', or 'none'.` ) ;
988+ return false ;
945989 }
946990
947- if ( browser !== "IE" && browser !== "chrome" && browser !== "none" ) {
948- console . log ( `Unrecognized browser ' ${ browser } ', expected 'IE' or 'chrome'. ` ) ;
991+ if ( unrecognized . length > 0 ) {
992+ console . log ( `Unrecognized argument: ${ unrecognized [ 0 ] } ` ) ;
949993 return false ;
950994 }
951995
996+ browser = parsedBrowser ;
997+ grep = parsedGrep ;
952998 return true ;
953999}
9541000
0 commit comments