bidi2pdf-rails 0.0.1.pre.alpha → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/bidi2pdf-rails.iml +55 -9
  3. data/.rubocop.yml +14 -0
  4. data/CHANGELOG.md +33 -0
  5. data/README.md +117 -27
  6. data/Rakefile +2 -0
  7. data/cliff.toml +126 -0
  8. data/lib/bidi2pdf_rails/browser_console_log_subscriber.rb +24 -0
  9. data/lib/bidi2pdf_rails/chromedriver_manager_singleton.rb +11 -11
  10. data/lib/bidi2pdf_rails/config.rb +133 -0
  11. data/lib/bidi2pdf_rails/configurable.rb +106 -0
  12. data/lib/bidi2pdf_rails/main_log_subscriber.rb +33 -0
  13. data/lib/bidi2pdf_rails/network_log_subscriber.rb +20 -0
  14. data/lib/bidi2pdf_rails/railtie.rb +12 -45
  15. data/lib/bidi2pdf_rails/services/html_renderer.rb +33 -0
  16. data/lib/bidi2pdf_rails/services/html_to_pdf_converter.rb +28 -0
  17. data/lib/bidi2pdf_rails/services/pdf_browser_session.rb +39 -0
  18. data/lib/bidi2pdf_rails/services/pdf_renderer.rb +82 -0
  19. data/lib/bidi2pdf_rails/services/url_to_pdf_converter.rb +82 -0
  20. data/lib/bidi2pdf_rails/version.rb +1 -1
  21. data/lib/bidi2pdf_rails.rb +41 -58
  22. data/lib/generators/bidi2pdf_rails/USAGE +12 -4
  23. data/lib/generators/bidi2pdf_rails/initializer_generator.rb +136 -30
  24. data/lib/generators/bidi2pdf_rails/templates/bidi2pdf_rails.rb.tt +25 -79
  25. data/spec/acceptance/user_can_download_report_pdf_spec.rb +133 -0
  26. data/spec/acceptance/user_can_generate_pdf_from_protected_remote_url_spec.rb +173 -0
  27. data/spec/dummy/app/controllers/reports_controller.rb +37 -0
  28. data/spec/dummy/app/controllers/secure_controller.rb +52 -0
  29. data/spec/dummy/app/views/layouts/simple.html.erb +17 -0
  30. data/spec/dummy/app/views/secure/show.html.erb +10 -0
  31. data/spec/dummy/config/environments/production.rb +1 -1
  32. data/spec/dummy/config/initializers/bidi2pdf_rails.rb +68 -54
  33. data/spec/dummy/config/initializers/cors.rb +1 -1
  34. data/spec/dummy/config/routes.rb +10 -0
  35. data/spec/dummy/log/development.log +16567 -156
  36. data/spec/dummy/log/test.log +53046 -0
  37. data/spec/dummy/tmp/pids/server.pid +1 -1
  38. data/spec/integration/generators/bidi2pdf_rails/initializer_generator_spec.rb +64 -0
  39. data/spec/rails_helper.rb +8 -1
  40. data/spec/spec_helper.rb +47 -5
  41. data/spec/support/default_dirs_helper.rb +32 -0
  42. data/spec/support/pdf_helper.rb +12 -0
  43. data/spec/support/render_setting_helpers.rb +28 -0
  44. data/spec/support/request_server_bootstrap.rb +44 -0
  45. data/spec/{bidi2pdf_rails → unit/bidi2pdf_rails}/bidi2pdf_rails_spec.rb +1 -1
  46. data/spec/unit/bidi2pdf_rails/configurable/base_nested_config_spec.rb +133 -0
  47. data/tasks/changelog.rake +29 -0
  48. data/tasks/coverage.rake +23 -0
  49. metadata +95 -25
  50. data/lib/bidi2pdf_rails/log_subscriber.rb +0 -13
  51. data/spec/dummy/spec/helpers/reports_helper_spec.rb +0 -15
  52. data/spec/dummy/spec/requests/reports_spec.rb +0 -10
  53. data/spec/dummy/spec/views/reports/show.html.erb_spec.rb +0 -5
  54. data/spec/generator/bidie2pdf_rails_initializer_generator_spec.rb +0 -5
  55. data/spec/generator/initializer_generator_spec.rb +0 -5
  56. data/spec/requests/reports_spec.rb +0 -17
