@@ -227,6 +227,7 @@ async function readPwtConfig(opts: ToolAdapterOptionsFromCli): Promise<{configPa
227227 const configPaths = opts . configPath ? [ opts . configPath ] : DEFAULT_CONFIG_PATHS ;
228228 let originalConfig ! : FullConfig ;
229229 let resolvedConfigPath ! : string ;
230+ const errors : Array < { path : string , error : Error } > = [ ] ;
230231
231232 const revertTransformHook = setupTransformHook ( ) ;
232233
@@ -239,7 +240,11 @@ async function readPwtConfig(opts: ToolAdapterOptionsFromCli): Promise<{configPa
239240
240241 break ;
241242 } catch ( err ) {
243+ const error = err as Error ;
244+ errors . push ( { path : resolvedConfigPath , error} ) ;
245+
242246 if ( ( err as NodeJS . ErrnoException ) . code !== 'MODULE_NOT_FOUND' ) {
247+ revertTransformHook ( ) ;
243248 throw err ;
244249 }
245250 }
@@ -248,12 +253,43 @@ async function readPwtConfig(opts: ToolAdapterOptionsFromCli): Promise<{configPa
248253 revertTransformHook ( ) ;
249254
250255 if ( ! originalConfig ) {
251- throw new Error ( `Unable to read config from paths: ${ configPaths . join ( ', ' ) } ` ) ;
256+ const errorMessage = createConfigReadErrorMessage ( configPaths , errors ) ;
257+ const error = new Error ( '' ) ;
258+ error . stack = errorMessage ;
259+ throw error ;
252260 }
253261
254262 return { config : originalConfig , configPath : resolvedConfigPath } ;
255263}
256264
265+ function createConfigReadErrorMessage ( searchedPaths : string [ ] , errors : Array < { path : string , error : Error } > ) : string {
266+ const lines : string [ ] = [ ] ;
267+
268+ lines . push ( 'HTML Reporter failed to read Playwright configuration file.\n' ) ;
269+ lines . push ( 'What happened:' ) ;
270+
271+ if ( searchedPaths . length === 0 ) {
272+ lines . push ( ` • No config paths were supplied` ) ;
273+ }
274+
275+ errors . forEach ( ( { path, error} ) => {
276+ if ( new RegExp ( '^Cannot find module[ \'"]*' + path ) . test ( error . message ) ) {
277+ lines . push ( ` • Tried to read ${ path } , but got an error: file does not exist` ) ;
278+ } else {
279+ lines . push ( ` • Tried to read ${ path } , but got an error: ${ error . message . replaceAll ( '\n' , '\n ' ) } ` ) ;
280+ }
281+ } ) ;
282+
283+ lines . push ( '\nWhat you can do:' ) ;
284+ lines . push ( ' • Ensure playwright config file exists in one of those locations' ) ;
285+ lines . push ( ' • Specify correct path using --config option' ) ;
286+ lines . push ( ' • Ensure playwright config file is valid' ) ;
287+ lines . push ( ' • If you are using path alises like "@/tests" or "~/tests", ensure they can be resolved at runtime.' ) ;
288+ lines . push ( ' You may need to install tsconfig-paths package. Read more: https://npm.im/tsconfig-paths' ) ;
289+
290+ return lines . join ( '\n' ) ;
291+ }
292+
257293async function registerTestResult ( eventMsg : PwtEventMessage , reportBuilder : GuiReportBuilder ) : Promise < TestBranch > {
258294 const { test, result, browserName, titlePath} = eventMsg ;
259295
0 commit comments