or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

entry-point.mdevents.mdindex.mdjavascript.mdlogging.mdnetwork.mdtarget.md

javascript.mddocs/

0

# JavaScript Bindings and Script Evaluation

1

2

The JavaScript domain provides capabilities for executing JavaScript code, creating custom bindings between browser JavaScript and Java code, and managing script injection into pages.

3

4

## Capabilities

5

6

### V101Javascript

7

8

Main JavaScript handler that extends the base Javascript class with version-specific CDP implementations.

9

10

```java { .api }

11

/**

12

* Manages JavaScript bindings and script evaluation for CDP version 101

13

* Extends Javascript with ScriptIdentifier and BindingCalled event types

14

*/

15

public class V101Javascript extends Javascript<ScriptIdentifier, BindingCalled> {

16

17

/**

18

* Creates a new JavaScript handler instance

19

* @param devtools DevTools instance for CDP communication

20

*/

21

public V101Javascript(DevTools devtools);

22

}

23

```

24

25

**Inherited Methods from Javascript Base Class:**

26

27

```java { .api }

28

/**

29

* Pin a script to be evaluated on every new document load

30

* @param exposeScriptAs Name to expose the script result as

31

* @param script JavaScript code to execute

32

* @return ScriptId that can be used to remove the script later

33

*/

34

public ScriptId pin(String exposeScriptAs, String script);

35

36

/**

37

* Add a listener for JavaScript binding calls from the browser

38

* @param listener Consumer that receives the payload string from binding calls

39

*/

40

public void addBindingCalledListener(Consumer<String> listener);

41

42

/**

43

* Add a JavaScript binding that allows browser code to call Java

44

* @param scriptName Name of the binding function to create in browser

45

*/

46

public void addJsBinding(String scriptName);

47

48

/**

49

* Remove a previously added JavaScript binding

50

* @param scriptName Name of the binding function to remove

51

*/

52

public void removeJsBinding(String scriptName);

53

54

/**

55

* Disable the JavaScript domain and clean up all bindings and listeners

56

*/

57

public void disable();

58

```

59

60

**Usage Examples:**

61

62

```java

63

import org.openqa.selenium.devtools.v101.V101Javascript;

64

65

// Create JavaScript handler

66

V101Javascript javascript = new V101Javascript(devTools);

67

68

// Add a custom binding

69

javascript.addJsBinding("sendDataToJava");

70

71

// Listen for binding calls

72

javascript.addBindingCalledListener(payload -> {

73

System.out.println("Received from browser: " + payload);

74

// Process the data sent from browser JavaScript

75

processDataFromBrowser(payload);

76

});

77

78

// Pin a script to run on every page load

79

ScriptId scriptId = javascript.pin("myUtility",

80

"window.myUtility = { " +

81

" sendMessage: function(msg) { " +

82

" sendDataToJava(JSON.stringify({type: 'message', data: msg})); " +

83

" } " +

84

"};"

85

);

86

87

// Navigate to a page

88

driver.get("https://example.com");

89

90

// The pinned script is now available on the page

91

driver.executeScript("myUtility.sendMessage('Hello from browser!');");

92

93

// Clean up when done

94

javascript.disable();

95

```

96

97

### ScriptId

98

99

Wrapper for script identifiers returned when pinning scripts to pages.

100

101

```java { .api }

102

/**

103

* Represents a script identifier for pinned scripts

104

* Used to manage and remove scripts that are evaluated on new documents

105

*/

106

public class ScriptId {

107

108

/**

109

* Get the underlying script identifier

110

* @return The actual script identifier object from CDP

111

*/

112

public Object getActualId();

113

}

114

```

115

116

**Usage Example:**

117

118