@@ -1,87 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bidi2pdf"
4
- require "bidi2pdf_rails/version"
5
- require "bidi2pdf_rails/railtie"
6
- require "bidi2pdf_rails/chromedriver_manager_singleton"
7
- require "bidi2pdf_rails/log_subscriber"
4
+ require "bidi2pdf/bidi/commands/print_parameters_validator"
5
+ require_relative "bidi2pdf_rails/version"
6
+ require_relative "bidi2pdf_rails/config"
7
+ require_relative "bidi2pdf_rails/railtie"
8
+ require_relative "bidi2pdf_rails/chromedriver_manager_singleton"
9
+ require_relative "bidi2pdf_rails/main_log_subscriber"
10
+ require_relative "bidi2pdf_rails/browser_console_log_subscriber"
11
+ require_relative "bidi2pdf_rails/network_log_subscriber"
8
12
 
9
13
  module Bidi2pdfRails
10
14
  class << self
11
- attr_accessor :logger, :notification_service, :verbosity, :default_timeout, :log_network_events, :log_browser_console, :remote_browser_url, :cookies,
12
- :headers, :auth, :headless, :chromedriver_port, :chrome_session_args,
13
- :proxy_addr, :proxy_port, :proxy_user, :proxy_pass, :install_dir,
14
- :viewport_width, :viewport_height,
15
- :pdf_margin_top, :pdf_margin_bottom, :pdf_margin_left, :pdf_margin_right,
16
- :pdf_scale, :pdf_print_background, :pdf_format, :pdf_orientation, :verbosity
15
+ def config
16
+ Config.instance
17
+ end
17
18
 
18
19
  # Allow configuration through a block
19
20
  def configure
20
- yield self if block_given?
21
+ yield config if block_given?
21
22
 
22
- apply_bidi2pdf_config
23
- end
23
+ config.validate_print_options!
24
24
 
25
- def apply_bidi2pdf_config
26
- # Allow configuration through a block
27
- Bidi2pdf.configure do |config|
28
- config.notification_service = notification_service
25
+ apply_bidi2pdf_config config
26
+ end
29
27
 
30
- config.logger = logger.tagged("bidi2pdf")
31
- config.default_timeout = default_timeout
28
+ def apply_bidi2pdf_config(config = Config.instance)
29
+ Bidi2pdf.configure do |bidi2pdf_config|
30
+ bidi2pdf_config.notification_service = config.general_options.notification_service_value
32
31
 
33
- if log_network_events
34
- config.network_events_logger = logger.tagged("bidi2pdf", "network")
35
- else
36
- config.network_events_logger = Logger.new(nil) # Disable network events logging
37
- end
32
+ bidi2pdf_config.logger = config.general_options.logger_value&.tagged("bidi2pdf")
33
+ bidi2pdf_config.default_timeout = config.general_options.default_timeout_value
38
34
 
39
- if log_browser_console
40
- config.browser_console_logger = logger.tagged("bidi2pdf", "browser_console")
41
- else
42
- config.browser_console_logger = Logger.new(nil) # Disable browser console logging
43
- end
35
+ bidi2pdf_config.network_events_logger = Logger.new(nil)
36
+ bidi2pdf_config.browser_console_logger = Logger.new(nil)
44
37
 
45
- config.enable_default_logging_subscriber = false
38
+ bidi2pdf_config.enable_default_logging_subscriber = false
46
39
  end
47
40
 
48
- Chromedriver::Binary.configure do |config|
49
- config.logger = logger
41
+ Chromedriver::Binary.configure do |chromedriver_config|
42
+ chromedriver_config.logger = config.general_options.logger_value&.tagged("bidi2pdf")
50
43
 
51
- config.proxy_addr = proxy_addr
52
- config.proxy_port = proxy_port
53
- config.proxy_user = proxy_user
54
- config.proxy_pass = proxy_pass
44
+ chromedriver_config.proxy_addr = config.proxy_settings.addr_value
45
+ chromedriver_config.proxy_port = config.proxy_settings.port_value
46
+ chromedriver_config.proxy_user = config.proxy_settings.user_value
47
+ chromedriver_config.proxy_pass = config.proxy_settings.pass_value
55
48
 
