capybara-playwright-driver 0.1.2 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e6ff7fd5aaa4b41cc19395605ea19820f140703b1e52d7e2e07aaaa73f0428a
4
- data.tar.gz: d77b98b91bad49e4a115b2cc7c8238611f02389e882a444d065418aeea3c2ae2
3
+ metadata.gz: 2f43dbe09eba1cda75ed608f418120fbe5daebe99aa4bebde377ef120bd88d3f
4
+ data.tar.gz: 825d1aa7230177a37c7f6ce23ce656961084a2f13bfe8e5e36674836866a477e
5
5
  SHA512:
6
- metadata.gz: e3eafd55be3b31d780fe7f4f1c7f5c3afa35ead692a5ce8ea22e755c4cceab37d390bbcf875fad6ae355e5475e047dc4719bbf6ebfd7abaf04732d52e9ed7c60
7
- data.tar.gz: 7cf9a6db8a89ba6437e6790812924682c08bbf55bc182737159aea1883190313a86aeddf86a85219fba048ed884b93a0cfd868e97f74b25e171974f0c56ebabc
6
+ metadata.gz: 9f989b332d2d69bf84e3b270478514cee94a1ed3dc40c6868b8c61565248fa0d597e16f1575a42344bd13cbb4ecce8277956813d67df8b407351db72e684778d
7
+ data.tar.gz: df9dfa30c1f50fb1dc3c037b1b7445308e5301632ec6f8d16ba05f53b071f8a106355ae5d8d59b6885892c70bd7b2b713fe3a6d2f3c763ba528cd37c0c8ec899
@@ -26,7 +26,8 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.required_ruby_version = '>= 2.4'
28
28
  spec.add_dependency 'capybara'
29
- spec.add_dependency 'playwright-ruby-client', '>= 0.5.9'
29
+ spec.add_dependency 'playwright-ruby-client', '>= 0.8.0'
30
+ spec.add_development_dependency 'allure-rspec'
30
31
  spec.add_development_dependency 'bundler', '~> 2.2.3'
31
32
  spec.add_development_dependency 'launchy', '>= 2.0.4'
32
33
  spec.add_development_dependency 'pry-byebug'
@@ -1,16 +1,26 @@
1
+ require_relative './tmpdir_owner'
2
+
1
3
  module Capybara
2
4
  module Playwright
5
+ # Responsibility of this class is:
6
+ # - Handling Capybara::Driver commands.
7
+ # - Managing Playwright browser contexts and pages.
8
+ #
9
+ # Note that this class doesn't manage Playwright::Browser.
10
+ # We should not use Playwright::Browser#close in this class.
3
11
  class Browser
12
+ include TmpdirOwner
4
13
  extend Forwardable
5
14
 
6
15
  class NoSuchWindowError < StandardError ; end
7
16
 
8
- def initialize(playwright:, driver:, browser_type:, browser_options:, page_options:)
17
+ def initialize(driver:, playwright_browser:, page_options:, record_video: false)
9
18
  @driver = driver
10
-
11
- browser_type = playwright.send(browser_type)
12
- @playwright_browser = browser_type.launch(**browser_options)
19
+ @playwright_browser = playwright_browser
13
20
  @page_options = page_options
21
+ if record_video
22
+ @page_options[:record_video_dir] ||= tmpdir
23
+ end
14
24
  @playwright_page = create_page(create_browser_context)
15
25
  end
16
26
 
@@ -34,8 +44,8 @@ module Capybara
34
44
  end
35
45
  end
36
46
 
37
- def quit
38
- @playwright_browser.close
47
+ def clear_browser_contexts
48
+ @playwright_browser.contexts.each(&:close)
39
49
  end
40
50
 
41
51
  def current_url
@@ -155,6 +165,22 @@ module Capybara
155
165
  wrap_node(result)
156
166
  end
157
167
 
168
+ # Not used by Capybara::Session.
169
+ # Intended to be directly called by user.
170
+ def video_path
171
+ return nil if !@playwright_page || @playwright_page.closed?
172
+
173
+ @playwright_page.video&.path
174
+ end
175
+
176
+ # Not used by Capybara::Session.
177
+ # Intended to be directly called by user.
178
+ def raw_screenshot(**options)
179
+ return nil if !@playwright_page || @playwright_page.closed?
180
+
181
+ @playwright_page.screenshot(**options)
182
+ end
183
+
158
184
  def save_screenshot(path, **options)
