diff --git a/.rubocop.yml b/.rubocop.yml index 0b4d78b2..63bff409 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -116,6 +116,43 @@ Style/DefWithParentheses: Style/MethodDefParentheses: Enabled: true +Style/MethodCallWithArgsParentheses: + Enabled: true + IgnoredMethods: + # Gemfile, gemspec + - source + - add_dependency + - add_development_dependency + + # include/require + - require + - require_relative + - include + + # fundamental methods + - raise + - sleep + + # RSpec + - describe + - it + - to + - not_to + - be + - eq + + # async/await + - define_async_method + - await + - future + + # utils + - debug_print + - debug_puts + +Style/MethodCallWithoutArgsParentheses: + Enabled: true + Style/RedundantFreeze: Enabled: true diff --git a/lib/puppeteer.rb b/lib/puppeteer.rb index b233f6a8..79e22346 100644 --- a/lib/puppeteer.rb +++ b/lib/puppeteer.rb @@ -6,6 +6,7 @@ class Puppeteer; end # Custom data types. require 'puppeteer/device' +require 'puppeteer/events' require 'puppeteer/errors' require 'puppeteer/viewport' diff --git a/lib/puppeteer/browser.rb b/lib/puppeteer/browser.rb index c7886541..658e843e 100644 --- a/lib/puppeteer/browser.rb +++ b/lib/puppeteer/browser.rb @@ -46,37 +46,30 @@ def initialize(connection:, context_ids:, ignore_https_errors:, default_viewport @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id) end @targets = {} - @connection.on_event 'Events.Connection.Disconnected' do - emit_event 'Events.Browser.Disconnected' + @connection.on_event(ConnectionEmittedEvents::Disconnected) do + emit_event(BrowserEmittedEvents::Disconnected) end - @connection.on_event 'Target.targetCreated', &method(:handle_target_created) - @connection.on_event 'Target.targetDestroyed', &method(:handle_target_destroyed) - @connection.on_event 'Target.targetInfoChanged', &method(:handle_target_info_changed) + @connection.on_event('Target.targetCreated', &method(:handle_target_created)) + @connection.on_event('Target.targetDestroyed', &method(:handle_target_destroyed)) + @connection.on_event('Target.targetInfoChanged', &method(:handle_target_info_changed)) end - EVENT_MAPPINGS = { - disconnected: 'Events.Browser.Disconnected', - targetcreated: 'Events.Browser.TargetCreated', - targetchanged: 'Events.Browser.TargetChanged', - targetdestroyed: 'Events.Browser.TargetDestroyed', - } - # @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed def on(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless BrowserEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}") end - add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end # @param event_name [Symbol] def once(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless BrowserEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserEmittedEvents.values.to_a.join(", ")}") end - observe_first(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end # @return [Puppeteer::BrowserRunner::BrowserProcess] @@ -137,8 +130,8 @@ def handle_target_created(event) # assert(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated'); @targets[target_info.target_id] = target if await target.initialized_promise - emit_event 'Events.Browser.TargetCreated', target - context.emit_event 'Events.BrowserContext.TargetCreated', target + emit_event(BrowserEmittedEvents::TargetCreated, target) + context.emit_event(BrowserContextEmittedEvents::TargetCreated, target) end end @@ -150,8 +143,8 @@ def handle_target_destroyed(event) @targets.delete(target_id) target.closed_callback if await target.initialized_promise - emit_event 'Events.Browser.TargetDestroyed', target - target.browser_context.emit_event 'Events.BrowserContext.TargetDestroyed', target + emit_event(BrowserEmittedEvents::TargetDestroyed, target) + target.browser_context.emit_event(BrowserContextEmittedEvents::TargetDestroyed, target) end end @@ -169,8 +162,8 @@ def handle_target_info_changed(event) was_initialized = target.initialized? target.handle_target_info_changed(target_info) if was_initialized && previous_url != target.url - emit_event 'Events.Browser.TargetChanged', target - target.browser_context.emit_event 'Events.BrowserContext.TargetChanged', target + emit_event(BrowserEmittedEvents::TargetChanged, target) + target.browser_context.emit_event(BrowserContextEmittedEvents::TargetChanged, target) end end @@ -222,12 +215,12 @@ def wait_for_target(predicate:, timeout: nil) event_listening_ids = [] target_promise = resolvable_future - event_listening_ids << add_event_listener('Events.Browser.TargetCreated') do |target| + event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetCreated) do |target| if predicate.call(target) target_promise.fulfill(target) end end - event_listening_ids << add_event_listener('Events.Browser.TargetChanged') do |target| + event_listening_ids << add_event_listener(BrowserEmittedEvents::TargetChanged) do |target| if predicate.call(target) target_promise.fulfill(target) end diff --git a/lib/puppeteer/browser_context.rb b/lib/puppeteer/browser_context.rb index bcd25ec3..6cec676b 100644 --- a/lib/puppeteer/browser_context.rb +++ b/lib/puppeteer/browser_context.rb @@ -11,29 +11,22 @@ def initialize(connection, browser, context_id) @id = context_id end - EVENT_MAPPINGS = { - disconnected: 'Events.BrowserContext.Disconnected', - targetcreated: 'Events.BrowserContext.TargetCreated', - targetchanged: 'Events.BrowserContext.TargetChanged', - targetdestroyed: 'Events.BrowserContext.TargetDestroyed', - } - # @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed def on(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless BrowserContextEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserContextEmittedEvents.values.to_a.join(", ")}") end - add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end # @param event_name [Symbol] def once(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless BrowserContextEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{BrowserContextEmittedEvents.values.to_a.join(", ")}") end - observe_first(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end # @return {!Array} target diff --git a/lib/puppeteer/cdp_session.rb b/lib/puppeteer/cdp_session.rb index 422a2761..28157c06 100644 --- a/lib/puppeteer/cdp_session.rb +++ b/lib/puppeteer/cdp_session.rb @@ -47,7 +47,7 @@ def handle_message(message) raise Error.new("unknown id: #{id}") end else - emit_event message['method'], message['params'] + emit_event(message['method'], message['params']) end end @@ -79,7 +79,7 @@ def handle_closed end @callbacks.clear @connection = nil - emit_event 'Events.CDPSession.Disconnected' + emit_event(CDPSessionEmittedEvents::Disconnected) end # @param event_name [String] diff --git a/lib/puppeteer/connection.rb b/lib/puppeteer/connection.rb index 23818b0c..63b8a5c1 100644 --- a/lib/puppeteer/connection.rb +++ b/lib/puppeteer/connection.rb @@ -211,7 +211,7 @@ def handle_message(message) end end else - emit_event message['method'], message['params'] + emit_event(message['method'], message['params']) end end @@ -233,7 +233,7 @@ def handle_message(message) session.handle_closed end @sessions.clear - emit_event 'Events.Connection.Disconnected' + emit_event(ConnectionEmittedEvents::Disconnected) end def on_close(&block) diff --git a/lib/puppeteer/dom_world.rb b/lib/puppeteer/dom_world.rb index 07337af8..d6905bf2 100644 --- a/lib/puppeteer/dom_world.rb +++ b/lib/puppeteer/dom_world.rb @@ -134,7 +134,7 @@ def SS(selector) # @return [String] def content - evaluate <<-JAVASCRIPT + evaluate(<<-JAVASCRIPT) () => { let retVal = ''; if (document.doctype) diff --git a/lib/puppeteer/event_callbackable.rb b/lib/puppeteer/event_callbackable.rb index 02dfdc7e..e1e81932 100644 --- a/lib/puppeteer/event_callbackable.rb +++ b/lib/puppeteer/event_callbackable.rb @@ -31,6 +31,8 @@ def add_event_listener(event_name, &block) (@event_listeners[event_name] ||= EventListeners.new).add(&block) end + alias_method :on, :add_event_listener + def remove_event_listener(*id_args) (@event_listeners ||= {}).each do |event_name, listeners| id_args.each do |id| @@ -50,6 +52,8 @@ def observe_first(event_name, &block) end end + alias_method :once, :observe_first + def on_event(event_name, &block) @event_callbackable_handlers ||= {} @event_callbackable_handlers[event_name] = block diff --git a/lib/puppeteer/events.rb b/lib/puppeteer/events.rb new file mode 100644 index 00000000..03953432 --- /dev/null +++ b/lib/puppeteer/events.rb @@ -0,0 +1,184 @@ +require 'digest/md5' + +module EventsDefinitionUtils + refine Kernel do + # Symbol is used to prevent external parties listening to these events + def Symbol(str) + Digest::MD5.hexdigest(str) + end + end + + refine Hash do + def define_const_into(target_module) + each do |key, value| + target_module.const_set(key, value) + target_module.define_singleton_method(key) { value } + end + keyset = Set.new(keys) + valueset = Set.new(values) + target_module.define_singleton_method(:keys) { keyset } + target_module.define_singleton_method(:values) { valueset } + end + end +end + +using EventsDefinitionUtils + +# Internal events that the Connection class emits. +module ConnectionEmittedEvents ; end + +{ + Disconnected: Symbol('Connection.Disconnected'), +}.define_const_into(ConnectionEmittedEvents) + +# Internal events that the CDPSession class emits. +module CDPSessionEmittedEvents ; end + +{ + Disconnected: Symbol('CDPSession.Disconnected'), +}.define_const_into(CDPSessionEmittedEvents) + +# All the events a Browser may emit. +module BrowserEmittedEvents ; end + +{ + # Emitted when Puppeteer gets disconnected from the Chromium instance. This might happen because of one of the following: + # - Chromium is closed or crashed + # - The Browser#disconnect method was called. + Disconnected: 'disconnected', + + # Emitted when the url of a target changes. Contains a {@link Target} instance. + TargetChanged: 'targetchanged', + + # Emitted when a target is created, for example when a new page is opened by + # window.open or by Browser#newPage + # Contains a Target instance. + TargetCreated: 'targetcreated', + + # Emitted when a target is destroyed, for example when a page is closed. + # Contains a Target instance. + TargetDestroyed: 'targetdestroyed', +}.define_const_into(BrowserEmittedEvents) + +module BrowserContextEmittedEvents ; end + +{ + # Emitted when the url of a target inside the browser context changes. + # Contains a Target instance. + TargetChanged: 'targetchanged', + + # Emitted when a target is created, for example when a new page is opened by + # window.open or by BrowserContext#newPage + # Contains a Target instance. + TargetCreated: 'targetcreated', + + # Emitted when a target is destroyed within the browser context, for example when a page is closed. + # Contains a Target instance. + TargetDestroyed: 'targetdestroyed', +}.define_const_into(BrowserContextEmittedEvents) + +# We use symbols to prevent any external parties listening to these events. +# They are internal to Puppeteer. +module NetworkManagerEmittedEvents ; end + +{ + Request: Symbol('NetworkManager.Request'), + Response: Symbol('NetworkManager.Response'), + RequestFailed: Symbol('NetworkManager.RequestFailed'), + RequestFinished: Symbol('NetworkManager.RequestFinished'), +}.define_const_into(NetworkManagerEmittedEvents) + + +# We use symbols to prevent external parties listening to these events. +# They are internal to Puppeteer. +module FrameManagerEmittedEvents ; end + +{ + FrameAttached: Symbol('FrameManager.FrameAttached'), + FrameNavigated: Symbol('FrameManager.FrameNavigated'), + FrameDetached: Symbol('FrameManager.FrameDetached'), + LifecycleEvent: Symbol('FrameManager.LifecycleEvent'), + FrameNavigatedWithinDocument: Symbol('FrameManager.FrameNavigatedWithinDocument'), + ExecutionContextCreated: Symbol('FrameManager.ExecutionContextCreated'), + ExecutionContextDestroyed: Symbol('FrameManager.ExecutionContextDestroyed'), +}.define_const_into(FrameManagerEmittedEvents) + +# All the events that a page instance may emit. +module PageEmittedEvents ; end + +{ + # Emitted when the page closes. + Close: 'close', + + # Emitted when JavaScript within the page calls one of console API methods, + # e.g. `console.log` or `console.dir`. Also emitted if the page throws an + # error or a warning. + Console: 'console', + + # Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, + # `confirm` or `beforeunload`. Puppeteer can respond to the dialog via + # Dialog#accept or Dialog#dismiss. + Dialog: 'dialog', + + # Emitted when the JavaScript + # {https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded DOMContentLoaded} event is dispatched. + DOMContentLoaded: 'domcontentloaded', + + # Emitted when the page crashes. Will contain an `Error`. + Error: 'error', + + # Emitted when a frame is attached. Will contain a Frame. + FrameAttached: 'frameattached', + # Emitted when a frame is detached. Will contain a Frame. + FrameDetached: 'framedetached', + # Emitted when a frame is navigated to a new URL. Will contain a {@link Frame}. + FrameNavigated: 'framenavigated', + + # Emitted when the JavaScript + # {https://developer.mozilla.org/en-US/docs/Web/Events/load | load} event is dispatched. + Load: 'load', + + # Emitted when the JavaScript code makes a call to `console.timeStamp`. For + # the list of metrics see {@link Page.metrics | page.metrics}. + # + # Contains an object with two properties: + # - `title`: the title passed to `console.timeStamp` + # - `metrics`: objec containing metrics as key/value pairs. The values will be `number`s. + Metrics: 'metrics', + + # Emitted when an uncaught exception happens within the page. + # Contains an `Error`. + PageError: 'pageerror', + + # Emitted when the page opens a new tab or window. + # Contains a Page corresponding to the popup window. + Popup: 'popup', + + # Emitted when a page issues a request and contains a HTTPRequest. + # + # The object is readonly. See Page#setRequestInterception for intercepting and mutating requests. + Request: 'request', + + # Emitted when a request fails, for example by timing out. + # + # Contains a HTTPRequest. + # + # NOTE: HTTP Error responses, such as 404 or 503, are still successful + # responses from HTTP standpoint, so request will complete with + # `requestfinished` event and not with `requestfailed`. + RequestFailed: 'requestfailed', + + # Emitted when a request finishes successfully. Contains a HTTPRequest. + RequestFinished: 'requestfinished', + + # Emitted when a response is received. Contains a HTTPResponse. + Response: 'response', + + # Emitted when a dedicated + # {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is spawned by the page. + WorkerCreated: 'workercreated', + + # Emitted when a dedicated + # {https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API WebWorker} is destroyed by the page. + WorkerDestroyed: 'workerdestroyed', +}.define_const_into(PageEmittedEvents) diff --git a/lib/puppeteer/frame_manager.rb b/lib/puppeteer/frame_manager.rb index ef0263f7..74e65e07 100644 --- a/lib/puppeteer/frame_manager.rb +++ b/lib/puppeteer/frame_manager.rb @@ -27,31 +27,31 @@ def initialize(client, page, ignore_https_errors, timeout_settings) # @type {!Set} @isolated_worlds = Set.new - @client.on_event 'Page.frameAttached' do |event| + @client.on_event('Page.frameAttached') do |event| handle_frame_attached(event['frameId'], event['parentFrameId']) end - @client.on_event 'Page.frameNavigated' do |event| + @client.on_event('Page.frameNavigated') do |event| handle_frame_navigated(event['frame']) end - @client.on_event 'Page.navigatedWithinDocument' do |event| + @client.on_event('Page.navigatedWithinDocument') do |event| handle_frame_navigated_within_document(event['frameId'], event['url']) end - @client.on_event 'Page.frameDetached' do |event| + @client.on_event('Page.frameDetached') do |event| handle_frame_detached(event['frameId']) end - @client.on_event 'Page.frameStoppedLoading' do |event| + @client.on_event('Page.frameStoppedLoading') do |event| handle_frame_stopped_loading(event['frameId']) end - @client.on_event 'Runtime.executionContextCreated' do |event| + @client.on_event('Runtime.executionContextCreated') do |event| handle_execution_context_created(event['context']) end - @client.on_event 'Runtime.executionContextDestroyed' do |event| + @client.on_event('Runtime.executionContextDestroyed') do |event| handle_execution_context_destroyed(event['executionContextId']) end - @client.on_event 'Runtime.executionContextsCleared' do |event| + @client.on_event('Runtime.executionContextsCleared') do |event| handle_execution_contexts_cleared end - @client.on_event 'Page.lifecycleEvent' do |event| + @client.on_event('Page.lifecycleEvent') do |event| handle_lifecycle_event(event) end end @@ -155,7 +155,7 @@ def handle_lifecycle_event(event) frame = @frames[event['frameId']] return if !frame frame.handle_lifecycle_event(event['loaderId'], event['name']) - emit_event 'Events.FrameManager.LifecycleEvent', frame + emit_event(FrameManagerEmittedEvents::LifecycleEvent, frame) end # @param {string} frameId @@ -163,7 +163,7 @@ def handle_frame_stopped_loading(frame_id) frame = @frames[frame_id] return if !frame frame.handle_loading_stopped - emit_event 'Events.FrameManager.LifecycleEvent', frame + emit_event(FrameManagerEmittedEvents::LifecycleEvent, frame) end # @param frame_tree [Hash] @@ -211,7 +211,7 @@ def handle_frame_attached(frame_id, parent_frame_id) frame = Puppeteer::Frame.new(self, @client, parent_frame, frame_id) @frames[frame_id] = frame - emit_event 'Events.FrameManager.FrameAttached', frame + emit_event(FrameManagerEmittedEvents::FrameAttached, frame) end # @param frame_payload [Hash] @@ -252,7 +252,7 @@ def handle_frame_navigated(frame_payload) # Update frame payload. frame.navigated(frame_payload) - emit_event 'Events.FrameManager.FrameNavigated', frame + emit_event(FrameManagerEmittedEvents::FrameNavigated, frame) end # @param name [String] @@ -280,8 +280,8 @@ def handle_frame_navigated_within_document(frame_id, url) frame = @frames[frame_id] return unless frame frame.navigated_within_document(url) - emit_event 'Events.FrameManager.FrameNavigatedWithinDocument', frame - emit_event 'Events.FrameManager.FrameNavigated', frame + emit_event(FrameManagerEmittedEvents::FrameNavigatedWithinDocument, frame) + emit_event(FrameManagerEmittedEvents::FrameNavigated, frame) end # @param frame_id [String] @@ -349,7 +349,7 @@ def execution_context_by_id(context_id) end frame.detach @frames.delete(frame.id) - emit_event 'Events.FrameManager.FrameDetached', frame + emit_event(FrameManagerEmittedEvents::FrameDetached, frame) end private def assert_no_legacy_navigation_options(wait_until:) diff --git a/lib/puppeteer/lifecycle_watcher.rb b/lib/puppeteer/lifecycle_watcher.rb index fe343d1b..aad33bba 100644 --- a/lib/puppeteer/lifecycle_watcher.rb +++ b/lib/puppeteer/lifecycle_watcher.rb @@ -69,17 +69,17 @@ def initialize(frame_manager, frame, wait_until, timeout) @timeout = timeout @listener_ids = {} - @listener_ids['client'] = @frame_manager.client.add_event_listener('Events.CDPSession.Disconnected') do + @listener_ids['client'] = @frame_manager.client.add_event_listener(CDPSessionEmittedEvents::Disconnected) do terminate(TerminatedError.new('Navigation failed because browser has disconnected!')) end @listener_ids['frame_manager'] = [ - @frame_manager.add_event_listener('Events.FrameManager.LifecycleEvent') do |_| + @frame_manager.add_event_listener(FrameManagerEmittedEvents::LifecycleEvent) do |_| check_lifecycle_complete end, - @frame_manager.add_event_listener('Events.FrameManager.FrameNavigatedWithinDocument', &method(:navigated_within_document)), - @frame_manager.add_event_listener('Events.FrameManager.FrameDetached', &method(:handle_frame_detached)), + @frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameNavigatedWithinDocument, &method(:navigated_within_document)), + @frame_manager.add_event_listener(FrameManagerEmittedEvents::FrameDetached, &method(:handle_frame_detached)), ] - @listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener('Events.NetworkManager.Request', &method(:handle_request)) + @listener_ids['network_manager'] = @frame_manager.network_manager.add_event_listener(NetworkManagerEmittedEvents::Request, &method(:handle_request)) @same_document_navigation_promise = resolvable_future @lifecycle_promise = resolvable_future diff --git a/lib/puppeteer/network_manager.rb b/lib/puppeteer/network_manager.rb index b6e0269b..40840952 100644 --- a/lib/puppeteer/network_manager.rb +++ b/lib/puppeteer/network_manager.rb @@ -212,7 +212,7 @@ def request_interception=(enabled) frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) } request = Puppeteer::Request.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain) @request_id_to_request[event['requestId']] = request - emit_event 'Events.NetworkManager.Request', request + emit_event(NetworkManagerEmittedEvents::Request, request) end private def handle_request_served_from_cache(event) @@ -230,8 +230,8 @@ def request_interception=(enabled) response.internal.body_loaded_promise.reject(Puppeteer::Response::Redirected.new) @request_id_to_request.delete(request.internal.request_id) @attempted_authentications.delete(request.internal.interception_id) - emit_event 'Events.NetworkManager.Response', response - emit_event 'Events.NetworkManager.RequestFinished', request + emit_event(NetworkManagerEmittedEvents::Response, response) + emit_event(NetworkManagerEmittedEvents::RequestFinished, request) end # @param event [Hash] @@ -242,7 +242,7 @@ def request_interception=(enabled) response = Puppeteer::Response.new(@client, request, event['response']) request.internal.response = response - emit_event 'Events.NetworkManager.Response', response + emit_event(NetworkManagerEmittedEvents::Response, response) end private def handle_loading_finished(event) @@ -260,7 +260,7 @@ def request_interception=(enabled) @request_id_to_request.delete(request.internal.request_id) @attempted_authentications.delete(request.internal.interception_id) - emit_event 'Events.NetworkManager.RequestFinished', request + emit_event(NetworkManagerEmittedEvents::RequestFinished, request) end private def handle_loading_failed(event) @@ -275,6 +275,6 @@ def request_interception=(enabled) end @request_id_to_request.delete(request.internal.request_id) @attempted_authentications.delete(request.internal.interception_id) - emit_event 'Events.NetworkManager.RequestFailed', request + emit_event(NetworkManagerEmittedEvents::RequestFailed, request) end end diff --git a/lib/puppeteer/page.rb b/lib/puppeteer/page.rb index 3c24b0e4..8ed91964 100644 --- a/lib/puppeteer/page.rb +++ b/lib/puppeteer/page.rb @@ -46,7 +46,7 @@ def initialize(client, target, ignore_https_errors, screenshot_task_queue) @screenshot_task_queue = screenshot_task_queue @workers = {} - @client.on_event 'Target.attachedToTarget' do |event| + @client.on_event('Target.attachedToTarget') do |event| if event['targetInfo']['type'] != 'worker' # If we don't detach from service workers, they will never die. await @client.send_message('Target.detachFromTarget', sessionId: event['sessionId']) @@ -56,65 +56,65 @@ def initialize(client, target, ignore_https_errors, screenshot_task_queue) session = Puppeteer::Connection.from_session(@client).session(event['sessionId']) # rubocop:disable Lint/UselessAssignment # const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this)); # this._workers.set(event.sessionId, worker); - # this.emit(Events.Page.WorkerCreated, worker); + # this.emit(PageEmittedEvents::WorkerCreated, worker); end - @client.on_event 'Target.detachedFromTarget' do |event| + @client.on_event('Target.detachedFromTarget') do |event| session_id = event['sessionId'] worker = @workers[session_id] next unless worker - emit_event('Events.Page.WorkerDestroyed', worker) + emit_event(PageEmittedEvents::WorkerDestroyed, worker) @workers.delete(session_id) end - @frame_manager.on_event 'Events.FrameManager.FrameAttached' do |event| - emit_event 'Events.Page.FrameAttached', event + @frame_manager.on_event(FrameManagerEmittedEvents::FrameAttached) do |event| + emit_event(PageEmittedEvents::FrameAttached, event) end - @frame_manager.on_event 'Events.FrameManager.FrameDetached' do |event| - emit_event 'Events.Page.FrameDetached', event + @frame_manager.on_event(FrameManagerEmittedEvents::FrameDetached) do |event| + emit_event(PageEmittedEvents::FrameDetached, event) end - @frame_manager.on_event 'Events.FrameManager.FrameNavigated' do |event| - emit_event 'Events.Page.FrameNavigated', event + @frame_manager.on_event(FrameManagerEmittedEvents::FrameNavigated) do |event| + emit_event(PageEmittedEvents::FrameNavigated, event) end network_manager = @frame_manager.network_manager - network_manager.on_event 'Events.NetworkManager.Request' do |event| - emit_event 'Events.Page.Request', event + network_manager.on_event(NetworkManagerEmittedEvents::Request) do |event| + emit_event(PageEmittedEvents::Request, event) end - network_manager.on_event 'Events.NetworkManager.Response' do |event| - emit_event 'Events.Page.Response', event + network_manager.on_event(NetworkManagerEmittedEvents::Response) do |event| + emit_event(PageEmittedEvents::Response, event) end - network_manager.on_event 'Events.NetworkManager.RequestFailed' do |event| - emit_event 'Events.Page.RequestFailed', event + network_manager.on_event(NetworkManagerEmittedEvents::RequestFailed) do |event| + emit_event(PageEmittedEvents::RequestFailed, event) end - network_manager.on_event 'Events.NetworkManager.RequestFinished' do |event| - emit_event 'Events.Page.RequestFinished', event + network_manager.on_event(NetworkManagerEmittedEvents::RequestFinished) do |event| + emit_event(PageEmittedEvents::RequestFinished, event) end @file_chooser_interception_is_disabled = false @file_chooser_interceptors = Set.new - @client.on_event 'Page.domContentEventFired' do |event| - emit_event 'Events.Page.DOMContentLoaded' + @client.on_event('Page.domContentEventFired') do |event| + emit_event(PageEmittedEvents::DOMContentLoaded) end - @client.on_event 'Page.loadEventFired' do |event| - emit_event 'Events.Page.Load' + @client.on_event('Page.loadEventFired') do |event| + emit_event(PageEmittedEvents::Load) end # client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event)); # client.on('Runtime.bindingCalled', event => this._onBindingCalled(event)); - @client.on_event 'Page.javascriptDialogOpening' do |event| + @client.on_event('Page.javascriptDialogOpening') do |event| handle_dialog_opening(event) end # client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails)); # client.on('Inspector.targetCrashed', event => this._onTargetCrashed()); # client.on('Performance.metrics', event => this._emitMetrics(event)); - @client.on_event 'Log.entryAdded' do |event| + @client.on_event('Log.entryAdded') do |event| handle_log_entry_added(event) end - @client.on_event 'Page.fileChooserOpened' do |event| + @client.on_event('Page.fileChooserOpened') do |event| handle_file_chooser(event) end @target.is_closed_promise.then do - emit_event 'Events.Page.Close' + emit_event(PageEmittedEvents::Close) @closed = true end end @@ -128,43 +128,22 @@ def init ) end - EVENT_MAPPINGS = { - close: 'Events.Page.Close', - # console: 'Events.Page.Console', - dialog: 'Events.Page.Dialog', - domcontentloaded: 'Events.Page.DOMContentLoaded', - # error: - frameattached: 'Events.Page.FrameAttached', - framedetached: 'Events.Page.FrameDetached', - framenavigated: 'Events.Page.FrameNavigated', - load: 'Events.Page.Load', - # metrics: 'Events.Page.Metrics', - # pageerror: 'Events.Page.PageError', - popup: 'Events.Page.Popup', - request: 'Events.Page.Request', - requestfailed: 'Events.Page.RequestFailed', - requestfinished: 'Events.Page.RequestFinished', - response: 'Events.Page.Response', - # workercreated: 'Events.Page.WorkerCreated', - # workerdestroyed: 'Events.Page.WorkerDestroyed', - } - # @param event_name [Symbol] def on(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless PageEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}") end - add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end # @param event_name [Symbol] def once(event_name, &block) - unless EVENT_MAPPINGS.has_key?(event_name.to_sym) - raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}") + unless PageEmittedEvents.values.include?(event_name.to_s) + raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}") end - observe_first(EVENT_MAPPINGS[event_name.to_sym], &block) + super(event_name.to_s, &block) end def handle_file_chooser(event) @@ -238,7 +217,7 @@ def browser_context class TargetCrashedError < StandardError; end private def handle_target_crashed - emit_event 'error', TargetCrashedError.new('Page crashed!') + emit_event('error', TargetCrashedError.new('Page crashed!')) end private def handle_log_entry_added(event) @@ -259,7 +238,7 @@ class TargetCrashedError < StandardError; end url: url, line_number: line_number, ) - emit_event('Events.Page.Console', + emit_event(PageEmittedEvents::Console, Puppeteer::ConsoleMessage.new(level, text, [], console_message_location)) end end @@ -502,7 +481,7 @@ def user_agent=(user_agent) # * @param {!Protocol.Performance.metricsPayload} event # */ # _emitMetrics(event) { - # this.emit(Events.Page.Metrics, { + # this.emit(PageEmittedEvents::Metrics, { # title: event.title, # metrics: this._buildMetricsObject(event.metrics) # }); @@ -528,7 +507,7 @@ def user_agent=(user_agent) # const message = helper.getExceptionMessage(exceptionDetails); # const err = new Error(message); # err.stack = ''; // Don't report clientside error with a node stack attached - # this.emit(Events.Page.PageError, err); + # this.emit(PageEmittedEvents::PageError, err); # } # /** @@ -613,7 +592,7 @@ def user_agent=(user_agent) # * @param {Protocol.Runtime.StackTrace=} stackTrace # */ # _addConsoleMessage(type, args, stackTrace) { - # if (!this.listenerCount(Events.Page.Console)) { + # if (!this.listenerCount(PageEmittedEvents::Console)) { # args.forEach(arg => arg.dispose()); # return; # } @@ -631,7 +610,7 @@ def user_agent=(user_agent) # columnNumber: stackTrace.callFrames[0].columnNumber, # } : {}; # const message = new ConsoleMessage(type, textTokens.join(' '), args, location); - # this.emit(Events.Page.Console, message); + # this.emit(PageEmittedEvents::Console, message); # } private def handle_dialog_opening(event) @@ -643,7 +622,7 @@ def user_agent=(user_agent) type: dialog_type, message: event['message'], default_value: event['defaultPrompt']) - emit_event('Events.Page.Dialog', dialog) + emit_event(PageEmittedEvents::Dialog, dialog) end # @return [String] @@ -726,7 +705,7 @@ def reload(timeout: nil, wait_until: nil) private def session_close_promise @disconnect_promise ||= resolvable_future do |future| - @client.observe_first('Events.CDPSession.Disconnected') do + @client.observe_first(CDPSessionEmittedEvents::Disconnected) do future.reject(Puppeteer::CDPSession::Error.new('Target Closed')) end end @@ -746,7 +725,7 @@ def reload(timeout: nil, wait_until: nil) -> (request) { predicate.call(request) } end - wait_for_network_manager_event('Events.NetworkManager.Request', + wait_for_network_manager_event(NetworkManagerEmittedEvents::Request, predicate: request_predicate, timeout: timeout, ) @@ -780,7 +759,7 @@ def reload(timeout: nil, wait_until: nil) -> (response) { predicate.call(response) } end - wait_for_network_manager_event('Events.NetworkManager.Response', + wait_for_network_manager_event(NetworkManagerEmittedEvents::Response, predicate: response_predicate, timeout: timeout, ) diff --git a/lib/puppeteer/target.rb b/lib/puppeteer/target.rb index c95eeb0f..e1100ca3 100644 --- a/lib/puppeteer/target.rb +++ b/lib/puppeteer/target.rb @@ -68,10 +68,10 @@ def ignore_initialize_callback_promise if opener_page.nil? || type != 'page' return true end - # if (!openerPage.listenerCount(Events.Page.Popup)) + # if (!openerPage.listenerCount(PageEmittedEvents::Popup)) # return true; popup_page = page - opener_page.emit_event('Events.Page.Popup', popup_page) + opener_page.emit_event(PageEmittedEvents::Popup, popup_page) true end diff --git a/spec/integration/browser_context_spec.rb b/spec/integration/browser_context_spec.rb index ed3c8ccb..c0dbf072 100644 --- a/spec/integration/browser_context_spec.rb +++ b/spec/integration/browser_context_spec.rb @@ -139,7 +139,7 @@ pages = contexts.map.with_index do |context, index| context.new_page.tap do |page| page.goto('http://127.0.0.1:4567/isolation') - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { localStorage.setItem('name', 'page#{index}'); document.cookie = 'name=page#{index}'; diff --git a/spec/integration/click_spec.rb b/spec/integration/click_spec.rb index 05ef3951..748d4a64 100644 --- a/spec/integration/click_spec.rb +++ b/spec/integration/click_spec.rb @@ -198,7 +198,7 @@ page.click('textarea', click_count: 2) page.click('textarea', click_count: 3) - selected_text = page.evaluate <<~JAVASCRIPT + selected_text = page.evaluate(<<~JAVASCRIPT) () => { const textarea = document.querySelector('textarea'); return textarea.value.substring( @@ -490,7 +490,7 @@ context 'with double click listener' do before { - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { globalThis.double = false; const button = document.querySelector('button'); @@ -510,7 +510,7 @@ context 'even if the button is partially obscured' do before { - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { const button = document.querySelector('button'); button.textContent = 'Some really long text that will go offscreen'; diff --git a/spec/integration/keyboard_spec.rb b/spec/integration/keyboard_spec.rb index 2455656d..de44c6dd 100644 --- a/spec/integration/keyboard_spec.rb +++ b/spec/integration/keyboard_spec.rb @@ -3,7 +3,7 @@ RSpec.describe Puppeteer::Keyboard do context 'with textarea content' do before { - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { const textarea = document.createElement('textarea'); document.body.appendChild(textarea); @@ -36,7 +36,7 @@ context 'with key event listener content' do before { - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { window.keyPromise = new Promise((resolve) => document.addEventListener('keydown', (event) => resolve(event.key)) @@ -120,7 +120,7 @@ it 'should not type canceled events' do page.focus('textarea') - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { window.addEventListener( 'keydown', @@ -140,7 +140,7 @@ it_fails_firefox 'should specify repeat property' do page.focus('textarea') - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => document.querySelector('textarea').addEventListener('keydown', (e) => (globalThis.lastEvent = e), true) JAVASCRIPT @@ -167,7 +167,7 @@ end it_fails_firefox 'should specify location' do - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { window.addEventListener( 'keydown', @@ -387,7 +387,7 @@ context 'with keydown event listener' do before { - page.evaluate <<~JAVASCRIPT + page.evaluate(<<~JAVASCRIPT) () => { globalThis.result = null; document.addEventListener('keydown', (event) => { @@ -428,9 +428,9 @@ 5.times { press 'ArrowLeft' } up 'Shift' if Puppeteer.env.firefox? - press 'a' + press('a') else - send_character 'a' + send_character('a') end } expect(page.S('input').evaluate('(el) => el.value')).to eq('1234a') @@ -438,14 +438,14 @@ it 'can use press, send_text without block' do page.click('input') - page.keyboard.type_text '123456789' - page.keyboard.down 'Shift' - 5.times { page.keyboard.press 'ArrowLeft' } - page.keyboard.up 'Shift' + page.keyboard.type_text('123456789') + page.keyboard.down('Shift') + 5.times { page.keyboard.press('ArrowLeft') } + page.keyboard.up('Shift') if Puppeteer.env.firefox? - page.keyboard.press 'a' + page.keyboard.press('a') else - page.keyboard.send_character 'a' + page.keyboard.send_character('a') end expect(page.S('input').evaluate('(el) => el.value')).to eq('1234a') end diff --git a/spec/integration/wait_task_spec.rb b/spec/integration/wait_task_spec.rb index 3b7c8db7..1a2421e6 100644 --- a/spec/integration/wait_task_spec.rb +++ b/spec/integration/wait_task_spec.rb @@ -104,7 +104,7 @@ end it 'should work with multiline body' do - result = page.wait_for_function <<~JAVASCRIPT + result = page.wait_for_function(<<~JAVASCRIPT) () => true diff --git a/spec/puppeteer/event_callbackable_spec.rb b/spec/puppeteer/event_callbackable_spec.rb index 5a5086cc..1b3861a3 100644 --- a/spec/puppeteer/event_callbackable_spec.rb +++ b/spec/puppeteer/event_callbackable_spec.rb @@ -11,10 +11,10 @@ class Pub context 'with no parameter' do before do - pub.on_event 'Pub.Event.awesome' do + pub.on_event('Pub.Event.awesome') do sub.awesome end - pub.on_event 'Pub.Event.strange' do + pub.on_event('Pub.Event.strange') do sub.strange end end @@ -22,27 +22,27 @@ class Pub it 'receives callback' do expect(sub).to receive(:awesome) expect(sub).not_to receive(:strange) - pub.emit_event 'Pub.Event.awesome' - pub.emit_event 'Pub.Event.strange.strange' + pub.emit_event('Pub.Event.awesome') + pub.emit_event('Pub.Event.strange.strange') end end context 'with parameters' do before do - pub.on_event 'Pub.Event.awesome' do |arg1, arg2| + pub.on_event('Pub.Event.awesome') do |arg1, arg2| sub.awesome(arg1, arg2) end end it 'can receive arguments' do expect(sub).to receive(:awesome).with(:error, 'none') - pub.emit_event 'Pub.Event.awesome', :error, 'none' + pub.emit_event('Pub.Event.awesome', :error, 'none') end end context 'with keyword parameters' do before do - pub.on_event 'Pub.Event.awesome' do |error: nil| + pub.on_event('Pub.Event.awesome') do |error: nil| if error sub.on_error(error) else @@ -53,13 +53,13 @@ class Pub it 'can receive with keyword arguments' do expect(sub).to receive(:on_error).with('not awesome') - pub.emit_event 'Pub.Event.awesome', error: 'not awesome' + pub.emit_event('Pub.Event.awesome', error: 'not awesome') end it 'can omit optional keyword arguments' do expect(sub).not_to receive(:on_error) expect(sub).to receive(:awesome) - pub.emit_event 'Pub.Event.awesome' + pub.emit_event('Pub.Event.awesome') end end end @@ -74,7 +74,7 @@ class Pub context 'with no parameters' do class Sub0 def initialize(pub) - pub.on_event 'Pub.Event.awesome', &method(:handle_awesome) + pub.on_event('Pub.Event.awesome', &method(:handle_awesome)) end def handle_awesome @@ -88,14 +88,14 @@ def ok; end it 'receive callback with no arguments' do expect(sub).to receive(:ok) - pub.emit_event 'Pub.Event.awesome' + pub.emit_event('Pub.Event.awesome') end end context 'with parameters' do class Sub1 def initialize(pub) - pub.on_event 'Pub.Event.awesome', &method(:handle_awesome) + pub.on_event('Pub.Event.awesome', &method(:handle_awesome)) end def handle_awesome(arg1, arg2) @@ -109,14 +109,14 @@ def ok(arg1, arg2); end it 'receive callback with arguments' do expect(sub).to receive(:ok).with(:error, 'none') - pub.emit_event 'Pub.Event.awesome', :error, 'none' + pub.emit_event('Pub.Event.awesome', :error, 'none') end end context 'with keyword parameters' do class Sub2 def initialize(pub) - pub.on_event 'Pub.Event.awesome', &method(:handle_awesome) + pub.on_event('Pub.Event.awesome', &method(:handle_awesome)) end def handle_awesome(error: nil, reason: nil) @@ -132,7 +132,7 @@ def ok(arg1, arg2); end it 'receive callback with keyword arguments' do expect(sub).to receive(:ok).with(404, 'Not Found') - pub.emit_event 'Pub.Event.awesome', error: 404, reason: 'Not Found' + pub.emit_event('Pub.Event.awesome', error: 404, reason: 'Not Found') end end end @@ -147,13 +147,13 @@ class ChildPub def initialize(parent) @me = 'child' - parent.on_event 'Parent.awesome' do + parent.on_event('Parent.awesome') do on_parent_awesome @me = 'awesome child' - emit_event 'Child.awesome' + emit_event('Child.awesome') end - parent.on_event 'Child.awesome' do + parent.on_event('Child.awesome') do raise StandardError.new('invalid') end end @@ -169,15 +169,15 @@ def on_parent_awesome it 'receives callback' do expect(child).to receive(:on_parent_awesome) - expect { parent.emit_event 'Parent.awesome' }.to change { child.me }.from('child').to('awesome child') + expect { parent.emit_event('Parent.awesome') }.to change { child.me }.from('child').to('awesome child') end it 'can handle nested callback' do called = false - child.on_event 'Child.awesome' do + child.on_event('Child.awesome') do called = true end - expect { parent.emit_event 'Parent.awesome' }.to change { called }.from(false).to(true) + expect { parent.emit_event('Parent.awesome') }.to change { called }.from(false).to(true) end end @@ -195,7 +195,7 @@ class Pub it 'notify event callbacks for all listeners' do expect(sub1).to receive(:ok) expect(sub2).to receive(:yes) - pub.emit_event 'Pub.Event.awesome' + pub.emit_event('Pub.Event.awesome') end context 'after removing a listener' do @@ -206,7 +206,7 @@ class Pub it 'notify event callbacks only for listeners which keep listening' do expect(sub1).not_to receive(:ok) expect(sub2).to receive(:yes) - pub.emit_event 'Pub.Event.awesome' + pub.emit_event('Pub.Event.awesome') end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0937af7f..48141fba 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -53,7 +53,7 @@ def firefox? # Disable RSpec exposing methods globally on `Module` and `main` config.disable_monkey_patching! - config.expect_with :rspec do |c| + config.expect_with(:rspec) do |c| c.syntax = :expect end