or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddom-apis.mdindex.mdjsdom-class.mdresources.mdtroubleshooting.mdvirtual-console.md
tile.json

virtual-console.mddocs/

0

# Virtual Console

1

2

The VirtualConsole class extends Node.js EventEmitter to capture console output from within jsdom. It captures both direct page output via `window.console` and jsdom implementation errors. This allows external code to monitor, log, or handle output generated inside the jsdom environment.

3

4

## Capabilities

5

6

### Constructor

7

8

Creates a new virtual console with no default behavior.

9

10

```javascript { .api }

11

/**

12

* Create a virtual console for capturing output

13

* Extends EventEmitter

14

*/

15

class VirtualConsole extends EventEmitter {

16

constructor();

17

}

18

```

19

20

**Usage Examples:**

21

22

```javascript

23

const { JSDOM, VirtualConsole } = require("jsdom");

24

25

// Create virtual console

26

const virtualConsole = new VirtualConsole();

27

28

// Add listeners before creating jsdom

29

virtualConsole.on("log", (message) => {

30

console.log("Page logged:", message);

31

});

32

33

const dom = new JSDOM(`

34

<script>console.log("Hello");</script>

35

`, {

36

runScripts: "dangerously",

37

virtualConsole: virtualConsole

38

});

39

// Logs: "Page logged: Hello"

40

```

41

42

### Methods

43

44

#### forwardTo()

45

46

```javascript { .api }

47

/**

48

* Forward console output to another console object

49

* @param anyConsole - Console object to forward to (e.g., Node.js console)

50

* @param options - Control jsdom error forwarding

51

* @param options.jsdomErrors - undefined (forward all), "none" (forward none), or array of error types to forward

52

* @returns This VirtualConsole instance for chaining

53

*/

54

forwardTo(

55

anyConsole: Console,

56

options?: { jsdomErrors?: undefined | "none" | string[] }

57

): VirtualConsole

58

```

59

60

Forwards all virtual console events to another console object. Iterates through the target console's methods and forwards matching events.

61

62

**Parameters:**

63

64

- **`anyConsole`**: Console object (typically Node.js `console`)

65

- **`options.jsdomErrors`** (optional):

66

- `undefined` (default): Forward all jsdom errors

67

- `"none"`: Don't forward any jsdom errors

68

- `string[]`: Array of error types to forward (e.g., `["unhandled-exception", "not-implemented"]`)

69

70

**Returns:** The VirtualConsole instance for chaining

71

72

**Usage Examples:**

73

74

```javascript

75

const { JSDOM, VirtualConsole } = require("jsdom");

76

77

// Forward everything to Node.js console

78

const virtualConsole = new VirtualConsole();

79

virtualConsole.forwardTo(console);

80

81

const dom = new JSDOM(`

82

<script>

83

console.log("Info message");

84

console.error("Error message");

85

</script>

86

`, {

87

runScripts: "dangerously",

88

virtualConsole: virtualConsole

89

});

90

// Both messages appear in Node.js console

91

92

// Forward console but not jsdom errors

93

const vc2 = new VirtualConsole();

94

vc2.forwardTo(console, { jsdomErrors: "none" });

95

96

// Forward only specific jsdom error types

97

const vc3 = new VirtualConsole();

98

vc3.forwardTo(console, {

99

jsdomErrors: ["unhandled-exception", "not-implemented"]

100

});

101

102

// Custom console object

103

const customConsole = {

104

log: (msg) => console.log("[Custom]", msg),

105

error: (msg) => console.error("[Custom Error]", msg)

106

};

107

108

const vc4 = new VirtualConsole();

109

vc4.forwardTo(customConsole);

110

```

111

112

### Console Events

113

114

VirtualConsole emits events for all standard console methods. Listen to these events to handle specific console output.

115

116

**Standard Console Events:**

117

118

```javascript { .api }

119

/**

120

* Console method events

121

*/

122

"log" | "warn" | "error" | "info" | "debug" | "trace" | "dir" | "dirxml" |

123

"assert" | "count" | "countReset" | "group" | "groupCollapsed" | "groupEnd" |

124

"table" | "time" | "timeLog" | "timeEnd" | "clear"

125

```

126

127

Each event receives the same arguments that were passed to the corresponding console method.

128

129

**Usage Examples:**

130

131