159
185
  assert_page_alive
160
186
 
@@ -302,7 +328,24 @@ module Capybara
302
328
  when ::Playwright::ElementHandle
303
329
  Node.new(@driver, @playwright_page, arg)
304
330
  when ::Playwright::JSHandle
305
- arg.json_value
331
+ obj_type, is_array = arg.evaluate('obj => [typeof obj, Array.isArray(obj)]')
332
+ if obj_type == 'object'
333
+ if is_array
334
+ # Firefox often include 'toJSON' into properties.
335
+ # https://github.com/microsoft/playwright/issues/7015
336
+ #
337
+ # Get rid of non-numeric entries.
338
+ arg.properties.select { |key, _| key.to_i.to_s == key.to_s }.map do |_, value|
339
+ wrap_node(value)
340
+ end
341
+ else
342
+ arg.properties.map do |key, value|
343
+ [key, wrap_node(value)]
344
+ end.to_h
345
+ end
346
+ else
347
+ arg.json_value
348
+ end
306
349
  else
307
350
  arg
308
351
  end
@@ -310,7 +353,6 @@ module Capybara
310
353
 
311
354
  def with_playwright_page(&block)
312
355
  assert_page_alive
313
- raise ArgumentError.new('block must be given') unless block
314
356
 
315
357
  block.call(@playwright_page)
316
358
  end
@@ -0,0 +1,99 @@
1
+ module Capybara
2
+ module Playwright
3
+ # playwright-ruby-client provides 3 methods to launch/connect browser.
4
+ #
5
+ # Playwright.create do |playwright|
6
+ # playwright.chromium.launch do |browser|
7
+ #
8
+ # Playwright.connect_to_playwright_server do |playwright| ...
9
+ # playwright.chromium.launch do |browser|
10
+ #
11
+ # Playwright.connect_to_browser_server do |browser| ...
12
+ #
13
+ # This class provides start/stop methods for driver.
14
+ # This is responsible for
15
+ # - managing PlaywrightExecution
16
+ # - launching browser with given option if needed
17
+ class BrowserRunner
18
+ class PlaywrightConnectToPlaywrightServer
19
+ def initialize(endpoint_url, options)
20
+ @ws_endpoint = endpoint_url
21
+ @browser_type = options[:browser_type] || :chromium
22
+ unless %i(chromium firefox webkit).include?(@browser_type)
23
+ raise ArgumentError.new("Unknown browser_type: #{@browser_type}")
24
+ end
25
+ @browser_options = BrowserOptions.new(options)
26
+ end
27
+
28
+ def playwright_execution
29
+ @playwright_execution ||= ::Playwright.connect_to_playwright_server(@ws_endpoint)
30
+ end
31
+
32
+ def playwright_browser
33
+ browser_type = playwright_execution.playwright.send(@browser_type)
34
+ browser_options = @browser_options.value
35
+ browser_type.launch(**browser_options)
36
+ end
37
+ end
38
+
39
+ class PlaywrightConnectToBrowserServer
40
+ def initialize(endpoint_url)
41
+ @ws_endpoint = endpoint_url
42
+ end
43
+
44
+ def playwright_execution
45
+ @playwright_execution ||= ::Playwright.connect_to_browser_server(@ws_endpoint)
46
+ end
47
+
48
+ def playwright_browser
49
+ playwright_execution.browser
50
+ end
51
+ end
52
+
53
+ class PlaywrightCreate
54
+ def initialize(options)
55
+ @playwright_cli_executable_path = options[:playwright_cli_executable_path] || 'npx playwright'
56
+ @browser_type = options[:browser_type] || :chromium
57
+ unless %i(chromium firefox webkit).include?(@browser_type)
58
+ raise ArgumentError.new("Unknown browser_type: #{@browser_type}")
59
+ end
60
+ @browser_options = BrowserOptions.new(options)
61
+ end
62
+
63
+ def playwright_execution
64
+ @playwright_execution ||= ::Playwright.create(
65
+ playwright_cli_executable_path: @playwright_cli_executable_path,
66
+ )
67
+ end
68
+
69
+ def playwright_browser
70
+ browser_type = playwright_execution.playwright.send(@browser_type)
71
+ browser_options = @browser_options.value
72
+ browser_type.launch(**browser_options)
73
+ end
74
+ end
75
+
76
+ def initialize(options)
77
+ @runner =
78
+ if options[:playwright_server_endpoint_url]
79
+ PlaywrightConnectToPlaywrightServer.new(options[:playwright_server_endpoint_url], options)
80
+ elsif options[:browser_server_endpoint_url]
81
+ PlaywrightConnectToBrowserServer.new(options[:browser_server_endpoint_url])
82
+ else
83
+ PlaywrightCreate.new(options)
84
+ end
85
+ end
86
+
87
+ # @return [::Playwright::Browser]
88
+ def start
89
+ @playwright_execution = @runner.playwright_execution
90
+ @runner.playwright_browser
91
+ end
92
+
93
+ def stop
94
+ @playwright_execution&.stop
95
+ @playwright_execution = nil
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,27 +1,34 @@
1
+ require_relative './driver_extension'
2
+
1
3
  module Capybara