56
- config.install_dir = install_dir
49
+ chromedriver_config.install_dir = config.chromedriver_settings.install_dir_value
57
50
  end
58
51
  end
59
52
 
60
- def reset_to_defaults!
61
- @logger = nil
62
- @default_timeout = 10
63
- @log_network_events = false
64
- @log_browser_console = true
65
- @verbosity = 0
66
- @remote_browser_url = nil
67
- @cookies = {}
68
- @headers = {}
69
- @auth = nil
70
- @headless = !Rails.env.development?
71
- @chromedriver_port = 0
72
- @chrome_session_args = Bidi2pdf::Bidi::Session::DEFAULT_CHROME_ARGS
73
-
74
- @proxy_addr = nil
75
- @proxy_port = nil
76
- @proxy_user = nil
77
- @proxy_pass = nil
78
- @install_dir = nil
53
+ def use_local_chromedriver?
54
+ !use_remote_browser?
55
+ end
56
+
57
+ def use_remote_browser?
58
+ config.render_remote_settings.browser_url_value.present?
79
59
  end
80
60
 
81
61
  def logger
82
- @logger ||= Rails.logger # lazy load the logger, after it exists
62
+ config.general_options.logger_value&.tagged("bidi2pdf-rails")
83
63
  end
84
64
  end
85
65
 
86
- self.reset_to_defaults!
66
+ that = self
67
+ ActiveSupport.on_load(:action_controller_base, run_once: true) do
68
+ that.configure # apply the default configuration at load time
69
+ end
87
70
  end
@@ -1,8 +1,16 @@
1
1
  Description:
2
- Explain the generator
2
+ Generates a configuration file for Bidi2pdfRails in config/initializers/bidi2pdf_rails.rb
3
+ and adds development environment settings.
3
4
 
4
5
  Example:
5
- bin/rails generate initializer Thing
6
+ bin/rails generate bidi2pdf_rails:initializer
6
7
 
7
- This will create:
8
- what/will/it/create
8
+ # With options
9
+ bin/rails generate bidi2pdf_rails:initializer --quiet # Skip interactive prompts
10
+ bin/rails generate bidi2pdf_rails:initializer --force # Overwrite existing config
11
+
12
+ This will create:
13
+ config/initializers/bidi2pdf_rails.rb
14
+
15
+ And add settings to:
16
+ config/environments/development.rb
@@ -1,43 +1,72 @@
1
1
  module Bidi2pdfRails
2
2
  class InitializerGenerator < Rails::Generators::Base
3
3
  source_root File.expand_path("templates", __dir__)
4
- desc "Generates a config/initializers/bidi2pdf.rb config file"
5
4
 
6
- class_option :force, type: :boolean, default: false, desc: "Overwrite existing file"
7
- class_option :quiet, type: :boolean, default: false, desc: "Skip prompts"
8
-
9
- def ask_questions
10
- return if options[:quiet]
5
+ def self.infer_option_type(default)
6
+ case default
7
+ when true, false then :boolean
8
+ when Numeric then :numeric
9
+ when Hash then :hash
10
+ when Array then :array
11
+ when Proc then :string
12
+ else :string
13
+ end
14
+ end
11
15
 
12
- @log_network_events = yes?("Log network traffic? (y/n)", :green)
13
- @log_browser_console = yes?("Log browser console output? (y/n)", :green)
14
- @headless = yes?("Run Chrome in headless mode? (y/n)", :green)
15
- @proxy = yes?("Use a proxy server? (y/n)", :green)
16
+ def self.normalize_group(key)
17
+ key.to_s.sub(/(_settings|_options)$/, "")
18
+ end
16
19
 
17
- if @proxy
18
- @proxy_addr = ask("Proxy address (e.g., 127.0.0.1):", :yellow)
19
- @proxy_port = ask("Proxy port (e.g., 8080):", :yellow)
20
+ def self.with_group_config
21
+ that = self
22
+ Bidi2pdfRails::Config::CONFIG_OPTIONS.each_pair do |group_key, group_config|
23
+ group_prefix = that.normalize_group(group_key)
24
+ yield group_key, group_prefix, group_config
20
25
  end