```java

119

// Pin multiple scripts and manage them

120

List<ScriptId> pinnedScripts = new ArrayList<>();

121

122

// Add utility functions

123

ScriptId utilityScript = javascript.pin("utils",

124

"window.utils = { " +

125

" logMessage: function(msg) { console.log('Utils:', msg); }, " +

126

" sendEvent: function(event, data) { " +

127

" myEventHandler(JSON.stringify({event: event, data: data})); " +

128

" } " +

129

"};"

130

);

131

pinnedScripts.add(utilityScript);

132

133

// Add monitoring script

134

ScriptId monitorScript = javascript.pin("monitor",

135

"window.addEventListener('error', function(e) { " +

136

" errorHandler(JSON.stringify({" +

137

" message: e.message, " +

138

" filename: e.filename, " +

139

" lineno: e.lineno " +

140

" })); " +

141

"});"

142

);

143

pinnedScripts.add(monitorScript);

144

145

// Scripts are now available on all new pages

146

// Remove specific scripts if needed (implementation would require CDP commands)

147

```

148

149

### JavaScript Binding Communication

150

151

**Setting up Two-way Communication:**

152

153

```java

154

// Set up bidirectional communication between Java and browser JavaScript

155

156

// 1. Add Java-to-browser functions (via executeScript)

157

// 2. Add browser-to-Java bindings

158

javascript.addJsBinding("sendToJava");

159

javascript.addJsBinding("reportError");

160

javascript.addJsBinding("requestData");

161

162

// Handle different types of messages from browser

163

javascript.addBindingCalledListener(payload -> {

164

try {

165

JsonObject message = JsonParser.parseString(payload).getAsJsonObject();

166

String type = message.get("type").getAsString();

167

168

switch (type) {

169

case "data":

170

handleDataFromBrowser(message.get("data"));

171

break;

172

case "error":

173

handleErrorFromBrowser(message.get("error"));

174

break;

175

case "request":

176

handleRequestFromBrowser(message.get("request"));

177

break;

178

default:

179

System.out.println("Unknown message type: " + type);

180

}

181

} catch (Exception e) {

182

System.err.println("Error parsing browser message: " + e.getMessage());

183

}

184

});

185

186

// Pin helper script for structured communication

187

javascript.pin("bridge",

188

"window.bridge = { " +

189

" sendData: function(data) { " +

190

" sendToJava(JSON.stringify({type: 'data', data: data})); " +

191

" }, " +

192

" reportError: function(error) { " +

193

" reportError(JSON.stringify({type: 'error', error: error})); " +

194

" }, " +

195

" requestData: function(requestId, params) { " +

196

" requestData(JSON.stringify({type: 'request', id: requestId, params: params})); " +

197

" } " +

198

"};"

199

);

200

```

201

202

### CDP Protocol Types

203

204

The underlying CDP protocol types used by the JavaScript domain:

205

206

```java { .api }

207

/**

208

* CDP Page.ScriptIdentifier for pinned scripts

209

* Raw identifier from the Chrome DevTools Protocol

210

*/

211

public class ScriptIdentifier {

212

public String getId();

213

}

214

215

/**

216

* CDP Runtime.bindingCalled event data

217

* Raw event data when a JavaScript binding is called

218

*/

219

public class BindingCalled {

220

public String getName();

221

public String getPayload();

222

public Optional<ExecutionContextId> getExecutionContextId();

223

}

224

225

/**

226

* CDP Runtime.addBinding command parameters

227

*/

228

public static Command<Void> addBinding(

229

String name,

230

Optional<String> executionContextName,

231

Optional<Integer> executionContextId

232

);

233

234

/**

235

* CDP Runtime.removeBinding command

236

*/

237

public static Command<Void> removeBinding(String name);

238

239

/**

240

* CDP Page.addScriptToEvaluateOnNewDocument command

241

*/

242

public static Command<ScriptIdentifier> addScriptToEvaluateOnNewDocument(

243

String source,

244

Optional<String> worldName,

245

Optional<Boolean> includeCommandLineAPI

246

);

247

248

/**

249

* CDP Page.removeScriptToEvaluateOnNewDocument command

250

*/

251

public static Command<Void> removeScriptToEvaluateOnNewDocument(ScriptIdentifier identifier);

252

```