```javascript

132

const { JSDOM, VirtualConsole } = require("jsdom");

133

134

const virtualConsole = new VirtualConsole();

135

136

// Listen to specific events

137

virtualConsole.on("log", (...args) => {

138

console.log("LOG:", ...args);

139

});

140

141

virtualConsole.on("error", (...args) => {

142

console.error("ERROR:", ...args);

143

});

144

145

virtualConsole.on("warn", (...args) => {

146

console.warn("WARNING:", ...args);

147

});

148

149

virtualConsole.on("info", (...args) => {

150

console.log("INFO:", ...args);

151

});

152

153

const dom = new JSDOM(`

154

<script>

155

console.log("Message 1", "Message 2");

156

console.error("Error occurred");

157

console.warn("Warning!");

158

console.info("Information");

159

</script>

160

`, {

161

runScripts: "dangerously",

162

virtualConsole: virtualConsole

163

});

164

```

165

166

### jsdomError Event

167

168

Special event emitted for jsdom implementation errors, similar to how error messages show up in web browser consoles.

169

170

```javascript { .api }

171

/**

172

* jsdom implementation error event

173

* @param error - Error object with type, message, and additional properties

174

*/

175

"jsdomError"

176

```

177

178

**Event Object Properties:**

179

180

- **`type`**: Error type string

181

- **`message`**: Error message

182

- Additional properties depend on error type

183

184

#### Error Types

185

186

##### css-parsing

187

188

```javascript { .api }

189

/**

190

* CSS stylesheet parsing error

191

*/

192

interface CSSParsingError {

193

type: "css-parsing";

194

message: string;

195

/** Exception from rrweb-cssom parser */

196

cause: Error;

197

/** Full text of the stylesheet */

198

sheetText: string;

199

}

200

```

201

202

##### not-implemented

203

204

```javascript { .api }

205

/**

206

* Stub method called from unimplemented web platform parts

207

*/

208

interface NotImplementedError {

209

type: "not-implemented";

210

message: string;

211

}

212

```

213

214

##### resource-loading

215

216

```javascript { .api }

217

/**

218

* Resource fetch error

219

*/

220

interface ResourceLoadingError {

221

type: "resource-loading";

222

message: string;

223

/** Network error exception */

224

cause: Error;

225

/** URL that was attempted */

226

url: string;

227

}

228

```

229

230

##### unhandled-exception

231

232

```javascript { .api }

233

/**

234

* Unhandled script execution error

235

*/

236

interface UnhandledExceptionError {

237

type: "unhandled-exception";

238

message: string;

239

/** Original exception object */

240

cause: Error;

241

}

242

```

243

244

**Usage Examples:**

245

246

```javascript

247

const { JSDOM, VirtualConsole } = require("jsdom");

248

249

const virtualConsole = new VirtualConsole();

250

251

// Handle all jsdom errors

252

virtualConsole.on("jsdomError", (error) => {

253

console.error(`jsdom error [${error.type}]:`, error.message);

254

255

switch (error.type) {

256

case "unhandled-exception":

257

console.error("Stack trace:", error.cause.stack);

258

break;

259

case "css-parsing":

260

console.error("Failed stylesheet:", error.sheetText.substring(0, 100));

261

break;

262

case "resource-loading":

263

console.error("Failed to load:", error.url);

264

break;

265

case "not-implemented":

266

// Ignore or log not-implemented warnings

267

break;

268

}

269

});

270

271

const dom = new JSDOM(`

272

<!DOCTYPE html>

273