26
+ end
21
27
 
22
- @configure_viewport = yes?("Configure custom viewport? (y/n)", :green)
23
- if @configure_viewport
24
- @viewport_width = ask("Viewport width (e.g., 1920):", :yellow)
25
- @viewport_height = ask("Viewport height (e.g., 1080):", :yellow)
28
+ def self.with_group_option
29
+ with_group_config do |group_key, group_prefix, group_config|
30
+ group_config[:options].each do |opt|
31
+ yield group_key, group_prefix, opt
32
+ end
26
33
  end
34
+ end
35
+
36
+ with_group_option do |_group_key, group_prefix, opt|
37
+ next unless opt[:ask]
38
+
39
+ name = "#{group_prefix}_#{opt[:name]}"
40
+ type = infer_option_type(opt[:default])
41
+ default = opt[:default_as_str] || opt[:default]
42
+
43
+ class_option name,
44
+ type: type,
45
+ desc: opt[:desc],
46
+ default: default,
47
+ enum: opt[:limited_to]
48
+ end
27
49
 
28
- @configure_pdf = yes?("Configure custom PDF settings? (y/n)", :green)
29
- if @configure_pdf
30
- @pdf_orientation = ask("PDF orientation (portrait/landscape):", :yellow)
31
- @pdf_margins = yes?("Configure PDF margins? (y/n)", :green)
32
- if @pdf_margins
33
- @pdf_margin_top = ask("PDF margin top (mm):", :yellow)
34
- @pdf_margin_bottom = ask("PDF margin bottom (mm):", :yellow)
35
- @pdf_margin_left = ask("PDF margin left (mm):", :yellow)
36
- @pdf_margin_right = ask("PDF margin right (mm):", :yellow)
50
+ def ask_questions
51
+ @answers = {}
52
+
53
+ return if options[:quiet]
54
+
55
+ self.class.with_group_config do |_group_key, group_prefix, group_config|
56
+ next unless group_config[:ask]
57
+ if group_config[:ask]
58
+ next unless yes?(group_config[:ask], :green)
59
+ end
60
+
61
+ group_config[:options].select { |opt| opt[:ask] }.each do |opt|
62
+ option_key = "#{group_prefix}_#{opt[:name]}".to_sym
63
+ next if cli_option_set?(option_key, opt)
64
+
65
+ @answers[option_key] = prompt_for_option(opt)
37
66
  end
38
- @pdf_print_background = yes?("Print background graphics? (y/n)", :green)
39
- @pdf_scale = ask("PDF scale (e.g., 1.0):", :yellow)
40
67
  end
68
+
69
+ @answers.compact!
41
70
  end
42
71
 
43
72
  def generate_config
@@ -48,9 +77,10 @@ module Bidi2pdfRails
48
77
 
49
78
  def inject_environment_config
50
79
  env_file = "config/environments/development.rb"
80
+ env_path = File.join(destination_root, env_file)
51
81
 
52
- if File.exist?(env_file)
53
- if File.read(env_file).include?("config.x.bidi2pdf_rails")
82
+ if File.exist?(env_path)
83
+ if File.read(env_path).include?("config.x.bidi2pdf_rails")
54
84
  say_status :skipped, "Bidi2PDF settings already present in #{env_file}", :yellow
55
85
  else