253

254

### Runtime and Page Commands

255

256

The V101Javascript class internally uses these CDP commands:

257

258

```java { .api }

259

// Runtime domain commands for bindings

260

public static Command<Void> Runtime.enable();

261

public static Command<Void> Runtime.disable();

262

public static Command<Void> Runtime.addBinding(String name, Optional<String> executionContextName, Optional<Integer> executionContextId);

263

public static Command<Void> Runtime.removeBinding(String name);

264

public static Event<BindingCalled> Runtime.bindingCalled();

265

266

// Page domain commands for script injection

267

public static Command<Void> Page.enable();

268

public static Command<Void> Page.disable();

269

public static Command<ScriptIdentifier> Page.addScriptToEvaluateOnNewDocument(String script, Optional<String> worldName, Optional<Boolean> includeCommandLineAPI);

270

public static Command<Void> Page.removeScriptToEvaluateOnNewDocument(ScriptIdentifier identifier);

271

```

272

273

## Advanced Usage Patterns

274

275

### Script Injection Patterns

276

277

```java

278

// Pattern 1: Utility functions available on all pages

279

ScriptId utilities = javascript.pin("pageUtils",

280

"window.pageUtils = { " +

281

" getElementInfo: function(selector) { " +

282

" const el = document.querySelector(selector); " +

283

" return el ? { " +

284

" tagName: el.tagName, " +

285

" id: el.id, " +

286

" className: el.className, " +

287

" textContent: el.textContent.substring(0, 100) " +

288

" } : null; " +

289

" }, " +

290

" highlightElement: function(selector) { " +

291

" const el = document.querySelector(selector); " +

292

" if (el) { " +

293

" el.style.border = '3px solid red'; " +

294

" setTimeout(() => el.style.border = '', 2000); " +

295

" } " +

296

" } " +

297

"};"

298

);

299

300

// Pattern 2: Event monitoring and reporting

301

javascript.pin("monitor",

302

"window.addEventListener('click', function(e) { " +

303

" if (e.target) { " +

304

" reportEvent(JSON.stringify({ " +

305

" type: 'click', " +

306

" element: e.target.tagName, " +

307

" id: e.target.id, " +

308

" classes: e.target.className " +

309

" })); " +

310

" } " +

311

"});"

312

);

313

```

314

315

### Error Handling and Recovery

316

317

```java

318

// Robust binding setup with error handling

319

try {

320

javascript.addJsBinding("dataHandler");

321

javascript.addJsBinding("errorReporter");

322

323

javascript.addBindingCalledListener(payload -> {

324

try {

325

processBinding(payload);

326

} catch (Exception e) {

327

System.err.println("Error processing binding: " + e.getMessage());

328

// Could implement retry logic or error reporting here

329

}

330

});

331

332

} catch (Exception e) {

333

System.err.println("Failed to set up JavaScript bindings: " + e.getMessage());

334

// Implement fallback strategies

335

}

336

```

337

338

### Performance Considerations

339

340

```java

341

// Efficient script injection - avoid heavy operations in pinned scripts

342

javascript.pin("lightweight",

343

"// Keep pinned scripts minimal and fast " +

344

"window.quickUtils = { " +

345

" ready: true, " +

346

" version: '1.0' " +

347

"};"

348

);

349

350

// Use binding calls for heavy operations instead of pinned scripts

351

javascript.addBindingCalledListener(payload -> {

352

// Process heavy operations in Java rather than browser

353

CompletableFuture.supplyAsync(() -> {

354

return processLargeDataSet(payload);

355

}).thenAccept(result -> {

356

// Send result back to browser via executeScript if needed

357

driver.executeScript("window.processResult = arguments[0];", result);

358

});

359

});

360

```