my_pdfkit 0.1.0.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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/release-drafter.yml +19 -0
- data/.github/workflows/stale.yml +19 -0
- data/.github/workflows/test.yml +71 -0
- data/.gitignore +25 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +46 -0
- data/CHANGELOG.md +154 -0
- data/Gemfile +12 -0
- data/LICENSE +20 -0
- data/POST_INSTALL +14 -0
- data/README.md +190 -0
- data/Rakefile +24 -0
- data/lib/my_pdfkit/configuration.rb +89 -0
- data/lib/my_pdfkit/html_preprocessor.rb +25 -0
- data/lib/my_pdfkit/middleware.rb +117 -0
- data/lib/my_pdfkit/os.rb +21 -0
- data/lib/my_pdfkit/pdfkit.rb +153 -0
- data/lib/my_pdfkit/source.rb +52 -0
- data/lib/my_pdfkit/version.rb +5 -0
- data/lib/my_pdfkit/wkhtmltopdf.rb +82 -0
- data/lib/my_pdfkit.rb +10 -0
- data/my_pdfkit.gemspec +33 -0
- data/spec/configuration_spec.rb +171 -0
- data/spec/fixtures/example.css +1 -0
- data/spec/fixtures/example.html +5 -0
- data/spec/fixtures/example_with_hex_symbol.css +3 -0
- data/spec/html_preprocessor_spec.rb +71 -0
- data/spec/middleware_spec.rb +531 -0
- data/spec/os_spec.rb +67 -0
- data/spec/pdfkit_spec.rb +608 -0
- data/spec/source_spec.rb +125 -0
- data/spec/spec_helper.rb +33 -0
- metadata +175 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MyPDFKit::Configuration do
|
6
|
+
subject { MyPDFKit::Configuration.new }
|
7
|
+
describe "#wkhtmltopdf" do
|
8
|
+
context "when explicitly configured" do
|
9
|
+
it "uses configured value and don't detect" do
|
10
|
+
expect(subject).not_to receive(:default_wkhtmltopdf)
|
11
|
+
subject.wkhtmltopdf = "./Gemfile" # Need a file which exists
|
12
|
+
expect(subject.wkhtmltopdf).to eq("./Gemfile")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "falls back to detected binary if configured path doesn't exists" do
|
16
|
+
expect(subject).to receive(:default_wkhtmltopdf).twice.and_return("/bin/fallback")
|
17
|
+
expect(subject).to receive(:warn).with(/No executable found/)
|
18
|
+
subject.wkhtmltopdf = "./missing-file" # Need a file which doesn't exist
|
19
|
+
expect(subject.wkhtmltopdf).to eq("/bin/fallback")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when not explicitly configured" do
|
24
|
+
context "when running inside bundler" do
|
25
|
+
# Simulate the presence of bundler even if it's not here
|
26
|
+
before { stub_const("Bundler::GemfileError", Class) }
|
27
|
+
|
28
|
+
it "detects the existance of bundler" do
|
29
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
|
30
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "falls back if bundler path fails" do
|
34
|
+
# This happens when there is a wrong (buggy) version of bundler for example
|
35
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("")
|
36
|
+
expect(subject).to receive(:`).with('which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
|
37
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns last line of 'bundle exec which' output" do
|
41
|
+
# Happens when the user does not have a HOME directory on their system and runs bundler < 2
|
42
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return(<<~EOT
|
43
|
+
`/home/myuser` is not a directory.
|
44
|
+
Bundler will use `/tmp/bundler/home/myuser' as your home directory temporarily.
|
45
|
+
/usr/bin/wkhtmltopdf
|
46
|
+
EOT
|
47
|
+
)
|
48
|
+
expect(subject.wkhtmltopdf).to eq('/usr/bin/wkhtmltopdf')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when running without bundler" do
|
53
|
+
# Simulate the absence of bundler even if it's there
|
54
|
+
before { hide_const("Bundler::GemfileError") }
|
55
|
+
|
56
|
+
it "detects the existance of bundler" do
|
57
|
+
expect(subject).not_to receive(:`).with('bundle exec which wkhtmltopdf')
|
58
|
+
expect(subject).to receive(:`).with('which wkhtmltopdf').and_return('c:\windows\path.exe')
|
59
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#executable" do
|
66
|
+
it "returns wkhtmltopdf by default" do
|
67
|
+
expect(subject.executable).to eql subject.wkhtmltopdf
|
68
|
+
end
|
69
|
+
|
70
|
+
it "uses xvfb-run wrapper when option of using xvfb is configured" do
|
71
|
+
expect(subject).to receive(:using_xvfb?).and_return(true)
|
72
|
+
expect(subject.executable).to include 'xvfb-run'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#default_options" do
|
77
|
+
it "sets defaults for the command options" do
|
78
|
+
expect(subject.default_options[:disable_smart_shrinking]).to eql false
|
79
|
+
expect(subject.default_options[:quiet]).to eql true
|
80
|
+
expect(subject.default_options[:page_size]).to eql 'Letter'
|
81
|
+
expect(subject.default_options[:margin_top]).to eql '0.75in'
|
82
|
+
expect(subject.default_options[:margin_bottom]).to eql '0.75in'
|
83
|
+
expect(subject.default_options[:margin_right]).to eql '0.75in'
|
84
|
+
expect(subject.default_options[:margin_left]).to eql '0.75in'
|
85
|
+
expect(subject.default_options[:encoding]).to eql 'UTF-8'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "allows additional options to be configured" do
|
89
|
+
subject.default_options = { quiet: false, is_awesome: true }
|
90
|
+
expect(subject.default_options[:quiet]).to eql false
|
91
|
+
expect(subject.default_options[:is_awesome]).to eql true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "merges additional options with existing defaults" do
|
95
|
+
subject.default_options = { quiet: false, is_awesome: true }
|
96
|
+
expect(subject.default_options[:quiet]).to eql false
|
97
|
+
expect(subject.default_options[:is_awesome]).to eql true
|
98
|
+
expect(subject.default_options[:disable_smart_shrinking]).to eql false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#root_url" do
|
103
|
+
it "has no default" do
|
104
|
+
expect(subject.root_url).to be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it "is configurable" do
|
108
|
+
subject.root_url = 'https://arbitrary.base_url.for/middleware'
|
109
|
+
expect(subject.root_url).to eql 'https://arbitrary.base_url.for/middleware'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#meta_tag_prefix" do
|
114
|
+
it "defaults to 'pdfkit-'" do
|
115
|
+
expect(subject.meta_tag_prefix).to eql 'pdfkit-'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "is configurable" do
|
119
|
+
subject.meta_tag_prefix = 'aDifferentPrefix-'
|
120
|
+
expect(subject.meta_tag_prefix).to eql 'aDifferentPrefix-'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#using_xvfb?" do
|
125
|
+
it "can be configured to true" do
|
126
|
+
subject.use_xvfb = true
|
127
|
+
expect(subject.using_xvfb?).to eql true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "defaults to false" do
|
131
|
+
expect(subject.using_xvfb?).to eql false
|
132
|
+
end
|
133
|
+
|
134
|
+
it "can be configured to false" do
|
135
|
+
subject.use_xvfb = false
|
136
|
+
expect(subject.using_xvfb?).to eql false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#verbose?" do
|
141
|
+
it "can be configured to true" do
|
142
|
+
subject.verbose = true
|
143
|
+
expect(subject.verbose?).to eql true
|
144
|
+
end
|
145
|
+
|
146
|
+
it "defaults to false" do
|
147
|
+
expect(subject.verbose?).to eql false
|
148
|
+
end
|
149
|
+
|
150
|
+
it "can be configured to false" do
|
151
|
+
subject.verbose = false
|
152
|
+
expect(subject.verbose?).to eql false
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#quiet?" do
|
157
|
+
it "can be configured to true" do
|
158
|
+
subject.verbose = false
|
159
|
+
expect(subject.quiet?).to eql true
|
160
|
+
end
|
161
|
+
|
162
|
+
it "defaults to true" do
|
163
|
+
expect(subject.quiet?).to eql true
|
164
|
+
end
|
165
|
+
|
166
|
+
it "can be configured to false" do
|
167
|
+
subject.verbose = true
|
168
|
+
expect(subject.quiet?).to eql false
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
body { font-size: 20px; }
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MyPDFKit::HTMLPreprocessor do
|
6
|
+
describe "#process" do
|
7
|
+
let(:preprocessor) { MyPDFKit::HTMLPreprocessor }
|
8
|
+
let(:root_url) { 'http://example.com/' } # This mirrors Middleware#root_url's response
|
9
|
+
let(:protocol) { 'http' }
|
10
|
+
|
11
|
+
it "correctly parses host-relative url with single quotes" do
|
12
|
+
original_body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
|
13
|
+
body = preprocessor.process original_body, root_url, protocol
|
14
|
+
expect(body).to eq("<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.com/test.png\" /></body></html>")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "correctly parses host-relative url with double quotes" do
|
18
|
+
original_body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
|
19
|
+
body = preprocessor.process original_body, root_url, protocol
|
20
|
+
expect(body).to eq("<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "correctly parses protocol-relative url with single quotes" do
|
24
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>}
|
25
|
+
body = preprocessor.process original_body, root_url, protocol
|
26
|
+
expect(body).to eq("<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "correctly parses protocol-relative url with double quotes" do
|
30
|
+
original_body = %{<link href="//fonts.googleapis.com/css?family=Open+Sans:400,600" rel='stylesheet' type='text/css'>}
|
31
|
+
body = preprocessor.process original_body, root_url, protocol
|
32
|
+
expect(body).to eq("<link href=\"http://fonts.googleapis.com/css?family=Open+Sans:400,600\" rel='stylesheet' type='text/css'>")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "correctly parses multiple tags where first one is root url" do
|
36
|
+
original_body = %{<a href='/'><img src='/logo.jpg' ></a>}
|
37
|
+
body = preprocessor.process original_body, root_url, protocol
|
38
|
+
expect(body).to eq "<a href='http://example.com/'><img src='http://example.com/logo.jpg' ></a>"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns the body even if there are no valid substitutions found" do
|
42
|
+
original_body = "NO MATCH"
|
43
|
+
body = preprocessor.process original_body, root_url, protocol
|
44
|
+
expect(body).to eq("NO MATCH")
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when root_url is nil' do
|
48
|
+
it "returns the body safely, without interpolating" do
|
49
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
50
|
+
body = preprocessor.process original_body, nil, protocol
|
51
|
+
expect(body).to eq(%{<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when protocol is nil' do
|
56
|
+
it "returns the body safely, without interpolating" do
|
57
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
58
|
+
body = preprocessor.process original_body, root_url, nil
|
59
|
+
expect(body).to eq(%{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='http://example.com/'><img src='http://example.com/logo.jpg'></a>})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when root_url and protocol are both nil' do
|
64
|
+
it "returns the body safely, without interpolating" do
|
65
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
66
|
+
body = preprocessor.process original_body, nil, nil
|
67
|
+
expect(body).to eq original_body
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|