Skip to content

Commit 12f0d19

Browse files
authored
[ruby][bidi] Add LogInspector (SeleniumHQ#11368)
1 parent 8d1fcf0 commit 12f0d19

File tree

9 files changed

+419
-1
lines changed

9 files changed

+419
-1
lines changed

common/src/web/bidi/logEntryAdded.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ <h1>Long entry added events</h1>
66

77
<button id="consoleLog" onclick="helloWorld()">Click me for console logs</button>
88

9+
<button id="consoleError" onclick="consoleError()">Click me for console error</button>
10+
911
<button id="jsException" onclick="createError()">Click me for jsException logs</button>
1012

1113
<button id="logWithStacktrace" onclick="bar()">Click me to get an error with stacktrace</button>
@@ -20,8 +22,10 @@ <h1>Long entry added events</h1>
2022
function foo() { throw new Error('Not working'); }
2123

2224
function bar() { foo(); }
25+
26+
function consoleError() { console.error('I am console error'); }
2327
</script>
2428

2529
</body>
2630

27-
</html>
31+
</html>

rb/lib/selenium/webdriver/bidi.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module Selenium
2121
module WebDriver
2222
class BiDi
2323
autoload :Session, 'selenium/webdriver/bidi/session'
24+
autoload :LogInspector, 'selenium/webdriver/bidi/log_inspector'
2425

2526
def initialize(url:)
2627
@ws = WebSocketConnection.new(url: url)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class BiDi
23+
class BaseLogEntry
24+
attr_accessor :level, :text, :timestamp, :stack_trace
25+
26+
def initialize(level:, text:, timestamp:, stack_trace:)
27+
@level = level
28+
@text = text
29+
@timestamp = timestamp
30+
@stack_trace = stack_trace
31+
end
32+
end # BaseLogEntry
33+
end # BiDi
34+
end # WebDriver
35+
end # Selenium
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class BiDi
23+
class ConsoleLogEntry < GenericLogEntry
24+
attr_accessor :method, :realm, :args
25+
26+
def initialize(level:, text:, timestamp:, type:, method:, realm:, args:, stack_trace:)
27+
super(level: level, text: text, timestamp: timestamp, type: type, stack_trace: stack_trace)
28+
@method = method
29+
@realm = realm
30+
@args = args
31+
end
32+
end # ConsoleLogEntry
33+
end # BiDi
34+
end # WebDriver
35+
end # Selenium
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class BiDi
23+
class GenericLogEntry < BaseLogEntry
24+
attr_accessor :type
25+
26+
def initialize(level:, text:, timestamp:, type:, stack_trace:)
27+
super(level: level, text: text, timestamp: timestamp, stack_trace: stack_trace)
28+
@type = type
29+
end
30+
end # GenericLogEntry
31+
end # BiDi
32+
end # WebDriver
33+
end # Selenium
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
class BiDi
23+
class JavascriptLogEntry < GenericLogEntry
24+
attr_accessor :type
25+
26+
def initialize(level:, text:, timestamp:, type:, stack_trace:)
27+
super(level: level, text: text, timestamp: timestamp, type: type, stack_trace: stack_trace)
28+
@type = "javascript"
29+
end
30+
end # JavascriptLogEntry
31+
end # BiDi
32+
end # WebDriver
33+
end # Selenium
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# frozen_string_literal: true
2+
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
# This file is automatically generated. Any changes will be lost!
21+
22+
require_relative 'log/base_log_entry'
23+
require_relative 'log/generic_log_entry'
24+
require_relative 'log/console_log_entry'
25+
require_relative 'log/javascript_log_entry'
26+
27+
module Selenium
28+
module WebDriver
29+
class BiDi
30+
class LogInspector
31+
EVENTS = {
32+
entry_added: 'entryAdded'
33+
}.freeze
34+
35+
LOG_LEVEL = {
36+
DEBUG: "debug",
37+
ERROR: "error",
38+
INFO: "info",
39+
WARNING: "warning"
40+
}.freeze
41+
42+
def initialize(driver, browsing_context_ids = nil)
43+
unless driver.capabilities.web_socket_url
44+
raise Error::WebDriverError, "WebDriver instance must support BiDi protocol"
45+
end
46+
47+
@bidi = driver.bidi
48+
@bidi.session.subscribe("log.entryAdded", browsing_context_ids)
49+
end
50+
51+
def on_console_entry(&block)
52+
enabled = log_listeners[:console].any?
53+
log_listeners[:console] << block
54+
return if enabled
55+
56+
on_log do |params|
57+
type = params["type"]
58+
console_log_events(params) if type.eql?("console")
59+
end
60+
end
61+
62+
def on_javascript_log(&block)
63+
enabled = log_listeners[:javascript].any?
64+
log_listeners[:javascript] << block
65+
return if enabled
66+
67+
on_log do |params|
68+
type = params["type"]
69+
javascript_log_events(params) if type.eql?("javascript")
70+
end
71+
end
72+
73+
def on_javascript_exception(&block)
74+
enabled = log_listeners[:js_exception].any?
75+
log_listeners[:js_exception] << block
76+
log_listeners[:javascript] << block
77+
return if enabled
78+
79+
on_log do |params|
80+
type = params["type"]
81+
level = params["level"]
82+
83+
javascript_log_events(params) if type.eql?("javascript") && level.eql?(LOG_LEVEL[:ERROR])
84+
end
85+
end
86+
87+
def on_log(&block)
88+
on(:entry_added, &block)
89+
end
90+
91+
private
92+
93+
def on(event, &block)
94+
event = EVENTS[event] if event.is_a?(Symbol)
95+
@bidi.callbacks["log.#{event}"] << block
96+
end
97+
98+
def log_listeners
99+
@log_listeners ||= Hash.new { |listeners, kind| listeners[kind] = [] }
100+
end
101+
102+
def console_log_events(params)
103+
event = ConsoleLogEntry.new(
104+
level: params['level'],
105+
text: params['text'],
106+
timestamp: params['timestamp'],
107+
type: params['type'],
108+
method: params['method'],
109+
realm: params['realm'],
110+
args: params['args'],
111+
stack_trace: params['stackTrace']
112+
)
113+
log_listeners[:console].each do |listener|
114+
listener.call(event)
115+
end
116+
end
117+
118+
def javascript_log_events(params)
119+
event = JavascriptLogEntry.new(
120+
level: params['level'],
121+
text: params['text'],
122+
timestamp: params['timestamp'],
123+
type: params['type'],
124+
stack_trace: params['stackTrace']
125+
)
126+
log_listeners[:javascript].each do |listener|
127+
listener.call(event)
128+
end
129+
130+
return unless params['level'].eql?(LOG_LEVEL[:ERROR])
131+
132+
log_listeners[:js_exception].each do |listener|
133+
listener.call(event)
134+
end
135+
end
136+
137+
end # LogInspector
138+
end # Bidi
139+
end # WebDriver
140+
end # Selenium

rb/lib/selenium/webdriver/bidi/session.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ def status
3232
Status.new(status['ready'], status['message'])
3333
end
3434

35+
def subscribe(events, browsing_contexts = nil)
36+
events_list = Array(events)
37+
browsing_contexts_list = browsing_contexts.nil? ? nil : Array(browsing_contexts)
38+
39+
@bidi.send_cmd("session.subscribe", events: events_list, contexts: browsing_contexts_list)
40+
end
41+
42+
def unsubscribe(events, browsing_contexts = nil)
43+
events_list = Array(events)
44+
browsing_contexts_list = browsing_contexts.nil? ? nil : Array(browsing_contexts)
45+
46+
@bidi.send_cmd("session.unsubscribe", events: events_list, contexts: browsing_contexts_list)
47+
end
48+
3549
end # Session
3650
end # BiDi
3751
end # WebDriver

0 commit comments

Comments
 (0)