<style>invalid css { { {</style>

274

<script>

275

// Unhandled exception

276

throw new Error("Something went wrong");

277

</script>

278

`, {

279

runScripts: "dangerously",

280

virtualConsole: virtualConsole

281

});

282

```

283

284

### Default VirtualConsole Behavior

285

286

When no `virtualConsole` option is provided to JSDOM constructor, a default VirtualConsole is created and forwarded to Node.js console.

287

288

```javascript

289

// Default behavior is equivalent to:

290

const virtualConsole = new VirtualConsole();

291

virtualConsole.forwardTo(console);

292

```

293

294

**Default jsdom Error Handling:**

295

296

- `"unhandled-exception"`: Logs `error.cause.stack` via `console.error()`

297

- Other errors: Logs `error.message` via `console.error()`

298

299

## Common Usage Patterns

300

301

### Capturing All Output

302

303

```javascript

304

const { JSDOM, VirtualConsole } = require("jsdom");

305

306

const virtualConsole = new VirtualConsole();

307

const logs = [];

308

309

virtualConsole.on("log", (...args) => {

310

logs.push({ type: "log", args });

311

});

312

313

virtualConsole.on("error", (...args) => {

314

logs.push({ type: "error", args });

315

});

316

317

const dom = new JSDOM(`

318

<script>

319

console.log("Test 1");

320

console.error("Test 2");

321

</script>

322

`, {

323

runScripts: "dangerously",

324

virtualConsole: virtualConsole

325

});

326

327

console.log(logs);

328

// [

329

// { type: "log", args: ["Test 1"] },

330

// { type: "error", args: ["Test 2"] }

331

// ]

332

```

333

334

### Filtering jsdom Errors

335

336

```javascript

337

const { JSDOM, VirtualConsole } = require("jsdom");

338

339

const virtualConsole = new VirtualConsole();

340

341

// Forward console methods but not jsdom errors

342

virtualConsole.forwardTo(console, { jsdomErrors: "none" });

343

344

// Handle jsdom errors separately

345

virtualConsole.on("jsdomError", (error) => {

346

// Only log serious errors

347

if (error.type === "unhandled-exception") {

348

console.error("Script error:", error.cause.stack);

349

}

350

// Ignore css-parsing, resource-loading, not-implemented

351

});

352

353

const dom = new JSDOM(`<!DOCTYPE html><script>console.log("Hi");</script>`, {

354

runScripts: "dangerously",

355

virtualConsole: virtualConsole

356

});

357

```

358

359

### Testing with Virtual Console

360

361

```javascript

362

const { JSDOM, VirtualConsole } = require("jsdom");

363

364

function testPageConsole() {

365

const virtualConsole = new VirtualConsole();

366

const errors = [];

367

368

virtualConsole.on("error", (...args) => {

369

errors.push(args);

370

});

371

372

const dom = new JSDOM(`

373

<script>

374

console.error("Expected error");

375

console.log("This is fine");

376

</script>

377

`, {

378

runScripts: "dangerously",

379

virtualConsole: virtualConsole

380

});

381

382

// Assert expected errors occurred

383

if (errors.length !== 1 || errors[0][0] !== "Expected error") {

384

throw new Error("Test failed");

385

}

386

387

console.log("Test passed");

388

}

389

390

testPageConsole();

391

```

392

393

### Silent Mode

394

395

```javascript

396

const { JSDOM, VirtualConsole } = require("jsdom");

397

398

// Create virtual console with no forwarding

399

const virtualConsole = new VirtualConsole();

400

// Don't call forwardTo() or add listeners

401

402

const dom = new JSDOM(`

403

<script>

404

console.log("This won't appear anywhere");

405

console.error("Neither will this");

406

</script>

407

`, {

408

runScripts: "dangerously",

409

virtualConsole: virtualConsole

410

});

411

412

// All console output is silenced

413

```

414

415

### Custom Logging Format

416

417

```javascript

418

const { JSDOM, VirtualConsole } = require("jsdom");

419

420

const virtualConsole = new VirtualConsole();

421

422

const customConsole = {

423

log: (...args) => {

424

const timestamp = new Date().toISOString();

425

console.log(`[${timestamp}] [LOG]`, ...args);

426

},

427

error: (...args) => {

428

const timestamp = new Date().toISOString();

429

console.error(`[${timestamp}] [ERROR]`, ...args);

430

},

431

warn: (...args) => {

432

const timestamp = new Date().toISOString();

433

console.warn(`[${timestamp}] [WARN]`, ...args);

434

}

435

};

436

437

virtualConsole.forwardTo(customConsole);

438

439

const dom = new JSDOM(`

440

<script>

441

console.log("Application started");

442

console.warn("Deprecated API used");

443

console.error("Something failed");

444

</script>

445

`, {

446

runScripts: "dangerously",

447

virtualConsole: virtualConsole

448

});

449

```

450

451

## Types

452

453

```javascript { .api }

454

interface CSSParsingError {

455

type: "css-parsing";

456

message: string;

457

cause: Error;

458

sheetText: string;

459

}

460

461

interface NotImplementedError {

462

type: "not-implemented";

463

message: string;

464

}

465

466

interface ResourceLoadingError {

467

type: "resource-loading";

468

message: string;

469

cause: Error;

470

url: string;

471

}

472

473

interface UnhandledExceptionError {

474

type: "unhandled-exception";

475

message: string;

476

cause: Error;

477

}

478

479

type JSDOMError =

480

| CSSParsingError

481

| NotImplementedError

482

| ResourceLoadingError

483

| UnhandledExceptionError;

484

```

485