2
4
  module Playwright
3
5
  class Driver < ::Capybara::Driver::Base
4
6
  extend Forwardable
7
+ include DriverExtension
5
8
 
6
9
  def initialize(app, **options)
7
- @playwright_cli_executable_path = options[:playwright_cli_executable_path] || 'npx playwright'
8
- @browser_type = options[:browser_type] || :chromium
9
- unless %i(chromium firefox webkit).include?(@browser_type)
10
- raise ArgumentError.new("Unknown browser_type: #{@browser_type}")
11
- end
12
-
13
- @browser_options = BrowserOptions.new(options)
10
+ @browser_runner = BrowserRunner.new(options)
14
11
  @page_options = PageOptions.new(options)
15
12
  end
16
13
 
17
14
  def wait?; true; end
18
15
  def needs_server?; true; end
19
16
 
20
- def browser
21
- @browser ||= create_browser
17
+ private def browser
18
+ @browser ||= ::Capybara::Playwright::Browser.new(
19
+ driver: self,
20
+ playwright_browser: playwright_browser,
21
+ page_options: @page_options.value,
22
+ record_video: callback_on_save_screenrecord?,
23
+ )
24
+ end
25
+
26
+ private def playwright_browser
27
+ @playwright_browser ||= create_playwright_browser
22
28
  end
23
29
 
24
- private def create_browser
30
+ private def create_playwright_browser
31
+ # clean up @playwright_browser and @playwright_execution on exit.
25
32
  main = Process.pid
26
33
  at_exit do
27
34
  # Store the exit status of the test run since it goes away after calling the at_exit proc...
@@ -30,27 +37,36 @@ module Capybara
30
37
  exit @exit_status if @exit_status # Force exit with stored status
31
38
  end
32
39
 
33
- @execution = execute_playwright
34
- ::Capybara::Playwright::Browser.new(
35
- playwright: @execution.playwright,
36
- driver: self,
37
- browser_type: @browser_type,
38
- browser_options: @browser_options.value,
39
- page_options: @page_options.value,
40
- )
41
- end
42
-
43
- private def execute_playwright
44
- ::Playwright.create(playwright_cli_executable_path: @playwright_cli_executable_path)
40
+ @browser_runner.start
45
41
  end
46
42
 
47
43
  private def quit
48
- @browser&.quit
49
- @execution&.stop
44
+ @playwright_browser&.close
45
+ @playwright_browser = nil
46
+ @browser_runner.stop
50
47
  end
51
48
 
52
49
  def reset!
53
- quit
50
+ # screenshot is available only before closing page.
51
+ if callback_on_save_screenshot?
52
+ raw_screenshot = @browser&.raw_screenshot
53
+ if raw_screenshot
54
+ callback_on_save_screenshot(raw_screenshot)
55
+ end
56
+ end
57
+
58
+ # video path can be aquired only before closing context.
59
+ # video is completedly saved only after closing context.
60
+ video_path = @browser&.video_path
61
+
62
+ # [NOTE] @playwright_browser should keep alive for better performance.
63
+ # Only `Browser` is disposed.
64
+ @browser&.clear_browser_contexts
65
+
66
+ if video_path
67
+ callback_on_save_screenrecord(video_path)
68
+ end
69
+
54
70
  @browser = nil
55
71
  end
56
72
 
@@ -94,9 +110,6 @@ module Capybara
94
110
  def_delegator(:browser, :switch_to_window)
95
111
  def_delegator(:browser, :accept_modal)
