diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bdc1cb4..87031eb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,9 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "nmatrix python" - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 + env: + TIMEOUT_SEC: 480 - run: rake build diff --git a/.github/workflows/nmatrix.yml b/.github/workflows/nmatrix.yml index 7b312c46..07937fa1 100644 --- a/.github/workflows/nmatrix.yml +++ b/.github/workflows/nmatrix.yml @@ -64,7 +64,9 @@ jobs: - run: bundle install --jobs 4 --retry 3 --without "numo python" - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 + env: + TIMEOUT_SEC: 480 - run: rake build diff --git a/.github/workflows/pycall.yml b/.github/workflows/pycall.yml index 5c50fe54..a0bd253e 100644 --- a/.github/workflows/pycall.yml +++ b/.github/workflows/pycall.yml @@ -83,7 +83,8 @@ jobs: - run: python -V - - run: bundle exec rake + - run: bundle exec rake VERBOSE=1 env: PYTHON: python + TIMEOUT_SEC: 480 continue-on-error: ${{ matrix.python == '2.x' }} diff --git a/Rakefile b/Rakefile index 4bb2425a..68699553 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,9 @@ require "rake/testtask" desc "Run tests" task :test do - ruby("test/run.rb") + verbose = "" + verbose = "-v" if ENV["VERBOSE"].to_i > 0 + ruby("test/run.rb #{verbose}".strip) end task default: :test diff --git a/lib/charty/backends/backend_helpers/playwright_manager.rb b/lib/charty/backends/backend_helpers/playwright_manager.rb new file mode 100644 index 00000000..edca3f02 --- /dev/null +++ b/lib/charty/backends/backend_helpers/playwright_manager.rb @@ -0,0 +1,63 @@ +module Charty + module Backends + module BackendHelpers + module PlaywrightManager + @_playwright_exec = nil + @_browser = nil + @_context = nil + + module_function def playwright + unless @_playwright_exec + load_playwright + path = ENV.fetch("PLAYWRIGHT_CLI_EXECUTABLE_PATH", "npx playwright") + @_playwright_exec = Playwright.create(playwright_cli_executable_path: path) + end + @_playwright_exec.playwright + end + + module_function def launch_browser + playwright.chromium.launch(headless: true) + end + + module_function def default_browser + unless @_browser + @_browser = launch_browser + end + @_browser + end + + module_function def default_context + unless @_context + @_context = default_browser.new_context + end + @_context + end + + module_function def new_page(&block) + page = default_context.new_page + return page unless block + + begin + return block.call(page) + ensure + page.close + end + end + + module_function def load_playwright + require "playwright" + rescue LoadError + $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer" + raise + end + + module_function def shutdown + @_playwright_exec.stop if @_playwright_exec + @_playwright_exec = nil + @_context = nil + @_browser = nil + end + end + end + end +end diff --git a/lib/charty/backends/plotly.rb b/lib/charty/backends/plotly.rb index 06875031..1ad98738 100644 --- a/lib/charty/backends/plotly.rb +++ b/lib/charty/backends/plotly.rb @@ -5,6 +5,7 @@ require_relative "plotly_helpers/html_renderer" require_relative "plotly_helpers/notebook_renderer" require_relative "plotly_helpers/plotly_renderer" +require_relative "backend_helpers/playwright_manager" module Charty module Backends @@ -918,60 +919,17 @@ def self.mathjax_config end end - @playwright_fiber = nil - - def self.ensure_playwright - if @playwright_fiber.nil? - begin - require "playwright" - rescue LoadError - $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer" - raise - end + def self.render_image(input, output, format, element_id, width, height) + BackendHelpers::PlaywrightManager.new_page do |page| + page.set_viewport_size(width: width, height: height) + page.goto("file://#{input}") + element = page.query_selector("\##{element_id}") - @playwright_fiber = Fiber.new do - playwright_cli_executable_path = ENV.fetch("PLAYWRIGHT_CLI_EXECUTABLE_PATH", "npx playwright") - Playwright.create(playwright_cli_executable_path: playwright_cli_executable_path) do |playwright| - playwright.chromium.launch(headless: true) do |browser| - request = Fiber.yield - loop do - result = nil - case request.shift - when :finish - break - when :render - input, output, format, element_id, width, height = request - - page = browser.new_page - page.set_viewport_size(width: width, height: height) - page.goto("file://#{input}") - element = page.query_selector("\##{element_id}") - - kwargs = {type: format} - kwargs[:path] = output unless output.nil? - result = element.screenshot(**kwargs) - end - request = Fiber.yield(result) - end - end - end - end - @playwright_fiber.resume + kwargs = {type: format} + kwargs[:path] = output unless output.nil? + element.screenshot(**kwargs) end end - - def self.terminate_playwright - return if @playwright_fiber.nil? - - @playwright_fiber.resume([:finish]) - end - - at_exit { terminate_playwright } - - def self.render_image(input, output, format, element_id, width, height) - ensure_playwright if @playwright_fiber.nil? - @playwright_fiber.resume([:render, input, output, format.to_s, element_id, width, height]) - end end end end diff --git a/test/run.rb b/test/run.rb index fa6a85c1..6cdeb9ee 100755 --- a/test/run.rb +++ b/test/run.rb @@ -4,6 +4,7 @@ # $VERBOSE = true require "pathname" +require "timeout" base_dir = Pathname(__dir__).parent.expand_path @@ -16,4 +17,11 @@ require_relative "helper" -exit(Test::Unit::AutoRunner.run(true, test_dir.to_s)) +run_test = lambda { Test::Unit::AutoRunner.run(true, test_dir.to_s) } +timeout_sec = ENV.fetch("TIMEOUT_SEC", "0").to_i +status = if timeout_sec > 0 + Timeout.timeout(timeout_sec) { run_test.() } + else + run_test.() + end +exit(status)