56
86
  content = <<~RUBY.gsub(/^(?=[\w#])/, " ")
@@ -69,5 +99,81 @@ module Bidi2pdfRails
69
99
  say_status :error, "Could not find #{env_file}", :red
70
100
  end
71
101
  end
102
+
103
+ no_commands do
104
+ def cli_option_set?(option_key, opt_def)
105
+ return false unless options.key?(option_key.to_s)
106
+
107
+ default = opt_def[:default_as_str] || opt_def[:default]
108
+ options[option_key.to_s].to_s != default.to_s
109
+ end
110
+
111
+ def prompt_for_option(opt)
112
+ type = self.class.infer_option_type(opt[:default])
113
+
114
+ if type == :boolean
115
+ question = opt[:desc].match?(/y\/n/i) ? opt[:desc] : "#{opt[:desc]} (y/n)?"
116
+ yes?(question, opt[:color])
117
+ else
118
+ opts = {
119
+ default: opt[:default_as_str] || opt[:default],
120
+ limited_to: opt[:limited_to],
121
+ echo: !opt[:secret]
122
+ }.compact
123
+
124
+ ask(opt[:desc], opt[:color], **opts)
125
+ end
126
+ end
127
+
128
+ def normalize_group(key)
129
+ self.class.normalize_group(key)
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def changed_by_user?(full_top_level_name, option_name)
136
+ top_level_name = normalize_group full_top_level_name
137
+
138
+ full_qual_option_name = "#{top_level_name}_#{option_name}".to_sym
139
+ return false unless options.key?(full_qual_option_name.to_s)
140
+
141
+ option_def = Bidi2pdfRails::Config::CONFIG_OPTIONS.dig(full_top_level_name.to_sym, :options).find { |opt| opt[:name] == option_name.to_sym }
142
+ default = option_def[:default_as_str] ? option_def[:default_as_str] : option_def[:default]
143
+
144
+ current_value = get_option_value(top_level_name, option_name)
145
+
146
+ return false if default.nil? && current_value.empty?
147
+ return true if default.nil? && current_value.present?
148
+
149
+ !current_value.to_s.match /#{Regexp.escape(default.to_s)}/
150
+ end
151
+
152
+ def get_option_value(top_level_name, option_name)
153
+ top_level_name = top_level_name.to_s.sub(/(_settings)|(_options)$/, "")
154
+ full_qual_option_name = "#{top_level_name}_#{option_name}".to_sym
155
+
156
+ result = if @answers.key?(full_qual_option_name)
157
+ @answers[full_qual_option_name]
158
+ elsif options.key?(full_qual_option_name.to_s)
159
+ options[full_qual_option_name.to_s]
160
+ else
161
+ nil
162
+ end
163
+
164
+ if result.is_a?(String)
165
+ if result.match(/(^\s+->\s+{)|(.*Rails\.)/) || numeric?(result)
166
+ return result
167
+ end
168
+ '"' + result + '"'
169
+ else
170
+ result
171
+ end
172
+ end
173
+
174
+ def numeric?(string)
175
+ # Float/Integer conversion with rescue catches most numeric formats
176
+ true if Float(string) rescue false
177
+ end
72
178
  end
73
179
  end
@@ -2,88 +2,34 @@
2
2
 
3
3
  Bidi2pdfRails.configure do |config|
4
4
  overrides = Rails.application.config.x.bidi2pdf_rails
5
-
6
- config.notification_service = ActiveSupport::Notifications
7
-
8
- config.logger = Rails.logger
9
- config.verbosity = overrides.verbosity.nil? ? :none : overrides.verbosity
10
- config.default_timeout = 10
11
-
12
- # Logging options
13
- config.log_network_events = <%= @log_network_events ? "true" : "false" %>
14
- config.log_browser_console = <%= @log_browser_console ? "true" : "false" %>
15
-
16
- # Chrome & BiDi
17
- # config.remote_browser_url = nil
18
- config.headless = overrides.headless.nil? ? <%= @headless ? "true" : "false" %> : overrides.headless
19
- # config.chromedriver_port = 0
20
- # config.chrome_session_args = [
21
- # "--disable-gpu",
22
- # "--no-sandbox"
23
- # ]
24
-
25
- <% if @proxy %>
26
- config.proxy_addr = "<%= @proxy_addr %>"
27
- config.proxy_port = <%= @proxy_port %>
28
- config.proxy_user = nil
29
- config.proxy_pass = nil
30
- <% else %>
31
- # config.proxy_addr = nil
32
- # config.proxy_port = nil
33
- # config.proxy_user = nil
34
- # config.proxy_pass = nil
35
- <% end %>
36
-
37
- <% if @configure_viewport %>
38
- # Viewport settings
39
- config.viewport_width = <%= @viewport_width || 1920 %>
40
- config.viewport_height = <%= @viewport_height || 1080 %>
41
- <% else %>
42
- # Viewport settings
43
- # config.viewport_width = 1920
44
- # config.viewport_height = 1080
45
- <% end %>
46
-
47
- <% if @configure_pdf %>
48
- # PDF settings
49
- config.pdf_orientation = "<%= @pdf_orientation || "portrait" %>"
50
- <% if @pdf_margins %>
51
- config.pdf_margin_top = <%= @pdf_margin_top || 10 %>
52
- config.pdf_margin_bottom = <%= @pdf_margin_bottom || 10 %>
53
- config.pdf_margin_left = <%= @pdf_margin_left || 10 %>
54
- config.pdf_margin_right = <%= @pdf_margin_right || 10 %>
55
- <% else %>
56
- # config.pdf_margin_top = 10
57
- # config.pdf_margin_bottom = 10
58
- # config.pdf_margin_left = 10
59
- # config.pdf_margin_right = 10
60
- <% end %>
61
- config.pdf_print_background = <%= @pdf_print_background ? "true" : "false" %>
62
- config.pdf_scale = <%= @pdf_scale || 1.0 %>
63
- <% else %>
64
- # PDF settings
65
- # config.pdf_orientation = "portrait"
66
- # config.pdf_margin_top = 10
67
- # config.pdf_margin_bottom = 10
68
- # config.pdf_margin_left = 10
69
- # config.pdf_margin_right = 10
70
- # config.pdf_print_background = true
71
- # config.pdf_scale = 1.0
5
+ <%
6
+ Bidi2pdfRails::Config::CONFIG_OPTIONS.each_pair do |top_level_option_name, top_level_option|
7
+ name = top_level_option[:name]
8
+ %>
9
+
10
+ #
11
+ # <%= name %>
12
+ #
13
+ <% top_level_option[:options].each do |option| %>
14
+ <% if option[:limited_to] %>
15
+ <%= "# Allowed values: #{option[:limited_to].map { |v| v.inspect }.join(", ")}" %>
16
+ <% end -%>
17
+ <% if changed_by_user?(top_level_option_name, option[:name]) -%>
18
+ <%= "config.#{top_level_option_name}.#{option[:name]} = #{get_option_value(top_level_option_name, option[:name]) } # #{option[:desc]}" -%>
19
+ <% else -%>
20
+ <%= "# config.#{top_level_option_name}.#{option[:name]} = #{option[:default_as_str] ? option[:default_as_str] : option[:default].inspect} # #{option[:desc]}" -%>
21
+ <% end -%>
22
+ <% end -%>
72
23
  <% end %>
24
+ end
73
25
 
74
- # config.cookies = [
75
- # { name: "session", value: "abc123", domain: "example.com" }
76
- # ]
26
+ Rails.application.config.after_initialize do
27
+ Bidi2pdfRails::MainLogSubscriber.attach_to "bidi2pdf", inherit_all: true # needed for imported methods
28
+ Bidi2pdfRails::MainLogSubscriber.attach_to "bidi2pdf_rails", inherit_all: true # needed for imported methods
77
29
 
78
- # config.headers = {
79
- # "X-API-KEY" => "topsecret"
80
- # }
30
+ Bidi2pdfRails::BrowserConsoleLogSubscriber.attach_to "bidi2pdf"
81
31
 
82
- # config.auth = {
83
- # username: "admin",
84
- # password: "secret"
85
- # }
32
+ Bidi2pdfRails::MainLogSubscriber.silence /network_event_.*\.bidi2pdf/
86
33
 
87
- # chromedriver install dir
88
- # config.install_dir = Rails.root.join("tmp", "bidi2pdf").to_s
34
+ Bidi2pdfRails::NetworkLogSubscriber.attach_to "bidi2pdf"
89
35
  end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_helper"
4
+ require "net/http"
5
+ require "rack/handler/puma"
6
+ require "socket"
7
+
8
+ RSpec.feature "As a devoloper, I want to generate PDF's with bidi2pdf-rails", :pdf, type: :request do
9
+ # This feature demonstrates how to use bidi2pdf-rails to generate PDFs
10
+ # from Rails views, remote URLs, and inline HTML. These specs double as
11
+ # living documentation for gem users.
12
+
13
+ before(:all) do
14
+ # Prepare the PDF rendering engine (chromium, etc.)
15
+ Bidi2pdfRails::ChromedriverManagerSingleton.initialize_manager force: true
16
+ end
17
+
18
+ after(:all) do
19
+ Bidi2pdfRails::ChromedriverManagerSingleton.shutdown
20
+ end
21
+
22
+ scenario "Rendering a controller view to PDF using layout: 'pdf'" do
23
+ # Controller example:
24
+ #
25
+ # def show
26
+ # respond_to do |format|
27
+ # format.html
28
+ # format.pdf { render pdf: 'my-report', layout: 'pdf' }
29
+ # end
30
+ # end
31
+
32
+ when_ "I visit the PDF version of a report" do
33
+ before do
34
+ @response = get_pdf_response "/reports/1.pdf"
35
+ end
36
+
37
+ then_ "I receive a successful HTTP response" do
38
+ expect(@response.code).to eq("200")
39
+ end
40
+
41
+ and_ "I receive a PDF file in response" do
42
+ expect(@response['Content-Type']).to eq("application/pdf")
43
+ end
44
+
45
+ and_ "the PDF contains the expected number of pages" do
46
+ expect(@response.body).to have_pdf_page_count(5)
47
+ end
48
+
49
+ and_ "the disposition header is set to attachment" do
50
+ expect(@response['Content-Disposition']).to start_with('inline; filename="my-report.pdf"')
51
+ end
52
+
53
+ and_ "the PDF contains the expected content" do
54
+ expect(@response.body).to contains_pdf_text("Section Two").at_page(2)
55
+ end
56
+ end
57
+ end
58
+
59
+ scenario "Converting a remote URL into a PDF with custom options" do
60
+ # Controller usage:
61
+ #
62
+ # def convert_remote_url
63
+ # render pdf: 'convert-remote-url', url: "http://example.com", wait_for_page_loaded: false, print_options: { page: { format: :A4 } }
64
+ # end
65
+
66
+ when_ "I visit the PDF version of a report" do
67
+ before do
68
+ @response = get_pdf_response "/convert-remote-url.pdf"
69
+ end
70
+
71
+ then_ "I receive a successful HTTP response" do
72
+ expect(@response.code).to eq("200")
73
+ end
74
+
75
+ and_ "I receive a PDF file in response" do
76
+ expect(@response['Content-Type']).to eq("application/pdf")
77
+ end
78
+
79
+ and_ "the PDF contains the expected number of pages" do
80
+ expect(@response.body).to have_pdf_page_count(1)
81
+ end
82
+
83
+ and_ "the disposition header is set to attachment" do
84
+ expect(@response['Content-Disposition']).to start_with('inline; filename="convert-remote-url.pdf"')
85
+ end
86
+ end
87
+ end
88
+
89
+ scenario "Rendering inline HTML directly to PDF" do
90
+ # Controller usage:
91
+ #
92
+ # def inline_html
93
+ # html = <<~HTML
94
+ # <html>
95
+ # <head>
96
+ # </head>
97
+ # <body>
98
+ # <h1>PDF Rendering Sample</h1>
99
+ # <p style="page-break-after: always;">Page break</p>
100
+ # <p>Content Page 2</p>
101
+ # </body>
102
+ # </html>
103
+ #
104
+ # render pdf: 'inline-html', inline: html, wait_for_page_loaded: false, print_options: { page: { format: :A4 } }
105
+ # end
106
+
107
+ when_ "I visit the PDF version of a report" do
108
+ before do
109
+ @response = get_pdf_response "/inline-html.pdf"
110
+ end
111
+
112
+ then_ "I receive a successful HTTP response" do
113
+ expect(@response.code).to eq("200")
114
+ end
115
+
116
+ and_ "I receive a PDF file in response" do
117
+ expect(@response['Content-Type']).to eq("application/pdf")
118
+ end
119
+
120
+ and_ "the PDF contains the expected number of pages" do
121
+ expect(@response.body).to have_pdf_page_count(2)
122
+ end
123
+
124
+ and_ "the disposition header is set to attachment" do
125
+ expect(@response['Content-Disposition']).to start_with('inline; filename="inline-html.pdf"')
126
+ end
127
+
128
+ and_ "the PDF contains the expected content" do
129
+ expect(@response.body).to contains_pdf_text("PDF Rendering Sample")
130
+ end
131
+ end
132
+ end
133
+ end