96
112
  def_delegator(:browser, :dismiss_modal)
97
-
98
- # capybara-playwright-driver specific methods
99
- def_delegator(:browser, :with_playwright_page)
100
113
  end
101
114
  end
102
115
  end
@@ -0,0 +1,45 @@
1
+ module Capybara
2
+ module Playwright
3
+ module DriverExtension
4
+ # Register screenshot save process.
5
+ # The callback is called just before page is closed.
6
+ # (just before #reset_session!)
7
+ #
8
+ # The **binary** (String) of the page screenshot is called back into the given block
9
+ def on_save_raw_screenshot_before_reset(&block)
10
+ @callback_on_save_screenshot = block
11
+ end
12
+
13
+ private def callback_on_save_screenshot?
14
+ !!@callback_on_save_screenshot
15
+ end
16
+
17
+ private def callback_on_save_screenshot(raw_screenshot)
18
+ @callback_on_save_screenshot&.call(raw_screenshot)
19
+ end
20
+
21
+ # Register screenrecord save process.
22
+ # The callback is called just after page is closed.
23
+ # (just after #reset_session!)
24
+ #
25
+ # The video path (String) is called back into the given block
26
+ def on_save_screenrecord(&block)
27
+ @callback_on_save_screenrecord = block
28
+ end
29
+
30
+ private def callback_on_save_screenrecord?
31
+ !!@callback_on_save_screenrecord
32
+ end
33
+
34
+ private def callback_on_save_screenrecord(video_path)
35
+ @callback_on_save_screenrecord&.call(video_path)
36
+ end
37
+
38
+ def with_playwright_page(&block)
39
+ raise ArgumentError.new('block must be given') unless block
40
+
41
+ @browser&.with_playwright_page(&block)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ module Capybara
2
+ module Playwright
3
+ module TmpdirOwner
4
+ require 'tmpdir'
5
+
6
+ def tmpdir
7
+ return @tmpdir if @tmpdir
8
+
9
+ dir = Dir.mktmpdir
10
+ ObjectSpace.define_finalizer(self, TmpdirRemover.new(dir))
11
+ @tmpdir = dir
12
+ end
13
+
14
+ def remove_tmpdir
15
+ if @tmpdir
16
+ FileUtils.remove_entry(@tmpdir, true)
17
+ ObjectSpace.undefine_finalizer(self)
18
+ @tmpdir = nil
19
+ end
20
+ end
21
+
22
+ class TmpdirRemover
23
+ def initialize(tmpdir)
24
+ @pid = Process.pid
25
+ @tmpdir = tmpdir
26
+ end
27
+
28
+ def call(*args)
29
+ return if @pid != Process.pid
30
+
31
+ begin
32
+ FileUtils.remove_entry(@tmpdir, true)
33
+ rescue => err
34
+ $stderr.puts err
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Playwright
5
- VERSION = '0.1.2'
5
+ VERSION = '0.1.6'
6
6
  end
7
7
  end
@@ -4,6 +4,7 @@ require 'capybara'
4
4
  require 'playwright'
5
5
 
6
6
  require 'capybara/playwright/browser'
7
+ require 'capybara/playwright/browser_runner'
7
8
  require 'capybara/playwright/browser_options'
8
9
  require 'capybara/playwright/dialog_event_handler'
9
10
  require 'capybara/playwright/driver'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-playwright-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-02 00:00:00.000000000 Z
11
+ date: 2021-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -30,14 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.5.9
33
+ version: 0.8.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.5.9
40
+ version: 0.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: allure-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -170,11 +184,14 @@ files:
170
184
  - lib/capybara/playwright.rb
171
185
  - lib/capybara/playwright/browser.rb
172
186
  - lib/capybara/playwright/browser_options.rb
187
+ - lib/capybara/playwright/browser_runner.rb
173
188
  - lib/capybara/playwright/dialog_event_handler.rb
174
189
  - lib/capybara/playwright/driver.rb
190
+ - lib/capybara/playwright/driver_extension.rb
175
191
  - lib/capybara/playwright/node.rb
176
192
  - lib/capybara/playwright/page.rb
177
193
  - lib/capybara/playwright/page_options.rb
194
+ - lib/capybara/playwright/tmpdir_owner.rb
178
195
  - lib/capybara/playwright/version.rb
179
196
  homepage: https://github.com/YusukeIwaki/capybara-playwright-driver
180
197
  licenses: