test: add integration tests

This commit is contained in:
Julien Neuhart
2025-03-21 11:18:20 +01:00
parent 820b914291
commit 0febb60a3f
139 changed files with 7561 additions and 16381 deletions

2
test/integration/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package integration contains everything related to integration testing.
package integration

View File

@@ -0,0 +1,852 @@
Feature: /forms/chromium/convert/html
Scenario: POST /forms/chromium/convert/html (Default)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/html (Single Page)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Page 12
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| singlePage | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
# page-break-after: always; tells the browser's print engine to force a page break after each element,
# even when calculating a large enough paper height, Chromium's PDF rendering will still honor those page break
# directives.
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/html (Landscape)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should NOT be set to landscape orientation
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| landscape | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should be set to landscape orientation
Scenario: POST /forms/chromium/convert/html (Native Page Ranges)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| nativePageRanges | 2-3 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/html (Header & Footer)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| files | testdata/header-footer-html/header.html | file |
| files | testdata/header-footer-html/footer.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 1:
"""
1 of 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
12 of 12
"""
Scenario: POST /forms/chromium/convert/html (Wait Delay)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| waitDelay | 2.5s | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/html (Wait For Expression)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| waitForExpression | window.globalVar === 'ready' | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/html (Emulated Media Type)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| emulatedMediaType | print | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| emulatedMediaType | screen | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Scenario: POST /forms/chromium/convert/html (Default Allow / Deny Lists)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should log the following entries:
| 'file:///etc/passwd' matches the expression from the denied list |
Scenario: POST /forms/chromium/convert/html (Main URL does NOT match allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^file:(?!//\\/tmp/).* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/html (Main URL does match denied list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | |
| CHROMIUM_DENY_LIST | ^file:///tmp.* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/html (Request does not match the allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^file:///tmp.* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should log the following entries:
| 'file:///etc/passwd' does not match the expression from the allowed list |
Scenario: POST /forms/chromium/convert/html (JavaScript Enabled)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/html (JavaScript Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_JAVASCRIPT | true |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/html (Fail On Resource HTTP Status Codes)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| failOnResourceHttpStatusCodes | [499,599] | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid HTTP status code from resources:
https://httpstat.us/400 - 400: Bad Request
"""
Scenario: POST /forms/chromium/convert/html (Fail On Resource Loading Failed)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| failOnResourceLoadingFailed | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium failed to load resources
"""
Then the response body should contain string:
"""
resource Stylesheet: net::ERR_CONNECTION_REFUSED
"""
Then the response body should contain string:
"""
resource Stylesheet: net::ERR_FILE_NOT_FOUND
"""
Scenario: POST /forms/chromium/convert/html (Fail On Console Exceptions)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/feature-rich-html/index.html | file |
| failOnConsoleExceptions | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium console exceptions
"""
Then the response body should contain string:
"""
exception "Uncaught" (61:12): Error: Exception 1
"""
Then the response body should contain string:
"""
exception "Uncaught" (65:12): Error: Exception 2
"""
Scenario: POST /forms/chromium/convert/html (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| singlePage | foo | field |
| paperWidth | foo | field |
| paperHeight | foo | field |
| marginTop | foo | field |
| marginBottom | foo | field |
| marginLeft | foo | field |
| marginRight | foo | field |
| preferCssPageSize | foo | field |
| generateDocumentOutline | foo | field |
| printBackground | foo | field |
| omitBackground | foo | field |
| landscape | foo | field |
| scale | foo | field |
| waitDelay | foo | field |
| emulatedMediaType | foo | field |
| failOnHttpStatusCodes | foo | field |
| failOnResourceHttpStatusCodes | foo | field |
| failOnResourceLoadingFailed | foo | field |
| failOnConsoleExceptions | foo | field |
| skipNetworkIdleEvent | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'skipNetworkIdleEvent' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnResourceHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceLoadingFailed' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnConsoleExceptions' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'waitDelay' is invalid (got 'foo', resulting to time: invalid duration "foo"); form field 'emulatedMediaType' is invalid (got 'foo', resulting to wrong value, expected either 'screen', 'print' or empty); form field 'omitBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'landscape' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'printBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'scale' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'singlePage' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'paperWidth' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'paperHeight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginTop' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginBottom' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginLeft' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginRight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'preferCssPageSize' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'generateDocumentOutline' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form file 'index.html' is required
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| omitBackground | true | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
omitBackground requires printBackground set to true
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| paperWidth | 0 | field |
| paperHeight | 0 | field |
| marginTop | 1000000 | field |
| marginBottom | 1000000 | field |
| marginLeft | 1000000 | field |
| marginRight | 1000000 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the provided settings; please check for aberrant form values
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| nativePageRanges | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the page ranges 'foo' (nativePageRanges)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| waitForExpression | undefined | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
The expression 'undefined' (waitForExpression) returned an exception or undefined
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| cookies | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got 'foo', resulting to unmarshal cookies: invalid character 'o' in literal false (expecting 'a'))
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| cookies | [{"name":"yummy_cookie","value":"choco"}] | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got '[{"name":"yummy_cookie","value":"choco"}]', resulting to cookie 0 must have its name, value and domain set)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| extraHttpHeaders | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got 'foo', resulting to unmarshal extraHttpHeaders: invalid character 'o' in literal false (expecting 'a'))
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| extraHttpHeaders | {"foo":"bar;scope;;"} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope;;"}', resulting to invalid scope '' for header 'foo')
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| extraHttpHeaders | {"foo":"bar;scope=*."} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope=*."}', resulting to invalid scope regex pattern for header 'foo': error parsing regexp: missing argument to repetition operator in `*.`)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| splitMode | foo | field |
| splitSpan | 2 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is invalid (got 'foo', resulting to wrong value, expected either 'intervals' or 'pages')
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| splitMode | intervals | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitSpan' is invalid (got 'foo', resulting to strconv.Atoi: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| splitMode | pages | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF split mode, while others may have failed to split due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/chromium/convert/html (Split Intervals)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-3-html/index.html | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/html (Split Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-3-html/index.html | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/html (Split Pages & Unify)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-3-html/index.html | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/html (Split Many PDFs - Lot of Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-12-html/index.html | file |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 12 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
| *_2.pdf |
| *_3.pdf |
| *_4.pdf |
| *_5.pdf |
| *_6.pdf |
| *_7.pdf |
| *_8.pdf |
| *_9.pdf |
| *_10.pdf |
| *_11.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_11.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_11.pdf" PDF should have the following content at page 1:
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/html (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/html (Split & PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/pages-3-html/index.html | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/html (Metadata)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/html (Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/html (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/html (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
Then the response status code should be 404
Scenario: POST /forms/chromium/convert/html (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| Gotenberg-Trace | forms_chromium_convert_html | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_chromium_convert_html"
Then the Gotenberg container should log the following entries:
| "trace":"forms_chromium_convert_html" |
Scenario: POST /forms/chromium/convert/html (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page-1-html/index.html","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
Then the response status code should be 200
Then the file request header "X-Foo" should be "bar"
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/chromium/convert/html (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/html (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
Then the response status code should be 401
Scenario: POST /foo/forms/chromium/convert/html (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/page-1-html/index.html | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,977 @@
Feature: /forms/chromium/convert/markdown
Scenario: POST /forms/chromium/convert/markdown (Default)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/markdown (Single Page)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| files | testdata/pages-12-markdown/page_3.md | file |
| files | testdata/pages-12-markdown/page_4.md | file |
| files | testdata/pages-12-markdown/page_5.md | file |
| files | testdata/pages-12-markdown/page_6.md | file |
| files | testdata/pages-12-markdown/page_7.md | file |
| files | testdata/pages-12-markdown/page_8.md | file |
| files | testdata/pages-12-markdown/page_9.md | file |
| files | testdata/pages-12-markdown/page_10.md | file |
| files | testdata/pages-12-markdown/page_11.md | file |
| files | testdata/pages-12-markdown/page_12.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Page 12
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| files | testdata/pages-12-markdown/page_3.md | file |
| files | testdata/pages-12-markdown/page_4.md | file |
| files | testdata/pages-12-markdown/page_5.md | file |
| files | testdata/pages-12-markdown/page_6.md | file |
| files | testdata/pages-12-markdown/page_7.md | file |
| files | testdata/pages-12-markdown/page_8.md | file |
| files | testdata/pages-12-markdown/page_9.md | file |
| files | testdata/pages-12-markdown/page_10.md | file |
| files | testdata/pages-12-markdown/page_11.md | file |
| files | testdata/pages-12-markdown/page_12.md | file |
| singlePage | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
# page-break-after: always; tells the browser's print engine to force a page break after each element,
# even when calculating a large enough paper height, Chromium's PDF rendering will still honor those page break
# directives.
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/markdown (Landscape)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should NOT be set to landscape orientation
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| landscape | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should be set to landscape orientation
Scenario: POST /forms/chromium/convert/markdown (Native Page Ranges)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| files | testdata/pages-12-markdown/page_3.md | file |
| files | testdata/pages-12-markdown/page_4.md | file |
| files | testdata/pages-12-markdown/page_5.md | file |
| files | testdata/pages-12-markdown/page_6.md | file |
| files | testdata/pages-12-markdown/page_7.md | file |
| files | testdata/pages-12-markdown/page_8.md | file |
| files | testdata/pages-12-markdown/page_9.md | file |
| files | testdata/pages-12-markdown/page_10.md | file |
| files | testdata/pages-12-markdown/page_11.md | file |
| files | testdata/pages-12-markdown/page_12.md | file |
| nativePageRanges | 2-3 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/markdown (Header & Footer)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| files | testdata/pages-12-markdown/page_3.md | file |
| files | testdata/pages-12-markdown/page_4.md | file |
| files | testdata/pages-12-markdown/page_5.md | file |
| files | testdata/pages-12-markdown/page_6.md | file |
| files | testdata/pages-12-markdown/page_7.md | file |
| files | testdata/pages-12-markdown/page_8.md | file |
| files | testdata/pages-12-markdown/page_9.md | file |
| files | testdata/pages-12-markdown/page_10.md | file |
| files | testdata/pages-12-markdown/page_11.md | file |
| files | testdata/pages-12-markdown/page_12.md | file |
| files | testdata/header-footer-html/header.html | file |
| files | testdata/header-footer-html/footer.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 1:
"""
1 of 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
12 of 12
"""
Scenario: POST /forms/chromium/convert/markdown (Wait Delay)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| waitDelay | 2.5s | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/markdown (Wait For Expression)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| waitForExpression | window.globalVar === 'ready' | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/markdown (Emulated Media Type)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| emulatedMediaType | print | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| emulatedMediaType | screen | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Scenario: POST /forms/chromium/convert/markdown (Default Allow / Deny Lists)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should log the following entries:
| 'file:///etc/passwd' matches the expression from the denied list |
Scenario: POST /forms/chromium/convert/markdown (Main URL does NOT match allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^file:(?!//\\/tmp/).* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/markdown (Main URL does match denied list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | |
| CHROMIUM_DENY_LIST | ^file:///tmp.* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/markdown (Request does not match the allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^file:///tmp.* |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should log the following entries:
| 'file:///etc/passwd' does not match the expression from the allowed list |
Scenario: POST /forms/chromium/convert/markdown (JavaScript Enabled)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/markdown (JavaScript Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_JAVASCRIPT | true |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/markdown (Fail On Resource HTTP Status Codes)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| failOnResourceHttpStatusCodes | [499,599] | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid HTTP status code from resources:
https://httpstat.us/400 - 400: Bad Request
"""
Scenario: POST /forms/chromium/convert/markdown (Fail On Resource Loading Failed)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| failOnResourceLoadingFailed | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium failed to load resources
"""
Then the response body should contain string:
"""
resource Stylesheet: net::ERR_CONNECTION_REFUSED
"""
Then the response body should contain string:
"""
resource Stylesheet: net::ERR_FILE_NOT_FOUND
"""
Scenario: POST /forms/chromium/convert/markdown (Fail On Console Exceptions)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/feature-rich-markdown/index.html | file |
| files | testdata/feature-rich-markdown/table.md | file |
| failOnConsoleExceptions | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium console exceptions
"""
Then the response body should contain string:
"""
exception "Uncaught" (93:12): Error: Exception 1
"""
Then the response body should contain string:
"""
exception "Uncaught" (97:12): Error: Exception 2
"""
Scenario: POST /forms/chromium/convert/markdown (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-3-markdown/index.html | file |
| files | testdata/pages-3-markdown/page_1.md | file |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Markdown file(s) not found: 'page_2.md'; 'page_3.md'
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| singlePage | foo | field |
| paperWidth | foo | field |
| paperHeight | foo | field |
| marginTop | foo | field |
| marginBottom | foo | field |
| marginLeft | foo | field |
| marginRight | foo | field |
| preferCssPageSize | foo | field |
| generateDocumentOutline | foo | field |
| printBackground | foo | field |
| omitBackground | foo | field |
| landscape | foo | field |
| scale | foo | field |
| waitDelay | foo | field |
| emulatedMediaType | foo | field |
| failOnHttpStatusCodes | foo | field |
| failOnResourceHttpStatusCodes | foo | field |
| failOnResourceLoadingFailed | foo | field |
| failOnConsoleExceptions | foo | field |
| skipNetworkIdleEvent | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'skipNetworkIdleEvent' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnResourceHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceLoadingFailed' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnConsoleExceptions' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'waitDelay' is invalid (got 'foo', resulting to time: invalid duration "foo"); form field 'emulatedMediaType' is invalid (got 'foo', resulting to wrong value, expected either 'screen', 'print' or empty); form field 'omitBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'landscape' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'printBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'scale' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'singlePage' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'paperWidth' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'paperHeight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginTop' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginBottom' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginLeft' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginRight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'preferCssPageSize' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'generateDocumentOutline' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form file 'index.html' is required; no form file found for extensions: [.md]
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| omitBackground | true | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
omitBackground requires printBackground set to true
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| paperWidth | 0 | field |
| paperHeight | 0 | field |
| marginTop | 1000000 | field |
| marginBottom | 1000000 | field |
| marginLeft | 1000000 | field |
| marginRight | 1000000 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the provided settings; please check for aberrant form values
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| nativePageRanges | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the page ranges 'foo' (nativePageRanges)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| waitForExpression | undefined | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
The expression 'undefined' (waitForExpression) returned an exception or undefined
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| cookies | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got 'foo', resulting to unmarshal cookies: invalid character 'o' in literal false (expecting 'a'))
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| cookies | [{"name":"yummy_cookie","value":"choco"}] | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got '[{"name":"yummy_cookie","value":"choco"}]', resulting to cookie 0 must have its name, value and domain set)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| extraHttpHeaders | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got 'foo', resulting to unmarshal extraHttpHeaders: invalid character 'o' in literal false (expecting 'a'))
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| extraHttpHeaders | {"foo":"bar;scope;;"} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope;;"}', resulting to invalid scope '' for header 'foo')
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| extraHttpHeaders | {"foo":"bar;scope=*."} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope=*."}', resulting to invalid scope regex pattern for header 'foo': error parsing regexp: missing argument to repetition operator in `*.`)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| splitMode | foo | field |
| splitSpan | 2 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is invalid (got 'foo', resulting to wrong value, expected either 'intervals' or 'pages')
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| splitMode | intervals | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitSpan' is invalid (got 'foo', resulting to strconv.Atoi: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| splitMode | pages | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF split mode, while others may have failed to split due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/chromium/convert/markdown (Split Intervals)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-3-markdown/index.html | file |
| files | testdata/pages-3-markdown/page_1.md | file |
| files | testdata/pages-3-markdown/page_2.md | file |
| files | testdata/pages-3-markdown/page_3.md | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/markdown (Split Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-3-markdown/index.html | file |
| files | testdata/pages-3-markdown/page_1.md | file |
| files | testdata/pages-3-markdown/page_2.md | file |
| files | testdata/pages-3-markdown/page_3.md | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/markdown (Split Pages & Unify)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-3-markdown/index.html | file |
| files | testdata/pages-3-markdown/page_1.md | file |
| files | testdata/pages-3-markdown/page_2.md | file |
| files | testdata/pages-3-markdown/page_3.md | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/markdown (Split Many PDFs - Lot of Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-12-markdown/index.html | file |
| files | testdata/pages-12-markdown/page_1.md | file |
| files | testdata/pages-12-markdown/page_2.md | file |
| files | testdata/pages-12-markdown/page_3.md | file |
| files | testdata/pages-12-markdown/page_4.md | file |
| files | testdata/pages-12-markdown/page_5.md | file |
| files | testdata/pages-12-markdown/page_6.md | file |
| files | testdata/pages-12-markdown/page_7.md | file |
| files | testdata/pages-12-markdown/page_8.md | file |
| files | testdata/pages-12-markdown/page_9.md | file |
| files | testdata/pages-12-markdown/page_10.md | file |
| files | testdata/pages-12-markdown/page_11.md | file |
| files | testdata/pages-12-markdown/page_12.md | file |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 12 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
| *_2.pdf |
| *_3.pdf |
| *_4.pdf |
| *_5.pdf |
| *_6.pdf |
| *_7.pdf |
| *_8.pdf |
| *_9.pdf |
| *_10.pdf |
| *_11.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_11.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_11.pdf" PDF should have the following content at page 1:
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/markdown (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/markdown (Split & PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/pages-3-markdown/index.html | file |
| files | testdata/pages-3-markdown/page_1.md | file |
| files | testdata/pages-3-markdown/page_2.md | file |
| files | testdata/pages-3-markdown/page_3.md | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/markdown (Metadata)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/markdown (Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/markdown (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/markdown (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
Then the response status code should be 404
Scenario: POST /forms/chromium/convert/markdown (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| Gotenberg-Trace | forms_chromium_convert_html | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_chromium_convert_html"
Then the Gotenberg container should log the following entries:
| "trace":"forms_chromium_convert_html" |
Scenario: POST /forms/chromium/convert/markdown (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page-1-markdown/index.html","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| files | testdata/page-1-markdown/page_1.md | file |
Then the response status code should be 200
Then the file request header "X-Foo" should be "bar"
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/chromium/convert/markdown (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/markdown (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
Then the response status code should be 401
Scenario: POST /foo/forms/chromium/convert/markdown (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/chromium/convert/markdown" endpoint with the following form data and header(s):
| files | testdata/page-1-markdown/index.html | file |
| files | testdata/page-1-markdown/page_1.md | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,929 @@
Feature: /forms/chromium/convert/url
Scenario: POST /forms/chromium/convert/url (Default)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/url (Single Page)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Page 12
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| singlePage | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
# page-break-after: always; tells the browser's print engine to force a page break after each element,
# even when calculating a large enough paper height, Chromium's PDF rendering will still honor those page break
# directives.
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/url (Landscape)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should NOT be set to landscape orientation
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| landscape | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should be set to landscape orientation
Scenario: POST /forms/chromium/convert/url (Native Page Ranges)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| nativePageRanges | 2-3 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/url (Header & Footer)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| files | testdata/header-footer-html/header.html | file |
| files | testdata/header-footer-html/footer.html | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 12 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 1:
"""
1 of 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
Pages 12
"""
Then the "foo.pdf" PDF should have the following content at page 12:
"""
12 of 12
"""
Scenario: POST /forms/chromium/convert/url (Custom HTTP Headers)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| userAgent | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) | field |
| extraHttpHeaders | {"X-Header":"foo","X-Scoped-Header-1":"bar;scope=https?:\\/\\/([a-zA-Z0-9-]+\\\\.)*domain\\\\.com\\/.*","X-Scoped-Header-2":"baz;scope=https?:\\/\\/([a-zA-Z0-9-]+\\\\.)*docker\\\\.internal:(\\\\d+)\\/.*"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the server request header "User-Agent" should be "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)"
Then the server request header "X-Header" should be "foo"
Then the server request header "X-Scoped-Header-1" should be ""
Then the server request header "X-Scoped-Header-2" should be "baz"
Scenario: POST /forms/chromium/convert/url (Cookies)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| cookies | [{"name":"cookie_1","value":"foo","domain":"host.docker.internal:%d"},{"name":"cookie_2","value":"bar","domain":"domain.com"}] | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the server request cookie "cookie_1" should be "foo"
Then the server request cookie "cookie_2" should be ""
Scenario: POST /forms/chromium/convert/url (Wait Delay)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| waitDelay | 2.5s | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/url (Wait For Expression)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| waitForExpression | window.globalVar === 'ready' | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Wait delay > 2 seconds or expression window globalVar === 'ready' returns true.
"""
Scenario: POST /forms/chromium/convert/url (Emulated Media Type)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| emulatedMediaType | print | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| emulatedMediaType | screen | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Emulated media type is 'screen'.
"""
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
Emulated media type is 'print'.
"""
Scenario: POST /forms/chromium/convert/url (Default Allow / Deny Lists)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should NOT log the following entries:
# Modern browsers block file URIs from being loaded into iframes when the parent page is served over HTTP/HTTPS.
| 'file:///etc/passwd' matches the expression from the denied list |
Scenario: POST /forms/chromium/convert/url (Main URL does NOT match allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^file:(?!//\\/tmp/).* |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/url (Main URL does match denied list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | |
| CHROMIUM_DENY_LIST | ^http.* |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
Then the response status code should be 403
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Forbidden
"""
Scenario: POST /forms/chromium/convert/url (Request does not match the allowed list)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_ALLOW_LIST | ^.* |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the Gotenberg container should NOT log the following entries:
# Modern browsers block file URIs from being loaded into iframes when the parent page is served over HTTP/HTTPS.
| 'file:///etc/passwd' does not match the expression from the allowed list |
Scenario: POST /forms/chromium/convert/url (JavaScript Enabled)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/url (JavaScript Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_JAVASCRIPT | true |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should NOT have the following content at page 1:
"""
JavaScript is enabled.
"""
Scenario: POST /forms/chromium/convert/url (Fail On Resource HTTP Status Codes)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| failOnResourceHttpStatusCodes | [499,599] | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Invalid HTTP status code from resources:
"""
Then the response body should contain string:
"""
/favicon.ico - 404: Not Found
"""
Scenario: POST /forms/chromium/convert/url (Fail On Resource Loading Failed)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| failOnResourceLoadingFailed | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium failed to load resources
"""
Then the response body should contain string:
"""
resource Stylesheet: net::ERR_CONNECTION_REFUSED
"""
Scenario: POST /forms/chromium/convert/url (Fail On Console Exceptions)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/feature-rich-html-remote/index.html | field |
| failOnConsoleExceptions | true | field |
Then the response status code should be 409
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should contain string:
"""
Chromium console exceptions
"""
Then the response body should contain string:
"""
exception "Uncaught" (56:12): Error: Exception 1
"""
Then the response body should contain string:
"""
exception "Uncaught" (60:12): Error: Exception 2
"""
Scenario: POST /forms/chromium/convert/url (Bad Request)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| singlePage | foo | field |
| paperWidth | foo | field |
| paperHeight | foo | field |
| marginTop | foo | field |
| marginBottom | foo | field |
| marginLeft | foo | field |
| marginRight | foo | field |
| preferCssPageSize | foo | field |
| generateDocumentOutline | foo | field |
| printBackground | foo | field |
| omitBackground | foo | field |
| landscape | foo | field |
| scale | foo | field |
| waitDelay | foo | field |
| emulatedMediaType | foo | field |
| failOnHttpStatusCodes | foo | field |
| failOnResourceHttpStatusCodes | foo | field |
| failOnResourceLoadingFailed | foo | field |
| failOnConsoleExceptions | foo | field |
| skipNetworkIdleEvent | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'skipNetworkIdleEvent' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceHttpStatusCodes' is invalid (got 'foo', resulting to unmarshal failOnResourceHttpStatusCodes: invalid character 'o' in literal false (expecting 'a')); form field 'failOnResourceLoadingFailed' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'failOnConsoleExceptions' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'waitDelay' is invalid (got 'foo', resulting to time: invalid duration "foo"); form field 'emulatedMediaType' is invalid (got 'foo', resulting to wrong value, expected either 'screen', 'print' or empty); form field 'omitBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'landscape' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'printBackground' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'scale' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'singlePage' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'paperWidth' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'paperHeight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginTop' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginBottom' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginLeft' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'marginRight' is invalid (got 'foo', resulting to strconv.ParseFloat: parsing "foo": invalid syntax); form field 'preferCssPageSize' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'generateDocumentOutline' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'url' is required
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| omitBackground | true | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
omitBackground requires printBackground set to true
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| paperWidth | 0 | field |
| paperHeight | 0 | field |
| marginTop | 1000000 | field |
| marginBottom | 1000000 | field |
| marginLeft | 1000000 | field |
| marginRight | 1000000 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the provided settings; please check for aberrant form values
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| nativePageRanges | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Chromium does not handle the page ranges 'foo' (nativePageRanges)
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| waitForExpression | undefined | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
The expression 'undefined' (waitForExpression) returned an exception or undefined
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| cookies | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got 'foo', resulting to unmarshal cookies: invalid character 'o' in literal false (expecting 'a'))
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| cookies | [{"name":"yummy_cookie","value":"choco"}] | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'cookies' is invalid (got '[{"name":"yummy_cookie","value":"choco"}]', resulting to cookie 0 must have its name, value and domain set)
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| extraHttpHeaders | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got 'foo', resulting to unmarshal extraHttpHeaders: invalid character 'o' in literal false (expecting 'a'))
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| extraHttpHeaders | {"foo":"bar;scope;;"} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope;;"}', resulting to invalid scope '' for header 'foo')
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| extraHttpHeaders | {"foo":"bar;scope=*."} | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'extraHttpHeaders' is invalid (got '{"foo":"bar;scope=*."}', resulting to invalid scope regex pattern for header 'foo': error parsing regexp: missing argument to repetition operator in `*.`)
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| splitMode | foo | field |
| splitSpan | 2 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is invalid (got 'foo', resulting to wrong value, expected either 'intervals' or 'pages')
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| splitMode | intervals | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitSpan' is invalid (got 'foo', resulting to strconv.Atoi: parsing "foo": invalid syntax)
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| splitMode | pages | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF split mode, while others may have failed to split due to different issues
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/chromium/convert/url (Split Intervals)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-3-html/index.html | field |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/url (Split Pages)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-3-html/index.html | field |
| splitMode | pages | field |
| splitSpan | 2- | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/url (Split Pages & Unify)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-3-html/index.html | field |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/chromium/convert/url (Split Many PDFs - Lot of Pages)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-12-html/index.html | field |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 12 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
| *_2.pdf |
| *_3.pdf |
| *_4.pdf |
| *_5.pdf |
| *_6.pdf |
| *_7.pdf |
| *_8.pdf |
| *_9.pdf |
| *_10.pdf |
| *_11.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_11.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_11.pdf" PDF should have the following content at page 1:
"""
Page 12
"""
Scenario: POST /forms/chromium/convert/url (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/url (Split & PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/pages-3-html/index.html | field |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 2 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/chromium/convert/url (Metadata)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/url (Flatten)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/chromium/convert/url (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/chromium/convert/url (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| CHROMIUM_DISABLE_ROUTES | true |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
Then the response status code should be 404
Scenario: POST /forms/chromium/convert/url (Gotenberg Trace)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| Gotenberg-Trace | forms_chromium_convert_url | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_chromium_convert_url"
Then the Gotenberg container should log the following entries:
| "trace":"forms_chromium_convert_url" |
Scenario: POST /forms/chromium/convert/url (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/chromium/convert/url (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
Then the response status code should be 401
Scenario: POST /foo/forms/chromium/convert/url (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
Given I have a static server
When I make a "POST" request to Gotenberg at the "/foo/forms/chromium/convert/url" endpoint with the following form data and header(s):
| url | http://host.docker.internal:%d/html/testdata/page-1-html/index.html | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,147 @@
Feature: /debug
Scenario: GET /debug (Disabled)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/debug" endpoint
Then the response status code should be 404
Scenario: GET /debug (Enabled)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
When I make a "GET" request to Gotenberg at the "/debug" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"version": "{version}",
"architecture": "ignore",
"modules": [
"api",
"chromium",
"exiftool",
"libreoffice",
"libreoffice-api",
"libreoffice-pdfengine",
"logging",
"pdfcpu",
"pdfengines",
"pdftk",
"prometheus",
"qpdf",
"webhook"
],
"modules_additional_data": {
"chromium": {
"version": "ignore"
},
"exiftool": {
"version": "ignore"
},
"libreoffice-api": {
"version": "ignore"
},
"pdfcpu": {
"version": "ignore"
},
"pdftk": {
"version": "ignore"
},
"qpdf": {
"version": "ignore"
}
},
"flags": {
"api-bind-ip": "",
"api-body-limit": "",
"api-disable-download-from": "false",
"api-disable-health-check-logging": "false",
"api-download-from-allow-list": "",
"api-download-from-deny-list": "",
"api-download-from-max-retry": "4",
"api-enable-basic-auth": "false",
"api-enable-debug-route": "true",
"api-port": "3000",
"api-port-from-env": "",
"api-root-path": "/",
"api-start-timeout": "30s",
"api-timeout": "30s",
"api-tls-cert-file": "",
"api-tls-key-file": "",
"api-trace-header": "Gotenberg-Trace",
"chromium-allow-file-access-from-files": "false",
"chromium-allow-insecure-localhost": "false",
"chromium-allow-list": "",
"chromium-auto-start": "false",
"chromium-clear-cache": "false",
"chromium-clear-cookies": "false",
"chromium-deny-list": "^file:(?!//\\/tmp/).*",
"chromium-disable-javascript": "false",
"chromium-disable-routes": "false",
"chromium-disable-web-security": "false",
"chromium-host-resolver-rules": "",
"chromium-ignore-certificate-errors": "false",
"chromium-incognito": "false",
"chromium-max-queue-size": "0",
"chromium-proxy-server": "",
"chromium-restart-after": "10",
"chromium-start-timeout": "20s",
"gotenberg-graceful-shutdown-duration": "30s",
"libreoffice-auto-start": "false",
"libreoffice-disable-routes": "false",
"libreoffice-max-queue-size": "0",
"libreoffice-restart-after": "10",
"libreoffice-start-timeout": "20s",
"log-fields-prefix": "",
"log-format": "auto",
"log-level": "info",
"pdfengines-convert-engines": "[libreoffice-pdfengine]",
"pdfengines-disable-routes": "false",
"pdfengines-engines": "[]",
"pdfengines-flatten-engines": "[qpdf]",
"pdfengines-merge-engines": "[qpdf,pdfcpu,pdftk]",
"pdfengines-read-metadata-engines": "[exiftool]",
"pdfengines-split-engines": "[pdfcpu,qpdf,pdftk]",
"pdfengines-write-metadata-engines": "[exiftool]",
"prometheus-collect-interval": "1s",
"prometheus-disable-collect": "false",
"prometheus-disable-route-logging": "false",
"prometheus-namespace": "gotenberg",
"webhook-allow-list": "",
"webhook-client-timeout": "30s",
"webhook-deny-list": "",
"webhook-disable": "false",
"webhook-error-allow-list": "",
"webhook-error-deny-list": "",
"webhook-max-retry": "4",
"webhook-retry-max-wait": "30s",
"webhook-retry-min-wait": "1s"
}
}
"""
Scenario: GET /debug (Gotenberg Trace)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
When I make a "GET" request to Gotenberg at the "/debug" endpoint with the following header(s):
| Gotenberg-Trace | debug |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "debug"
Then the Gotenberg container should log the following entries:
| "trace":"debug" |
Scenario: GET /debug (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/debug" endpoint
Then the response status code should be 401
Scenario: GET /foo/debug (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/debug" endpoint
Then the response status code should be 200

View File

@@ -0,0 +1,107 @@
# TODO:
# 1. Check if down for each module.
# 2. Restarting modules do not make health check fail.
Feature: /health
Scenario: GET /health
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json; charset=utf-8"
Then the response body should match JSON:
"""
{
"status": "up",
"details": {
"chromium": {
"status": "up",
"timestamp": "ignore"
},
"libreoffice": {
"status": "up",
"timestamp": "ignore"
}
}
}
"""
Then the Gotenberg container should log the following entries:
| "path":"/health" |
Scenario: GET /health (No Logging)
Given I have a Gotenberg container with the following environment variable(s):
| API_DISABLE_HEALTH_CHECK_LOGGING | true |
When I make a "GET" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Then the Gotenberg container should NOT log the following entries:
| "path":"/health" |
Scenario: GET /health (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/health" endpoint with the following header(s):
| Gotenberg-Trace | get_health |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "get_health"
Then the Gotenberg container should log the following entries:
| "trace":"get_health" |
Scenario: GET /health (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Scenario: GET /foo/health (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/health" endpoint
Then the response status code should be 200
Scenario: HEAD /health
Given I have a default Gotenberg container
When I make a "HEAD" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Then the response body should match string:
"""
"""
Then the Gotenberg container should log the following entries:
| "path":"/health" |
Scenario: HEAD /health (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "HEAD" request to Gotenberg at the "/health" endpoint with the following header(s):
| Gotenberg-Trace | head_health |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "head_health"
Then the Gotenberg container should log the following entries:
| "trace":"head_health" |
Scenario: HEAD /health (No Logging)
Given I have a Gotenberg container with the following environment variable(s):
| API_DISABLE_HEALTH_CHECK_LOGGING | true |
When I make a "HEAD" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Then the Gotenberg container should NOT log the following entries:
| "path":"/health" |
Scenario: HEAD /health (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "HEAD" request to Gotenberg at the "/health" endpoint
Then the response status code should be 200
Scenario: HEAD /foo/health (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ROOT_PATH | /foo/ |
When I make a "HEAD" request to Gotenberg at the "/foo/health" endpoint
Then the response status code should be 200
# TODO:
# 1. Check if down for each module.
# 2. Restarting modules do not make health check fail.

View File

@@ -0,0 +1,614 @@
Feature: /forms/libreoffice/convert
Scenario: POST /forms/libreoffice/convert (Single Document)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/libreoffice/convert (Many Documents)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| files | testdata/page_2.docx | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.zip |
| page_1.docx.pdf |
| page_2.docx.pdf |
Then the "page_1.docx.pdf" PDF should have 1 page(s)
Then the "page_2.docx.pdf" PDF should have 1 page(s)
Then the "page_1.docx.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "page_2.docx.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Scenario: POST /forms/libreoffice/convert (Protected)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/protected_page_1.docx | file |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
LibreOffice failed to process a document: a password may be required, or, if one has been given, it is invalid. In any case, the exact cause is uncertain.
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/protected_page_1.docx | file |
| password | foo | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Scenario: POST /forms/libreoffice/convert (Landscape)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| Gotenberg-Output-Filename | foo | header |
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should NOT be set to landscape orientation
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| landscape | true | field |
| Gotenberg-Output-Filename | foo | header |
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should be set to landscape orientation
Scenario: POST /forms/libreoffice/convert (Native Page Ranges - Single Document)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| nativePageRanges | 2-3 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/libreoffice/convert (Native Page Ranges - Many Documents)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| files | testdata/pages_12.docx | file |
| nativePageRanges | 2-3 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.zip |
| pages_3.docx.pdf |
| pages_12.docx.pdf |
Then the "pages_3.docx.pdf" PDF should have 2 page(s)
Then the "pages_12.docx.pdf" PDF should have 2 page(s)
Then the "pages_3.docx.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.docx.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Then the "pages_12.docx.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_12.docx.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/libreoffice/convert (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| landscape | foo | field |
| exportFormFields | foo | field |
| allowDuplicateFieldNames | foo | field |
| exportBookmarks | foo | field |
| exportBookmarksToPdfDestination | foo | field |
| exportPlaceholders | foo | field |
| exportNotes | foo | field |
| exportNotesPages | foo | field |
| exportOnlyNotesPages | foo | field |
| exportNotesInMargin | foo | field |
| convertOooTargetToPdfTarget | foo | field |
| exportLinksRelativeFsys | foo | field |
| exportHiddenSlides | foo | field |
| skipEmptyPages | foo | field |
| addOriginalDocumentAsStream | foo | field |
| singlePageSheets | foo | field |
| losslessImageCompression | foo | field |
| quality | -1 | field |
| reduceImageResolution | foo | field |
| maxImageResolution | 10 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: no form file found for extensions: [.123 .602 .abw .bib .bmp .cdr .cgm .cmx .csv .cwk .dbf .dif .doc .docm .docx .dot .dotm .dotx .dxf .emf .eps .epub .fodg .fodp .fods .fodt .fopd .gif .htm .html .hwp .jpeg .jpg .key .ltx .lwp .mcw .met .mml .mw .numbers .odd .odg .odm .odp .ods .odt .otg .oth .otp .ots .ott .pages .pbm .pcd .pct .pcx .pdb .pdf .pgm .png .pot .potm .potx .ppm .pps .ppt .pptm .pptx .psd .psw .pub .pwp .pxl .ras .rtf .sda .sdc .sdd .sdp .sdw .sgl .slk .smf .stc .std .sti .stw .svg .svm .swf .sxc .sxd .sxg .sxi .sxm .sxw .tga .tif .tiff .txt .uof .uop .uos .uot .vdx .vor .vsd .vsdm .vsdx .wb2 .wk1 .wks .wmf .wpd .wpg .wps .xbm .xhtml .xls .xlsb .xlsm .xlsx .xlt .xltm .xltx .xlw .xml .xpm .zabw]; form field 'landscape' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportFormFields' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'allowDuplicateFieldNames' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportBookmarks' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportBookmarksToPdfDestination' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportPlaceholders' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportNotes' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportNotesPages' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportOnlyNotesPages' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportNotesInMargin' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'convertOooTargetToPdfTarget' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportLinksRelativeFsys' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'exportHiddenSlides' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'skipEmptyPages' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'addOriginalDocumentAsStream' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'singlePageSheets' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'losslessImageCompression' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'quality' is invalid (got '-1', resulting to value is inferior to 1); form field 'reduceImageResolution' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax); form field 'maxImageResolution' is invalid (got '10', resulting to value is not 75, 150, 300, 600 or 1200)
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| nativePageRanges | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
LibreOffice failed to process a document: possible causes include malformed page ranges 'foo' (nativePageRanges), or, if a password has been provided, it may not be required. In any case, the exact cause is uncertain.
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| password | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
LibreOffice failed to process a document: possible causes include malformed page ranges '' (nativePageRanges), or, if a password has been provided, it may not be required. In any case, the exact cause is uncertain.
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/protected_page_1.docx | file |
| password | bar | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
LibreOffice failed to process a document: a password may be required, or, if one has been given, it is invalid. In any case, the exact cause is uncertain.
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| files | testdata/page_2.docx | file |
| merge | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'merge' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | foo | field |
| splitSpan | 2 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is invalid (got 'foo', resulting to wrong value, expected either 'intervals' or 'pages')
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | intervals | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitSpan' is invalid (got 'foo', resulting to strconv.Atoi: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | pages | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF split mode, while others may have failed to split due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
A PDF format in '{PdfA:foo PdfUa:false}' is not supported
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/libreoffice/convert (Merge)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| files | testdata/page_2.docx | file |
| merge | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Scenario: POST /forms/libreoffice/convert (Merge & Split)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| files | testdata/page_2.docx | file |
| merge | true | field |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| *_0.pdf |
| *_1.pdf |
Then the "*_0.pdf" PDF should have 1 page(s)
Then the "*_1.pdf" PDF should have 1 page(s)
Then the "*_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "*_1.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Scenario: POST /forms/libreoffice/convert (Split Intervals)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.docx_0.pdf |
| pages_3.docx_1.pdf |
Then the "pages_3.docx_0.pdf" PDF should have 2 page(s)
Then the "pages_3.docx_1.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3.docx_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/libreoffice/convert (Split Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.docx_0.pdf |
| pages_3.docx_1.pdf |
Then the "pages_3.docx_0.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_1.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.docx_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/libreoffice/convert (Split Pages & Unify)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.docx.pdf |
Then the "pages_3.docx.pdf" PDF should have 2 page(s)
Then the "pages_3.docx.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.docx.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/libreoffice/convert (Split Many PDFs - Lot of Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_12.docx | file |
| files | testdata/pages_3.docx | file |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 15 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.docx_0.pdf |
| pages_3.docx_1.pdf |
| pages_3.docx_2.pdf |
| pages_12.docx_0.pdf |
| pages_12.docx_1.pdf |
| pages_12.docx_2.pdf |
| pages_12.docx_3.pdf |
| pages_12.docx_4.pdf |
| pages_12.docx_5.pdf |
| pages_12.docx_6.pdf |
| pages_12.docx_7.pdf |
| pages_12.docx_8.pdf |
| pages_12.docx_9.pdf |
| pages_12.docx_10.pdf |
| pages_12.docx_11.pdf |
Then the "pages_3.docx_0.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_2.pdf" PDF should have 1 page(s)
Then the "pages_12.docx_0.pdf" PDF should have 1 page(s)
Then the "pages_12.docx_11.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3.docx_2.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the "pages_12.docx_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_12.docx_11.pdf" PDF should have the following content at page 1:
"""
Page 12
"""
Scenario: POST /forms/libreoffice/convert (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/libreoffice/convert (Split & PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/pages_3.docx | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.docx_0.pdf |
| pages_3.docx_1.pdf |
Then the "pages_3.docx_0.pdf" PDF should have 2 page(s)
Then the "pages_3.docx_1.pdf" PDF should have 1 page(s)
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3.docx_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3.docx_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/libreoffice/convert (Metadata)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/libreoffice/convert (Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/libreoffice/convert (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/libreoffice/convert (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| LIBREOFFICE_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
Then the response status code should be 404
Scenario: POST /forms/libreoffice/convert (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| Gotenberg-Trace | forms_libreoffice_convert | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_libreoffice_convert"
Then the Gotenberg container should log the following entries:
| "trace":"forms_libreoffice_convert" |
Scenario: POST /forms/libreoffice/convert (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.docx","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
Then the response status code should be 200
Then the file request header "X-Foo" should be "bar"
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/libreoffice/convert (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Scenario: POST /forms/libreoffice/convert (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
Then the response status code should be 401
Scenario: POST /foo/forms/libreoffice/convert (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/libreoffice/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.docx | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,185 @@
# TODO:
# 1. PDF/UA-2.
Feature: /forms/pdfengines/convert
Scenario: POST /forms/pdfengines/convert (Single PDF/A-1b)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Single PDF/A-2b)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-2b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-2b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Single PDF/A-3b)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-3b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-3b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Single PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Single PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | PDF/A-1b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: either 'pdfa' or 'pdfua' form fields must be provided
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| pdfa | PDF/A-1b | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: no form file found for extensions: [.pdf]
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
Scenario: POST /forms/pdfengines/convert (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| Gotenberg-Trace | forms_pdfengines_convert | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_convert"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_convert" |
Scenario: POST /forms/pdfengines/convert (Output Filename - Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be the following file(s) in the response:
| foo.pdf |
Scenario: POST /forms/pdfengines/convert (Output Filename - Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | PDF/A-1b | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| foo.zip |
| page_1.pdf |
| page_2.pdf |
Scenario: POST /forms/pdfengines/convert (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| pdfa | PDF/A-1b | field |
Then the file request header "X-Foo" should be "bar"
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/convert (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then the webhook request PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Scenario: POST /forms/pdfengines/convert (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/convert (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/convert" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| pdfa | PDF/A-1b | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,112 @@
Feature: /forms/pdfengines/flatten
Scenario: POST /forms/pdfengines/flatten (Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/flatten (Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/flatten (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: no form file found for extensions: [.pdf]
"""
Scenario: POST /forms/pdfengines/flatten (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/flatten (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Trace | forms_pdfengines_flatten | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_flatten"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_flatten" |
Scenario: POST /forms/pdfengines/flatten (Output Filename - Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be the following file(s) in the response:
| foo.pdf |
Scenario: POST /forms/pdfengines/flatten (Output Filename - Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| foo.zip |
| page_1.pdf |
| page_2.pdf |
Scenario: POST /forms/pdfengines/flatten (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
Then the file request header "X-Foo" should be "bar"
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/flatten (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/flatten (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/flatten (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/flatten" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,324 @@
Feature: /forms/pdfengines/merge
Scenario: POST /forms/pdfengines/merge (default - QPDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Scenario: POST /forms/pdfengines/merge (pdfcpu)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_MERGE_ENGINES | pdfcpu |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Scenario: POST /forms/pdfengines/merge (PDFtk)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_MERGE_ENGINES | pdftk |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Scenario: POST /forms/pdfengines/merge (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: no form file found for extensions: [.pdf]
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/pdfengines/merge (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/pdfengines/merge (Metadata)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/merge (Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/merge (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/merge (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/merge (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Trace | forms_pdfengines_merge | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_merge"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_merge" |
Scenario: POST /forms/pdfengines/merge (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf"},{"url":"http://host.docker.internal:%d/static/testdata/page_2.pdf"}] | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/merge (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| Gotenberg-Output-Filename | foo | header |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| foo.pdf |
Then the "foo.pdf" PDF should have 2 page(s)
Then the "foo.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "foo.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Scenario: POST /forms/pdfengines/merge (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/merge (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/merge" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"

View File

@@ -0,0 +1,268 @@
Feature: /forms/pdfengines/{write|read}
Scenario: POST /forms/pdfengines/metadata/{write|read} (Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/metadata/{write|read} (Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files. | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/page_1.pdf | file |
| files | teststore/page_2.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"page_1.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
},
"page_2.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/metadata/write (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is required; no form file found for extensions: [.pdf]
"""
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/pdfengines/metadata/read (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: no form file found for extensions: [.pdf]
"""
Scenario: POST /forms/pdfengines/metadata/write (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/metadata/read (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/metadata/write (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Trace | forms_pdfengines_metadata_write | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_metadata_write"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_metadata_write" |
Scenario: POST /forms/pdfengines/metadata/read (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| Gotenberg-Trace | forms_pdfengines_metadata_read | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_metadata_read"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_metadata_read" |
Scenario: POST /forms/pdfengines/metadata/write (Output Filename - Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be the following file(s) in the response:
| foo.pdf |
Scenario: POST /forms/pdfengines/metadata/write (Output Filename - Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| files | testdata/page_2.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| foo.zip |
| page_1.pdf |
| page_2.pdf |
Scenario: POST /forms/pdfengines/metadata/write (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| Gotenberg-Output-Filename | foo | header |
Then the file request header "X-Foo" should be "bar"
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Scenario: POST /forms/pdfengines/metadata/read (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/page_1.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
Then the file request header "X-Foo" should be "bar"
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Scenario: POST /forms/pdfengines/metadata/write (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the webhook request
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"foo.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/metadata/write (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
Then the response status code should be 401
Scenario: POST /forms/pdfengines/metadata/read (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/metadata/{write|read} (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
| files | testdata/page_1.pdf | file |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/foo.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"

View File

@@ -0,0 +1,551 @@
Feature: /forms/pdfengines/split
Scenario: POST /forms/pdfengines/split (Intervals - Default - pdfcpu)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Pages - Default - pdfcpu)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 1 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Pages & Unify - Default - pdfcpu)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.pdf |
Then the "pages_3.pdf" PDF should have 2 page(s)
Then the "pages_3.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Pages & Unify - QPDF)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_SPLIT_ENGINES | qpdf |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2-z | field |
| splitUnify | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.pdf |
Then the "pages_3.pdf" PDF should have 2 page(s)
Then the "pages_3.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Pages & Unify - PDFtk)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_SPLIT_ENGINES | pdftk |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2-end | field |
| splitUnify | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3.pdf |
Then the "pages_3.pdf" PDF should have 2 page(s)
Then the "pages_3.pdf" PDF should have the following content at page 1:
"""
Page 2
"""
Then the "pages_3.pdf" PDF should have the following content at page 2:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Many PDFs - Lot of Pages)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_12.pdf | file |
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 1 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 15 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
| pages_3_2.pdf |
| pages_12_0.pdf |
| pages_12_1.pdf |
| pages_12_2.pdf |
| pages_12_3.pdf |
| pages_12_4.pdf |
| pages_12_5.pdf |
| pages_12_6.pdf |
| pages_12_7.pdf |
| pages_12_8.pdf |
| pages_12_9.pdf |
| pages_12_10.pdf |
| pages_12_11.pdf |
Then the "pages_3_0.pdf" PDF should have 1 page(s)
Then the "pages_3_2.pdf" PDF should have 1 page(s)
Then the "pages_12_0.pdf" PDF should have 1 page(s)
Then the "pages_12_11.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_2.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the "pages_12_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_12_11.pdf" PDF should have the following content at page 1:
"""
Page 12
"""
Scenario: POST /forms/pdfengines/split (Bad Request)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is required; form field 'splitSpan' is required; no form file found for extensions: [.pdf]
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | foo | field |
| splitSpan | 2 | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitMode' is invalid (got 'foo', resulting to wrong value, expected either 'intervals' or 'pages')
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'splitSpan' is invalid (got 'foo', resulting to strconv.Atoi: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF split mode, while others may have failed to split due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
At least one PDF engine cannot process the requested PDF format, while others may have failed to convert due to different issues
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfua | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'pdfua' is invalid (got 'foo', resulting to strconv.ParseBool: parsing "foo": invalid syntax)
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| metadata | foo | field |
Then the response status code should be 400
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
Invalid form data: form field 'metadata' is invalid (got 'foo', resulting to unmarshal metadata: invalid character 'o' in literal false (expecting 'a'))
"""
Scenario: POST /forms/pdfengines/split (PDF/A-1b & PDF/UA-1)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 1 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Scenario: POST /forms/pdfengines/split (Metadata)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/pages_3_0.pdf | file |
| files | teststore/pages_3_1.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"pages_3_0.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
},
"pages_3_1.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/split (Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be flatten
Scenario: POST /forms/pdfengines/split (PDF/A-1b & PDF/UA-1 & Metadata & Flatten)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| pdfa | PDF/A-1b | field |
| pdfua | true | field |
| metadata | {"Author":"Julien Neuhart","Copyright":"Julien Neuhart","CreateDate":"2006-09-18T16:27:50-04:00","Creator":"Gotenberg","Keywords":["first","second"],"Marked":true,"ModDate":"2006-09-18T16:27:50-04:00","PDFVersion":1.7,"Producer":"Gotenberg","Subject":"Sample","Title":"Sample","Trapped":"Unknown"} | field |
| flatten | true | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the response
Then there should be the following file(s) in the response:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Then the response PDF(s) should be valid "PDF/A-1b" with a tolerance of 7 failed rule(s)
Then the response PDF(s) should be valid "PDF/UA-1" with a tolerance of 2 failed rule(s)
Then the response PDF(s) should be flatten
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
| files | teststore/pages_3_0.pdf | file |
| files | teststore/pages_3_1.pdf | file |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/json"
Then the response body should match JSON:
"""
{
"pages_3_0.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
},
"pages_3_1.pdf": {
"Author": "Julien Neuhart",
"Copyright": "Julien Neuhart",
"CreateDate": "2006:09:18 16:27:50-04:00",
"Creator": "Gotenberg",
"Keywords": ["first", "second"],
"Marked": true,
"ModDate": "2006:09:18 16:27:50-04:00",
"PDFVersion": 1.7,
"Producer": "Gotenberg",
"Subject": "Sample",
"Title": "Sample",
"Trapped": "Unknown"
}
}
"""
Scenario: POST /forms/pdfengines/split (Routes Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PDFENGINES_DISABLE_ROUTES | true |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 404
Scenario: POST /forms/pdfengines/split (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| Gotenberg-Trace | forms_pdfengines_split | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then the response header "Gotenberg-Trace" should be "forms_pdfengines_split"
Then the Gotenberg container should log the following entries:
| "trace":"forms_pdfengines_split" |
Scenario: POST /forms/pdfengines/split (Output Filename - Single PDF)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | pages | field |
| splitSpan | 2- | field |
| splitUnify | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be the following file(s) in the response:
| foo.pdf |
Scenario: POST /forms/pdfengines/split (Output Filename - Many PDFs)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"
Then there should be the following file(s) in the response:
| foo.zip |
| pages_3_0.pdf |
| pages_3_1.pdf |
Scenario: POST /forms/pdfengines/split (Download From)
Given I have a default Gotenberg container
Given I have a static server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| downloadFrom | [{"url":"http://host.docker.internal:%d/static/testdata/pages_3.pdf","extraHttpHeaders":{"X-Foo":"bar"}}] | field |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the file request header "X-Foo" should be "bar"
Then the response header "Content-Type" should be "application/zip"
Scenario: POST /forms/pdfengines/split (Webhook)
Given I have a default Gotenberg container
Given I have a webhook server
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
| Gotenberg-Webhook-Url | http://host.docker.internal:%d/webhook | header |
| Gotenberg-Webhook-Error-Url | http://host.docker.internal:%d/webhook/error | header |
Then the response status code should be 204
When I wait for the asynchronous request to the webhook
Then the webhook request header "Content-Type" should be "application/zip"
Then there should be 2 PDF(s) in the webhook request
Then there should be the following file(s) in the webhook request:
| pages_3_0.pdf |
| pages_3_1.pdf |
Then the "pages_3_0.pdf" PDF should have 2 page(s)
Then the "pages_3_1.pdf" PDF should have 1 page(s)
Then the "pages_3_0.pdf" PDF should have the following content at page 1:
"""
Page 1
"""
Then the "pages_3_0.pdf" PDF should have the following content at page 2:
"""
Page 2
"""
Then the "pages_3_1.pdf" PDF should have the following content at page 1:
"""
Page 3
"""
Scenario: POST /forms/pdfengines/split (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 401
Scenario: POST /foo/forms/pdfengines/split (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "POST" request to Gotenberg at the "/foo/forms/pdfengines/split" endpoint with the following form data and header(s):
| files | testdata/pages_3.pdf | file |
| splitMode | intervals | field |
| splitSpan | 2 | field |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/zip"

View File

@@ -0,0 +1,90 @@
# TODO:
# 1. Count restarts.
# 2. Count queue size.
Feature: /prometheus/metrics
Scenario: GET /prometheus/metrics (Enabled)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "text/plain; version=0.0.4; charset=utf-8; escaping=underscores"
Then the response body should match string:
"""
# HELP gotenberg_chromium_requests_queue_size Current number of Chromium conversion requests waiting to be treated.
# TYPE gotenberg_chromium_requests_queue_size gauge
gotenberg_chromium_requests_queue_size 0
# HELP gotenberg_chromium_restarts_count Current number of Chromium restarts.
# TYPE gotenberg_chromium_restarts_count gauge
gotenberg_chromium_restarts_count 0
# HELP gotenberg_libreoffice_requests_queue_size Current number of LibreOffice conversion requests waiting to be treated.
# TYPE gotenberg_libreoffice_requests_queue_size gauge
gotenberg_libreoffice_requests_queue_size 0
# HELP gotenberg_libreoffice_restarts_count Current number of LibreOffice restarts.
# TYPE gotenberg_libreoffice_restarts_count gauge
gotenberg_libreoffice_restarts_count 0
"""
Then the Gotenberg container should log the following entries:
| "path":"/prometheus/metrics" |
Scenario: GET /prometheus/metrics (Custom Namespace)
Given I have a Gotenberg container with the following environment variable(s):
| PROMETHEUS_NAMESPACE | foo |
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "text/plain; version=0.0.4; charset=utf-8; escaping=underscores"
Then the response body should match string:
"""
# HELP foo_chromium_requests_queue_size Current number of Chromium conversion requests waiting to be treated.
# TYPE foo_chromium_requests_queue_size gauge
foo_chromium_requests_queue_size 0
# HELP foo_chromium_restarts_count Current number of Chromium restarts.
# TYPE foo_chromium_restarts_count gauge
foo_chromium_restarts_count 0
# HELP foo_libreoffice_requests_queue_size Current number of LibreOffice conversion requests waiting to be treated.
# TYPE foo_libreoffice_requests_queue_size gauge
foo_libreoffice_requests_queue_size 0
# HELP foo_libreoffice_restarts_count Current number of LibreOffice restarts.
# TYPE foo_libreoffice_restarts_count gauge
foo_libreoffice_restarts_count 0
"""
Scenario: GET /prometheus/metrics (Disabled)
Given I have a Gotenberg container with the following environment variable(s):
| PROMETHEUS_DISABLE_COLLECT | true |
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint
Then the response status code should be 404
Scenario: GET /prometheus/metrics (No Logging)
Given I have a Gotenberg container with the following environment variable(s):
| PROMETHEUS_DISABLE_ROUTE_LOGGING | true |
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint
Then the response status code should be 200
Then the Gotenberg container should NOT log the following entries:
| "path":"/prometheus/metrics" |
Scenario: GET /prometheus/metrics (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint with the following header(s):
| Gotenberg-Trace | prometheus_metrics |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "prometheus_metrics"
Then the Gotenberg container should log the following entries:
| "trace":"prometheus_metrics" |
Scenario: GET /prometheus/metrics (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/prometheus/metrics" endpoint
Then the response status code should be 401
Scenario: GET /foo/prometheus/metrics (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/prometheus/metrics" endpoint
Then the response status code should be 200

View File

@@ -0,0 +1,62 @@
Feature: /
Scenario: GET /
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "text/html; charset=UTF-8"
Then the response body should match string:
"""
Hey, Gotenberg has no UI, it's an API. Head to the <a href="https://gotenberg.dev">documentation</a> to learn how to interact with it 🚀
"""
Scenario: GET / (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/" endpoint with the following header(s):
| Gotenberg-Trace | root |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "root"
Then the Gotenberg container should log the following entries:
| "trace":"root" |
Scenario: GET / (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/" endpoint
Then the response status code should be 401
Scenario: GET /foo/ (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/" endpoint
Then the response status code should be 200
Scenario: GET /favicon.ico
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/favicon.ico" endpoint
Then the response status code should be 204
Scenario: GET /favicon.ico (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/favicon.ico" endpoint with the following header(s):
| Gotenberg-Trace | favicon |
Then the response status code should be 204
Then the response header "Gotenberg-Trace" should be "favicon"
Then the Gotenberg container should log the following entries:
| "trace":"favicon" |
Scenario: GET /favicon.ico (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/favicon.ico" endpoint
Then the response status code should be 401
Scenario: GET /foo/favicon.ico (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/favicon.ico" endpoint
Then the response status code should be 204

View File

@@ -0,0 +1,35 @@
Feature: /version
Scenario: GET /version
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/version" endpoint
Then the response status code should be 200
Then the response header "Content-Type" should be "text/plain; charset=UTF-8"
Then the response body should match string:
"""
{version}
"""
Scenario: GET /version (Gotenberg Trace)
Given I have a default Gotenberg container
When I make a "GET" request to Gotenberg at the "/version" endpoint with the following header(s):
| Gotenberg-Trace | version |
Then the response status code should be 200
Then the response header "Gotenberg-Trace" should be "version"
Then the Gotenberg container should log the following entries:
| "trace":"version" |
Scenario: GET /version (Basic Auth)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_BASIC_AUTH | true |
| GOTENBERG_API_BASIC_AUTH_USERNAME | foo |
| GOTENBERG_API_BASIC_AUTH_PASSWORD | bar |
When I make a "GET" request to Gotenberg at the "/version" endpoint
Then the response status code should be 401
Scenario: GET /foo/version (Root Path)
Given I have a Gotenberg container with the following environment variable(s):
| API_ENABLE_DEBUG_ROUTE | true |
| API_ROOT_PATH | /foo/ |
When I make a "GET" request to Gotenberg at the "/foo/version" endpoint
Then the response status code should be 200

View File

@@ -0,0 +1,50 @@
//go:build integration
package integration
import (
"os"
"runtime"
"testing"
"github.com/cucumber/godog"
"github.com/cucumber/godog/colors"
flag "github.com/spf13/pflag"
"github.com/gotenberg/gotenberg/v8/test/integration/scenario"
)
var opts = godog.Options{
Format: "pretty",
Paths: []string{"features"},
Output: colors.Colored(os.Stdout),
Concurrency: runtime.NumCPU(),
}
func TestMain(m *testing.M) {
repository := flag.String("gotenberg-docker-repository", "", "")
version := flag.String("gotenberg-version", "", "")
platform := flag.String("gotenberg-container-platform", "", "")
flag.Parse()
if *platform == "" {
switch runtime.GOARCH {
case "arm64":
*platform = "linux/arm64"
default:
*platform = "linux/amd64"
}
}
scenario.GotenbergDockerRepository = *repository
scenario.GotenbergVersion = *version
scenario.GotenbergContainerPlatform = *platform
code := godog.TestSuite{
Name: "integration",
ScenarioInitializer: scenario.InitializeScenario,
Options: &opts,
}.Run()
os.Exit(code)
}

View File

@@ -0,0 +1,57 @@
package scenario
import (
"fmt"
"reflect"
)
func compareJson(expected, actual interface{}) error {
// Handle maps (JSON objects).
expectedMap, ok := expected.(map[string]interface{})
if ok {
actualMap, ok := actual.(map[string]interface{})
if !ok {
return fmt.Errorf("expected an object, but actual is: %T", actual)
}
// For each key in expected, compare if the expected value is not
// "ignore".
for key, expVal := range expectedMap {
if str, isStr := expVal.(string); isStr && str == "ignore" {
continue // Skip.
}
actVal, exists := actualMap[key]
if !exists {
return fmt.Errorf("missing expected key %q", key)
}
if err := compareJson(expVal, actVal); err != nil {
return fmt.Errorf("key %q: %w", key, err)
}
}
return nil
}
// Handle slices (JSON arrays).
expectedSlice, ok := expected.([]interface{})
if ok {
actualSlice, ok := actual.([]interface{})
if !ok {
return fmt.Errorf("expected an array, but actual is: %T", actual)
}
if len(expectedSlice) != len(actualSlice) {
return fmt.Errorf("expected array length to be: %d, but actual is: %d", len(expectedSlice), len(actualSlice))
}
for i := range expectedSlice {
if err := compareJson(expectedSlice[i], actualSlice[i]); err != nil {
return fmt.Errorf("at index %d: %w", i, err)
}
}
return nil
}
// For other types, compare directly.
if !reflect.DeepEqual(expected, actual) {
return fmt.Errorf("expected %v (%T) but got %v (%T)", expected, expected, actual, actual)
}
return nil
}

View File

@@ -0,0 +1,136 @@
package scenario
import (
"context"
"fmt"
"io"
"path/filepath"
"time"
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/network"
"github.com/testcontainers/testcontainers-go/wait"
)
var (
GotenbergDockerRepository string
GotenbergVersion string
GotenbergContainerPlatform string
)
type noopLogger struct{}
func (n *noopLogger) Printf(format string, v ...interface{}) {
// NOOP
}
func startGotenbergContainer(ctx context.Context, env map[string]string) (*testcontainers.DockerNetwork, testcontainers.Container, error) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
n, err := network.New(ctx)
if err != nil {
return nil, nil, fmt.Errorf("create Gotenberg container network: %w", err)
}
heathPath := "/health"
if env["API_ROOT_PATH"] != "" {
heathPath = fmt.Sprintf("%shealth", env["API_ROOT_PATH"])
}
req := testcontainers.ContainerRequest{
Image: fmt.Sprintf("gotenberg/%s:%s", GotenbergDockerRepository, GotenbergVersion),
ImagePlatform: GotenbergContainerPlatform,
ExposedPorts: []string{"3000/tcp"},
HostConfigModifier: func(hostConfig *container.HostConfig) {
hostConfig.ExtraHosts = []string{"host.docker.internal:host-gateway"}
},
Networks: []string{n.Name},
WaitingFor: wait.ForHTTP(heathPath),
Env: env,
}
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
Logger: &noopLogger{},
})
if err != nil {
err = fmt.Errorf("start new Gotenberg container: %w", err)
}
return n, c, err
}
func execCommandInIntegrationToolsContainer(ctx context.Context, cmd []string, path string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
req := testcontainers.ContainerRequest{
Image: "gotenberg/integration-tools:latest",
Files: []testcontainers.ContainerFile{
{
HostFilePath: path,
ContainerFilePath: filepath.Base(path),
FileMode: 0o700,
},
},
Cmd: []string{"tail", "-f", "/dev/null"}, // Keeps container running indefinitely.
}
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
Logger: &noopLogger{},
})
if err != nil {
return "", fmt.Errorf("start new Integration Tools container: %w", err)
}
defer func(c testcontainers.Container, ctx context.Context) {
err := c.Terminate(ctx)
if err != nil {
fmt.Printf("terminate container: %v\n", err)
}
}(c, ctx)
_, output, err := c.Exec(ctx, cmd)
if err != nil {
return "", fmt.Errorf("exec %q: %w", cmd, err)
}
b, err := io.ReadAll(output)
if err != nil {
return "", fmt.Errorf("read output: %w", err)
}
return string(b), nil
}
func containerHttpEndpoint(ctx context.Context, container testcontainers.Container, port nat.Port) (string, error) {
ip, err := container.Host(ctx)
if err != nil {
return "", fmt.Errorf("get container IP: %w", err)
}
mapped, err := container.MappedPort(ctx, port)
if err != nil {
return "", fmt.Errorf("get container port: %w", err)
}
return fmt.Sprintf("http://%s:%s", ip, mapped.Port()), nil
}
func containerLogEntries(ctx context.Context, container testcontainers.Container) (string, error) {
logReader, err := container.Logs(ctx)
if err != nil {
return "", fmt.Errorf("get container log entries: %w", err)
}
defer logReader.Close()
logsBytes, err := io.ReadAll(logReader)
if err != nil {
return "", fmt.Errorf("read container log entries: %w", err)
}
return string(logsBytes), nil
}

View File

@@ -0,0 +1,2 @@
// Package scenario gathers all steps used in the features.
package scenario

View File

@@ -0,0 +1,83 @@
package scenario
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
)
func doRequest(method, url string, headers map[string]string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, fmt.Errorf("create a request: %w", err)
}
for header, value := range headers {
req.Header.Set(header, value)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("send a request: %w", err)
}
return resp, nil
}
func doFormDataRequest(method, url string, fields map[string]string, files map[string][]string, headers map[string]string) (*http.Response, error) {
var b bytes.Buffer
writer := multipart.NewWriter(&b)
for name, value := range fields {
err := writer.WriteField(name, value)
if err != nil {
return nil, fmt.Errorf("write field %q: %w", name, err)
}
}
for name, paths := range files {
for _, path := range paths {
part, err := writer.CreateFormFile(name, filepath.Base(path))
if err != nil {
return nil, fmt.Errorf("create form file %q: %w", filepath.Base(path), err)
}
reader, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("open file %q: %w", path, err)
}
defer reader.Close()
_, err = io.Copy(part, reader)
if err != nil {
return nil, fmt.Errorf("copy file %q: %w", path, err)
}
}
}
err := writer.Close()
if err != nil {
return nil, fmt.Errorf("close writer: %w", err)
}
req, err := http.NewRequest(method, url, &b)
if err != nil {
return nil, fmt.Errorf("create a request: %w", err)
}
for header, value := range headers {
req.Header.Set(header, value)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("send a request: %w", err)
}
return resp, nil
}

View File

@@ -0,0 +1,911 @@
package scenario
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"github.com/cucumber/godog"
"github.com/google/uuid"
"github.com/mholt/archives"
"github.com/testcontainers/testcontainers-go"
)
type scenario struct {
resp *httptest.ResponseRecorder
workdir string
gotenbergContainer testcontainers.Container
gotenbergContainerNetwork *testcontainers.DockerNetwork
server *server
hostPort int
}
func (s *scenario) reset(ctx context.Context) error {
s.resp = httptest.NewRecorder()
err := os.RemoveAll(s.workdir)
if err != nil {
return fmt.Errorf("remove workdir %q: %w", s.workdir, err)
}
s.workdir = ""
if s.server == nil {
return nil
}
err = s.server.stop(ctx)
if err != nil {
return fmt.Errorf("stop server: %w", err)
}
return nil
}
func (s *scenario) iHaveADefaultGotenbergContainer(ctx context.Context) error {
n, c, err := startGotenbergContainer(ctx, nil)
if err != nil {
return fmt.Errorf("create Gotenberg container: %s", err)
}
s.gotenbergContainerNetwork = n
s.gotenbergContainer = c
return nil
}
func (s *scenario) iHaveAGotenbergContainerWithTheFollowingEnvironmentVariables(ctx context.Context, envTable *godog.Table) error {
env := make(map[string]string)
for _, row := range envTable.Rows {
env[row.Cells[0].Value] = row.Cells[1].Value
}
n, c, err := startGotenbergContainer(ctx, env)
if err != nil {
return fmt.Errorf("create Gotenberg container: %s", err)
}
s.gotenbergContainerNetwork = n
s.gotenbergContainer = c
return nil
}
func (s *scenario) iHaveAServer(ctx context.Context) error {
srv, err := newServer(ctx, s.workdir)
if err != nil {
return fmt.Errorf("create server: %s", err)
}
s.server = srv
port, err := s.server.start(ctx)
if err != nil {
return fmt.Errorf("start server: %s", err)
}
s.hostPort = port
return nil
}
func (s *scenario) iMakeARequestToGotenberg(ctx context.Context, method, endpoint string) error {
return s.iMakeARequestToGotenbergWithTheFollowingHeaders(ctx, method, endpoint, nil)
}
func (s *scenario) iMakeARequestToGotenbergWithTheFollowingHeaders(ctx context.Context, method, endpoint string, headersTable *godog.Table) error {
if s.gotenbergContainer == nil {
return errors.New("no Gotenberg container")
}
base, err := containerHttpEndpoint(ctx, s.gotenbergContainer, "3000")
if err != nil {
return fmt.Errorf("get container HTTP endpoint: %w", err)
}
headers := make(map[string]string)
if headersTable != nil {
for _, row := range headersTable.Rows {
headers[row.Cells[0].Value] = row.Cells[1].Value
}
}
resp, err := doRequest(method, fmt.Sprintf("%s%s", base, endpoint), headers, nil)
if err != nil {
return fmt.Errorf("do request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read response body: %w", err)
}
s.resp = httptest.NewRecorder()
s.resp.Code = resp.StatusCode
for key, values := range resp.Header {
for _, v := range values {
s.resp.Header().Add(key, v)
}
}
_, err = s.resp.Body.Write(body)
if err != nil {
return fmt.Errorf("write response body: %w", err)
}
return nil
}
func (s *scenario) iMakeARequestToGotenbergWithTheFollowingFormDataAndHeaders(ctx context.Context, method, endpoint string, dataTable *godog.Table) error {
if s.gotenbergContainer == nil {
return errors.New("no Gotenberg container")
}
fields := make(map[string]string)
files := make(map[string][]string)
headers := make(map[string]string)
for _, row := range dataTable.Rows {
name := row.Cells[0].Value
value := row.Cells[1].Value
kind := row.Cells[2].Value
switch kind {
case "field":
if name == "downloadFrom" || name == "url" || name == "cookies" {
fields[name] = strings.ReplaceAll(value, "%d", fmt.Sprintf("%d", s.hostPort))
continue
}
fields[name] = value
case "file":
if strings.Contains(value, "teststore") {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
value = strings.ReplaceAll(value, "teststore", dirPath)
} else {
wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("get current directory: %w", err)
}
value = fmt.Sprintf("%s/%s", wd, value)
}
files[name] = append(files[name], value)
case "header":
if name == "Gotenberg-Webhook-Url" || name == "Gotenberg-Webhook-Error-Url" {
headers[name] = fmt.Sprintf(value, s.hostPort)
continue
}
headers[name] = value
default:
return fmt.Errorf("unexpected %q %q", kind, value)
}
}
base, err := containerHttpEndpoint(ctx, s.gotenbergContainer, "3000")
if err != nil {
return fmt.Errorf("get container HTTP endpoint: %w", err)
}
resp, err := doFormDataRequest(method, fmt.Sprintf("%s%s", base, endpoint), fields, files, headers)
if err != nil {
return fmt.Errorf("do request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read response body: %w", err)
}
s.resp = httptest.NewRecorder()
s.resp.Code = resp.StatusCode
for key, values := range resp.Header {
for _, v := range values {
s.resp.Header().Add(key, v)
}
}
_, err = s.resp.Body.Write(body)
if err != nil {
return fmt.Errorf("write response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil
}
cd := resp.Header.Get("Content-Disposition")
if cd == "" {
return nil
}
_, params, err := mime.ParseMediaType(cd)
if err != nil {
return fmt.Errorf("parse Content-Disposition header: %w", err)
}
filename, ok := params["filename"]
if !ok {
return errors.New("no filename in Content-Disposition header")
}
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
err = os.MkdirAll(dirPath, 0o755)
if err != nil {
return fmt.Errorf("create working directory: %w", err)
}
fpath := fmt.Sprintf("%s/%s", dirPath, filename)
file, err := os.Create(fpath)
if err != nil {
return fmt.Errorf("create file %q: %w", fpath, err)
}
defer file.Close()
_, err = file.Write(body)
if err != nil {
return fmt.Errorf("write file %q: %w", fpath, err)
}
if resp.Header.Get("Content-Type") == "application/zip" {
var format archives.Zip
err = format.Extract(ctx, file, func(ctx context.Context, f archives.FileInfo) error {
source, err := f.Open()
if err != nil {
return fmt.Errorf("open file %q: %w", f.Name(), err)
}
defer source.Close()
targetPath := fmt.Sprintf("%s/%s", dirPath, f.Name())
target, err := os.Create(targetPath)
if err != nil {
return fmt.Errorf("create file %q: %w", targetPath, err)
}
defer target.Close()
_, err = io.Copy(target, source)
if err != nil {
return fmt.Errorf("copy file %q: %w", targetPath, err)
}
return nil
})
if err != nil {
return err
}
}
return nil
}
func (s *scenario) iWaitForTheAsynchronousRequestToWebhook(ctx context.Context) error {
if s.server == nil {
return errors.New("server not initialized")
}
if s.server.req != nil {
return nil
}
select {
case <-ctx.Done():
return ctx.Err()
case err := <-s.server.errChan:
return err
}
}
func (s *scenario) theGotenbergContainerShouldLogTheFollowingEntries(ctx context.Context, should string, entriesTable *godog.Table) error {
if s.gotenbergContainer == nil {
return errors.New("no Gotenberg container")
}
expected := make([]string, len(entriesTable.Rows))
for i, row := range entriesTable.Rows {
expected[i] = row.Cells[0].Value
}
invert := should == "should NOT"
check := func() error {
logs, err := containerLogEntries(ctx, s.gotenbergContainer)
if err != nil {
return fmt.Errorf("get log entries: %w", err)
}
for _, entry := range expected {
if !invert && !strings.Contains(logs, entry) {
return fmt.Errorf("expected log entry %q not found in %q", expected, logs)
}
if invert && strings.Contains(logs, entry) {
return fmt.Errorf("log entry %q NOT expected", expected)
}
}
return nil
}
var err error
for i := 0; i < 3; i++ {
err = check()
if err != nil && !invert {
// We have to retry as not all logs may have been produced.
time.Sleep(500 * time.Millisecond)
continue
}
break
}
return err
}
func (s *scenario) theResponseStatusCodeShouldBe(expected int) error {
if expected != s.resp.Code {
return fmt.Errorf("expected response status code to be: %d, but actual is: %d %q", expected, s.resp.Code, s.resp.Body.String())
}
return nil
}
func (s *scenario) theHeaderValueShouldBe(kind, name string, expected string) error {
var actual string
if kind == "response" {
actual = s.resp.Header().Get(name)
} else if s.server == nil {
return errors.New("server not initialized")
} else if s.server.req == nil {
return errors.New("no webhook request found")
} else {
actual = s.server.req.Header.Get(name)
}
if expected != actual {
return fmt.Errorf("expected %s header %q to be: %q, but actual is: %q", kind, name, expected, actual)
}
return nil
}
func (s *scenario) theCookieValueShouldBe(kind, name, expected string) error {
var cookies []*http.Cookie
if kind == "response" {
cookies = s.resp.Result().Cookies()
} else if s.server == nil {
return errors.New("server not initialized")
} else if s.server.req == nil {
return errors.New("no webhook request found")
} else {
cookies = s.server.req.Cookies()
}
var actual *http.Cookie
for _, cookie := range cookies {
if cookie.Name == name {
actual = cookie
break
}
}
if actual == nil {
if expected != "" {
return fmt.Errorf("expected %s cookie %q not found", kind, name)
}
return nil
}
if expected != actual.Value {
return fmt.Errorf("expected %s cookie %q to be: %q, but actual is: %q", kind, name, expected, actual.Value)
}
return nil
}
func (s *scenario) theBodyShouldMatchString(kind string, expectedDoc *godog.DocString) error {
var actual string
if kind == "response" {
actual = s.resp.Body.String()
} else if s.server == nil {
return errors.New("server not initialized")
} else if s.server.req == nil {
return errors.New("no webhook request found")
} else {
body, err := io.ReadAll(s.server.req.Body)
if err != nil {
return fmt.Errorf("read request body: %w", err)
}
actual = string(body)
}
expected := strings.ReplaceAll(expectedDoc.Content, "{version}", GotenbergVersion)
if actual != expected {
return fmt.Errorf("expected %q body to be: %q, but actual is: %q", kind, expected, actual)
}
return nil
}
func (s *scenario) theBodyShouldContainString(kind string, expectedDoc *godog.DocString) error {
var actual string
if kind == "response" {
actual = s.resp.Body.String()
} else if s.server == nil {
return errors.New("server not initialized")
} else if s.server.req == nil {
return errors.New("no webhook request found")
} else {
body, err := io.ReadAll(s.server.req.Body)
if err != nil {
return fmt.Errorf("read request body: %w", err)
}
actual = string(body)
}
expected := strings.ReplaceAll(expectedDoc.Content, "{version}", GotenbergVersion)
if !strings.Contains(actual, expected) {
return fmt.Errorf("expected %q body to contain: %q, but actual is: %q", kind, expected, actual)
}
return nil
}
func (s *scenario) theBodyShouldMatchJSON(kind string, expectedDoc *godog.DocString) error {
var body []byte
if kind == "response" {
body = s.resp.Body.Bytes()
} else if s.server == nil {
return errors.New("server not initialized")
} else if s.server.req == nil {
return errors.New("no webhook request found")
} else {
b, err := io.ReadAll(s.server.req.Body)
if err != nil {
return fmt.Errorf("read request body: %w", err)
}
body = b
}
var expected, actual interface{}
content := strings.ReplaceAll(expectedDoc.Content, "{version}", GotenbergVersion)
err := json.Unmarshal([]byte(content), &expected)
if err != nil {
return fmt.Errorf("unmarshal expected JSON: %w", err)
}
err = json.Unmarshal(body, &actual)
if err != nil {
return fmt.Errorf("unmarshal actual JSON: %w", err)
}
err = compareJson(expected, actual)
if err != nil {
return fmt.Errorf("expected matching JSON: %w", err)
}
return nil
}
func (s *scenario) thereShouldBePdfs(expected int, kind string) error {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
var paths []string
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.EqualFold(filepath.Ext(info.Name()), ".pdf") {
paths = append(paths, path)
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
if len(paths) != expected {
return fmt.Errorf("expected %d PDF(s), but actual is %d", expected, len(paths))
}
return nil
}
func (s *scenario) thereShouldBeTheFollowingFiles(kind string, filesTable *godog.Table) error {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
var filenames []string
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if !info.IsDir() {
filenames = append(filenames, info.Name())
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
for _, row := range filesTable.Rows {
found := false
expected := row.Cells[0].Value
for _, filename := range filenames {
if strings.HasPrefix(expected, "*_") && strings.Contains(filename, strings.ReplaceAll(expected, "*_", "")) {
found = true
}
if strings.EqualFold(expected, filename) {
found = true
break
}
}
if !found {
return fmt.Errorf("expected file %q not found among %q", expected, filenames)
}
}
return nil
}
func (s *scenario) thePdfsShouldBeValidWithAToleranceOf(ctx context.Context, kind, validate string, tolerance int) error {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
var paths []string
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.EqualFold(filepath.Ext(info.Name()), ".pdf") {
paths = append(paths, path)
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
var flavor string
switch validate {
case "PDF/A-1b":
flavor = "1b"
case "PDF/A-2b":
flavor = "2b"
case "PDF/A-3b":
flavor = "3b"
case "PDF/UA-1":
flavor = "ua1"
case "PDF/UA-2":
flavor = "ua2"
default:
return fmt.Errorf("unknown %q", validate)
}
for _, path := range paths {
cmd := []string{
"verapdf",
"-f",
flavor,
filepath.Base(path),
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
re := regexp.MustCompile(`failedRules="(\d+)"`)
matches := re.FindStringSubmatch(output)
if len(matches) < 2 {
return errors.New("expected failed rules")
}
failedRules, err := strconv.Atoi(matches[1])
if err != nil {
return fmt.Errorf("convert failed rules value %q to integer: %w", matches[1], err)
}
if tolerance < failedRules {
return fmt.Errorf("expected failed rules to be inferior or equal to: %d, but actual is %d", tolerance, failedRules)
}
}
return nil
}
func (s *scenario) thePdfShouldHavePages(ctx context.Context, name string, pages int) error {
var path string
if !strings.HasPrefix(name, "*_") {
path = fmt.Sprintf("%s/%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"), name)
_, err := os.Stat(path)
if os.IsNotExist(err) {
return fmt.Errorf("PDF %q does not exist", path)
}
} else {
substr := strings.ReplaceAll(name, "*_", "")
err := filepath.Walk(fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace")), func(currentPath string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.Contains(info.Name(), substr) {
path = currentPath
return filepath.SkipDir
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
}
cmd := []string{
"pdfinfo",
filepath.Base(path),
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
output = strings.ReplaceAll(output, " ", "")
re := regexp.MustCompile(`Pages:(\d+)`)
matches := re.FindStringSubmatch(output)
if len(matches) < 2 {
return errors.New("expected pages")
}
actual, err := strconv.Atoi(matches[1])
if err != nil {
return fmt.Errorf("convert pages value %q to integer: %w", matches[1], err)
}
if actual != pages {
return fmt.Errorf("expected %d pages, but actual is %d", pages, actual)
}
return nil
}
func (s *scenario) thePdfShouldBeSetToLandscapeOrientation(ctx context.Context, name string, kind string) error {
var path string
if !strings.HasPrefix(name, "*_") {
path = fmt.Sprintf("%s/%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"), name)
_, err := os.Stat(path)
if os.IsNotExist(err) {
return fmt.Errorf("PDF %q does not exist", path)
}
} else {
substr := strings.ReplaceAll(name, "*_", "")
err := filepath.Walk(fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace")), func(currentPath string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.Contains(info.Name(), substr) {
path = currentPath
return filepath.SkipDir
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
}
cmd := []string{
"pdfinfo",
filepath.Base(path),
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
output = strings.ReplaceAll(output, " ", "")
re := regexp.MustCompile(`Pagesize:(\d+)x(\d+).*`)
matches := re.FindStringSubmatch(output)
if len(matches) < 3 {
return errors.New("expected page size")
}
invert := kind == "should NOT"
width, err := strconv.Atoi(matches[1])
if err != nil {
return fmt.Errorf("convert width value %q to integer: %w", matches[1], err)
}
height, err := strconv.Atoi(matches[2])
if err != nil {
return fmt.Errorf("convert height value %q to integer: %w", matches[2], err)
}
if invert && height < width {
return fmt.Errorf("expected height %d to be greater than width %d", height, width)
}
if !invert && width < height {
return fmt.Errorf("expected width %d to be greater than height %d", width, height)
}
return nil
}
func (s *scenario) thePdfShouldHaveTheFollowingContentAtPage(ctx context.Context, name, kind string, page int, expected *godog.DocString) error {
var path string
if !strings.HasPrefix(name, "*_") {
path = fmt.Sprintf("%s/%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"), name)
_, err := os.Stat(path)
if os.IsNotExist(err) {
return fmt.Errorf("PDF %q does not exist", path)
}
} else {
substr := strings.ReplaceAll(name, "*_", "")
err := filepath.Walk(fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace")), func(currentPath string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.Contains(info.Name(), substr) {
path = currentPath
return filepath.SkipDir
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
}
cmd := []string{
"pdftotext",
"-f",
fmt.Sprintf("%d", page),
"-l",
fmt.Sprintf("%d", page),
filepath.Base(path),
"-",
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
invert := kind == "should NOT"
if !invert && !strings.Contains(output, expected.Content) {
return fmt.Errorf("expected %q not found in %q", expected.Content, output)
}
if invert && strings.Contains(output, expected.Content) {
return fmt.Errorf("%q found in %q", expected.Content, output)
}
return nil
}
func (s *scenario) thePdfsShouldBeFlatten(ctx context.Context, kind, should string) error {
dirPath := fmt.Sprintf("%s/%s", s.workdir, s.resp.Header().Get("Gotenberg-Trace"))
_, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory %q does not exist", dirPath)
}
var paths []string
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, pathErr error) error {
if pathErr != nil {
return pathErr
}
if strings.EqualFold(filepath.Ext(info.Name()), ".pdf") {
paths = append(paths, path)
}
return nil
})
if err != nil {
return fmt.Errorf("walk %q: %w", s.workdir, err)
}
for _, path := range paths {
cmd := []string{
"verapdf",
"-off",
"--extract",
"annotations",
filepath.Base(path),
}
output, err := execCommandInIntegrationToolsContainer(ctx, cmd, path)
if err != nil {
return fmt.Errorf("exec %q: %w", cmd, err)
}
invert := should == "should NOT"
if invert && strings.Contains(output, "<featuresReport></featuresReport>") {
return fmt.Errorf("PDF %q is flatten", path)
}
if !invert && !strings.Contains(output, "<featuresReport></featuresReport>") {
return fmt.Errorf("PDF %q is not flatten", path)
}
}
return nil
}
func InitializeScenario(ctx *godog.ScenarioContext) {
s := &scenario{}
ctx.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
wd, err := os.Getwd()
if err != nil {
return ctx, fmt.Errorf("get current directory: %w", err)
}
s.workdir = fmt.Sprintf("%s/teststore/%s", wd, uuid.NewString())
err = os.MkdirAll(s.workdir, 0o755)
if err != nil {
return ctx, fmt.Errorf("create working directory: %w", err)
}
return ctx, nil
})
ctx.Given(`^I have a default Gotenberg container$`, s.iHaveADefaultGotenbergContainer)
ctx.Given(`^I have a Gotenberg container with the following environment variable\(s\):$`, s.iHaveAGotenbergContainerWithTheFollowingEnvironmentVariables)
ctx.Given(`^I have a (webhook|static) server$`, s.iHaveAServer)
ctx.When(`^I make a "(GET|HEAD)" request to Gotenberg at the "([^"]*)" endpoint$`, s.iMakeARequestToGotenberg)
ctx.When(`^I make a "(GET|HEAD)" request to Gotenberg at the "([^"]*)" endpoint with the following header\(s\):$`, s.iMakeARequestToGotenbergWithTheFollowingHeaders)
ctx.When(`^I make a "(POST)" request to Gotenberg at the "([^"]*)" endpoint with the following form data and header\(s\):$`, s.iMakeARequestToGotenbergWithTheFollowingFormDataAndHeaders)
ctx.When(`^I wait for the asynchronous request to the webhook$`, s.iWaitForTheAsynchronousRequestToWebhook)
ctx.Then(`^the Gotenberg container (should|should NOT) log the following entries:$`, s.theGotenbergContainerShouldLogTheFollowingEntries)
ctx.Then(`^the response status code should be (\d+)$`, s.theResponseStatusCodeShouldBe)
ctx.Then(`^the (response|webhook request|file request|server request) header "([^"]*)" should be "([^"]*)"$`, s.theHeaderValueShouldBe)
ctx.Then(`^the (response|webhook request|file request|server request) cookie "([^"]*)" should be "([^"]*)"$`, s.theCookieValueShouldBe)
ctx.Then(`^the (response|webhook request) body should match string:$`, s.theBodyShouldMatchString)
ctx.Then(`^the (response|webhook request) body should contain string:$`, s.theBodyShouldContainString)
ctx.Then(`^the (response|webhook request) body should match JSON:$`, s.theBodyShouldMatchJSON)
ctx.Then(`^there should be (\d+) PDF\(s\) in the (response|webhook request)$`, s.thereShouldBePdfs)
ctx.Then(`^there should be the following file\(s\) in the (response|webhook request):$`, s.thereShouldBeTheFollowingFiles)
ctx.Then(`^the (response|webhook request) PDF\(s\) should be valid "([^"]*)" with a tolerance of (\d+) failed rule\(s\)$`, s.thePdfsShouldBeValidWithAToleranceOf)
ctx.Then(`^the (response|webhook request) PDF\(s\) (should|should NOT) be flatten$`, s.thePdfsShouldBeFlatten)
ctx.Then(`^the "([^"]*)" PDF should have (\d+) page\(s\)$`, s.thePdfShouldHavePages)
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) be set to landscape orientation$`, s.thePdfShouldBeSetToLandscapeOrientation)
ctx.Then(`^the "([^"]*)" PDF (should|should NOT) have the following content at page (\d+):$`, s.thePdfShouldHaveTheFollowingContentAtPage)
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
if s.gotenbergContainer != nil {
errTerminate := s.gotenbergContainer.Terminate(ctx, testcontainers.StopTimeout(0))
if errTerminate != nil {
return ctx, fmt.Errorf("terminate Gotenberg container: %w", errTerminate)
}
}
if s.gotenbergContainerNetwork != nil {
errRemove := s.gotenbergContainerNetwork.Remove(ctx)
if errRemove != nil {
return ctx, fmt.Errorf("remove Gotenberg container network: %w", errRemove)
}
}
return ctx, nil
})
ctx.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
errReset := s.reset(ctx)
if errReset != nil {
return ctx, fmt.Errorf("reset scenario: %w", errReset)
}
return ctx, nil
})
}

View File

@@ -0,0 +1,176 @@
package scenario
import (
"context"
"errors"
"fmt"
"io"
"mime"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/cucumber/godog"
"github.com/labstack/echo/v4"
"github.com/mholt/archives"
)
type server struct {
srv *echo.Echo
req *http.Request
errChan chan error
}
func newServer(ctx context.Context, workdir string) (*server, error) {
srv := echo.New()
srv.HideBanner = true
srv.HidePort = true
s := &server{
srv: srv,
errChan: make(chan error, 1),
}
wd, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("get current directory: %w", err)
}
webhookErr := func(err error) error {
s.errChan <- err
return err
}
webhookHandler := func(c echo.Context) error {
s.req = c.Request()
body, err := io.ReadAll(s.req.Body)
if err != nil {
return webhookErr(fmt.Errorf("read request body: %w", err))
}
cd := s.req.Header.Get("Content-Disposition")
if cd == "" {
return webhookErr(fmt.Errorf("no Content-Disposition header"))
}
_, params, err := mime.ParseMediaType(cd)
if err != nil {
return webhookErr(fmt.Errorf("parse Content-Disposition header: %w", err))
}
filename, ok := params["filename"]
if !ok {
return webhookErr(errors.New("no filename in Content-Disposition header"))
}
dirPath := fmt.Sprintf("%s/%s", workdir, s.req.Header.Get("Gotenberg-Trace"))
err = os.MkdirAll(dirPath, 0o755)
if err != nil {
return webhookErr(fmt.Errorf("create working directory: %w", err))
}
fpath := fmt.Sprintf("%s/%s", dirPath, filename)
file, err := os.Create(fpath)
if err != nil {
return webhookErr(fmt.Errorf("create file %q: %w", fpath, err))
}
defer file.Close()
_, err = file.Write(body)
if err != nil {
return webhookErr(fmt.Errorf("write file %q: %w", fpath, err))
}
if s.req.Header.Get("Content-Type") == "application/zip" {
var format archives.Zip
err = format.Extract(ctx, file, func(ctx context.Context, f archives.FileInfo) error {
source, err := f.Open()
if err != nil {
return fmt.Errorf("open file %q: %w", f.Name(), err)
}
defer source.Close()
targetPath := fmt.Sprintf("%s/%s", dirPath, f.Name())
target, err := os.Create(targetPath)
if err != nil {
return fmt.Errorf("create file %q: %w", targetPath, err)
}
defer target.Close()
_, err = io.Copy(target, source)
if err != nil {
return fmt.Errorf("copy file %q: %w", targetPath, err)
}
return nil
})
if err != nil {
return webhookErr(err)
}
}
return webhookErr(c.String(http.StatusOK, http.StatusText(http.StatusOK)))
}
webhookErrorHandler := func(c echo.Context) error {
s.req = c.Request()
return webhookErr(c.String(http.StatusOK, http.StatusText(http.StatusOK)))
}
srv.POST("/webhook", webhookHandler)
srv.PATCH("/webhook", webhookHandler)
srv.PUT("/webhook", webhookHandler)
srv.POST("/webhook/error", webhookErrorHandler)
srv.PATCH("/webhook/error", webhookErrorHandler)
srv.PUT("/webhook/error", webhookErrorHandler)
srv.GET("/static/:path", func(c echo.Context) error {
s.req = c.Request()
path := c.Param("path")
if strings.Contains(path, "teststore") {
return c.Attachment(fmt.Sprintf("%s/%s/%s", workdir, s.req.Header.Get("Gotenberg-Trace"), filepath.Base(path)), filepath.Base(path))
}
return c.Attachment(fmt.Sprintf("%s/%s", wd, path), filepath.Base(path))
})
srv.GET("/html/:path", func(c echo.Context) error {
s.req = c.Request()
path := fmt.Sprintf("%s/%s", wd, c.Param("path"))
f, err := os.Open(path)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("open file %q: %s", path, err))
}
defer f.Close()
b, err := io.ReadAll(f)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("read file %q: %s", path, err))
}
return c.HTML(http.StatusOK, string(b))
})
return s, nil
}
func (s *server) start(ctx context.Context) (int, error) {
// #nosec
ln, err := net.Listen("tcp", "0.0.0.0:0")
if err != nil {
return 0, fmt.Errorf("create listener: %w", err)
}
port := ln.Addr().(*net.TCPAddr).Port
go func() {
s.srv.Listener = ln
err = s.srv.Start("")
if err != nil && !errors.Is(err, http.ErrServerClosed) {
godog.Log(ctx, err.Error())
}
}()
return port, nil
}
func (s *server) stop(ctx context.Context) error {
close(s.errChan)
return s.srv.Shutdown(ctx)
}

View File

@@ -0,0 +1,64 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- net::ERR_CONNECTION_REFUSED -->
<link
rel="stylesheet"
type="text/css"
href="http://localhost:100/style.css"
/>
<title>Feature Rich HTML</title>
<style>
@media print {
#screen {
display: none;
}
}
@media screen {
#print {
display: none;
}
}
</style>
</head>
<body>
<p id="wait" style="display: none">
Wait delay > 2 seconds or expression window globalVar === 'ready' returns
true.
</p>
<p id="print">Emulated media type is 'print'.</p>
<p id="screen">Emulated media type is 'screen'.</p>
<p id="javascript" style="display: none">JavaScript is enabled.</p>
<iframe src="file:///etc/passwd"></iframe>
<script type="application/javascript">
var globalVar = "notReady";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
delay(2000).then(() => {
document.getElementById("wait").style.display = "contents";
window.globalVar = "ready";
});
</script>
<script type="application/javascript">
document.getElementById("javascript").style.display = "contents";
</script>
<script type="application/javascript">
console.log("a simple message");
console.debug("a debug message");
console.warn("a warning message");
console.error("an error message");
</script>
<script type="application/javascript">
throw new Error("Exception 1");
</script>
<script type="application/javascript">
throw new Error("Exception 2");
</script>
</body>
</html>

View File

@@ -0,0 +1,69 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- net::ERR_FILE_NOT_FOUND -->
<link rel="stylesheet" type="text/css" href="doesnotexist.css" />
<!-- net::ERR_CONNECTION_REFUSED -->
<link
rel="stylesheet"
type="text/css"
href="http://localhost:100/style.css"
/>
<!-- 400 Bad Request -->
<link rel="stylesheet" type="text/css" href="https://httpstat.us/400" />
<title>Feature Rich HTML</title>
<style>
@media print {
#screen {
display: none;
}
}
@media screen {
#print {
display: none;
}
}
</style>
</head>
<body>
<p id="wait" style="display: none">
Wait delay > 2 seconds or expression window globalVar === 'ready' returns
true.
</p>
<p id="print">Emulated media type is 'print'.</p>
<p id="screen">Emulated media type is 'screen'.</p>
<p id="javascript" style="display: none">JavaScript is enabled.</p>
<iframe src="/etc/passwd"></iframe>
<iframe src="\\localhost/etc/passwd"></iframe>
<script type="application/javascript">
var globalVar = "notReady";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
delay(2000).then(() => {
document.getElementById("wait").style.display = "contents";
window.globalVar = "ready";
});
</script>
<script type="application/javascript">
document.getElementById("javascript").style.display = "contents";
</script>
<script type="application/javascript">
console.log("a simple message");
console.debug("a debug message");
console.warn("a warning message");
console.error("an error message");
</script>
<script type="application/javascript">
throw new Error("Exception 1");
</script>
<script type="application/javascript">
throw new Error("Exception 2");
</script>
</body>
</html>

View File

@@ -0,0 +1,70 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- net::ERR_FILE_NOT_FOUND -->
<link rel="stylesheet" type="text/css" href="doesnotexist.css" />
<!-- net::ERR_CONNECTION_REFUSED -->
<link
rel="stylesheet"
type="text/css"
href="http://localhost:100/style.css"
/>
<!-- 400 Bad Request -->
<link rel="stylesheet" type="text/css" href="https://httpstat.us/400" />
<title>Feature Rich HTML</title>
<style>
@media print {
#screen {
display: none;
}
}
@media screen {
#print {
display: none;
}
}
</style>
</head>
<body>
{{ toHTML "table.md" }}
<p id="wait" style="display: none">
Wait delay > 2 seconds or expression window globalVar === 'ready' returns
true.
</p>
<p id="print">Emulated media type is 'print'.</p>
<p id="screen">Emulated media type is 'screen'.</p>
<p id="javascript" style="display: none">JavaScript is enabled.</p>
<iframe src="/etc/passwd"></iframe>
<iframe src="\\localhost/etc/passwd"></iframe>
<script type="application/javascript">
var globalVar = "notReady";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
delay(2000).then(() => {
document.getElementById("wait").style.display = "contents";
window.globalVar = "ready";
});
</script>
<script type="application/javascript">
document.getElementById("javascript").style.display = "contents";
</script>
<script type="application/javascript">
console.log("a simple message");
console.debug("a debug message");
console.warn("a warning message");
console.error("an error message");
</script>
<script type="application/javascript">
throw new Error("Exception 1");
</script>
<script type="application/javascript">
throw new Error("Exception 2");
</script>
</body>
</html>

View File

@@ -0,0 +1,7 @@
## This paragraph displays a table from a markdown file
| Tables | Are | Cool |
| -------- | :-----------: | ----: |
| col 1 is | left-aligned | $1600 |
| col 2 is | centered | $12 |
| col 3 is | right-aligned | $1 |

View File

@@ -0,0 +1,13 @@
<html>
<head>
<style>
body {
font-size: 12px;
margin: auto 20px;
}
</style>
</head>
<body>
<p><span class="pageNumber"></span> of <span class="totalPages"></span></p>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<html>
<head>
<style>
body {
font-size: 12px;
margin: auto 20px;
}
</style>
</head>
<body>
<span class="title"></span>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<!doctype html>
<html lang="en">
<head>
<title>Page 1</title>
</head>
<body>
<h1>Page 1</h1>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<!doctype html>
<html lang="en">
<head>
<title>Page 1</title>
</head>
<body>
{{ toHTML "page_1.md" }}
</body>
</html>

View File

@@ -0,0 +1 @@
# Page 1

BIN
test/integration/testdata/page_1.docx vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/page_1.pdf vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/page_2.docx vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/page_2.pdf vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,25 @@
<!doctype html>
<html lang="en">
<head>
<title>Pages 12</title>
<style>
.page-break-after {
page-break-after: always;
}
</style>
</head>
<body>
<h1 class="page-break-after">Page 1</h1>
<h1 class="page-break-after">Page 2</h1>
<h1 class="page-break-after">Page 3</h1>
<h1 class="page-break-after">Page 4</h1>
<h1 class="page-break-after">Page 5</h1>
<h1 class="page-break-after">Page 6</h1>
<h1 class="page-break-after">Page 7</h1>
<h1 class="page-break-after">Page 8</h1>
<h1 class="page-break-after">Page 9</h1>
<h1 class="page-break-after">Page 10</h1>
<h1 class="page-break-after">Page 11</h1>
<h1 class="page-break-after">Page 12</h1>
</body>
</html>

View File

@@ -0,0 +1,25 @@
<!doctype html>
<html lang="en">
<head>
<title>Pages 12</title>
<style>
.page-break-after {
page-break-after: always;
}
</style>
</head>
<body>
<div class="page-break-after">{{ toHTML "page_1.md" }}</div>
<div class="page-break-after">{{ toHTML "page_2.md" }}</div>
<div class="page-break-after">{{ toHTML "page_3.md" }}</div>
<div class="page-break-after">{{ toHTML "page_4.md" }}</div>
<div class="page-break-after">{{ toHTML "page_5.md" }}</div>
<div class="page-break-after">{{ toHTML "page_6.md" }}</div>
<div class="page-break-after">{{ toHTML "page_7.md" }}</div>
<div class="page-break-after">{{ toHTML "page_8.md" }}</div>
<div class="page-break-after">{{ toHTML "page_9.md" }}</div>
<div class="page-break-after">{{ toHTML "page_10.md" }}</div>
<div class="page-break-after">{{ toHTML "page_11.md" }}</div>
<div class="page-break-after">{{ toHTML "page_12.md" }}</div>
</body>
</html>

View File

@@ -0,0 +1 @@
# Page 1

View File

@@ -0,0 +1 @@
# Page 10

View File

@@ -0,0 +1 @@
# Page 11

View File

@@ -0,0 +1 @@
# Page 12

View File

@@ -0,0 +1 @@
# Page 2

View File

@@ -0,0 +1 @@
# Page 3

View File

@@ -0,0 +1 @@
# Page 4

View File

@@ -0,0 +1 @@
# Page 5

View File

@@ -0,0 +1 @@
# Page 6

View File

@@ -0,0 +1 @@
# Page 7

View File

@@ -0,0 +1 @@
# Page 8

View File

@@ -0,0 +1 @@
# Page 9

View File

@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<title>Pages 3</title>
<style>
.page-break-after {
page-break-after: always;
}
</style>
</head>
<body>
<h1 class="page-break-after">Page 1</h1>
<h1 class="page-break-after">Page 2</h1>
<h1 class="page-break-after">Page 3</h1>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<title>Pages 3</title>
<style>
.page-break-after {
page-break-after: always;
}
</style>
</head>
<body>
<div class="page-break-after">{{ toHTML "page_1.md" }}</div>
<div class="page-break-after">{{ toHTML "page_2.md" }}</div>
<div class="page-break-after">{{ toHTML "page_3.md" }}</div>
</body>
</html>

View File

@@ -0,0 +1 @@
# Page 1

View File

@@ -0,0 +1 @@
# Page 2

View File

@@ -0,0 +1 @@
# Page 3

BIN
test/integration/testdata/pages_12.docx vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/pages_12.pdf vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/pages_3.docx vendored Normal file

Binary file not shown.

BIN
test/integration/testdata/pages_3.pdf vendored Normal file

Binary file not shown.

14
test/integration/testdata/pem/README.md vendored Normal file
View File

@@ -0,0 +1,14 @@
To generate a valid certificate and private key use the following command:
```bash
# In OpenSSL ≥ 1.1.1
openssl req -x509 -newkey rsa:4096 -sha256 -days 9999 -nodes \
-keyout key.pem -out cert.pem -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:::1"
```
To check a certificate use the following command:
```bash
openssl x509 -in cert.pem -text
```

30
test/integration/testdata/pem/cert.pem vendored Normal file
View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFOjCCAyKgAwIBAgIUZaht2QoZwWDK8wEuwm+wmip9sqwwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI0MDUyNjA1MDExNFoYDzIwNTEx
MDExMDUwMTE0WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCm3TNckD55ae6pxXS03iV2P3X/edZT4vRa8D15elsi
CSRf6mdU2TVAQyg22GEcMXgsbba7sotJVg7559LkWAgb3Dj9rbPputdS29ebncat
x1nzo1QHMCS/v7nWoPe9fQVlDEf3ebM198f+5vhccSYFxFa+YvsUmSw9yMF8z1nA
6POZTpm6ErByAY9EGvC8EcNOQd9xLOfBZc0e+mY/rMRxmL+0N+sSRE/ACU+2zxHN
KcCiFX5WQdLDYW1ZjX5xAVatCPNlxSQpj97/ktGsnqwGnJWSTeMUOPv7L0LrQasf
k1VXBvfTW2/ZqhI9WA8qfdC5XOuzVwfU14gv+6vv9AGZnUFmOjeo9XG4xWBxlIKj
AQAzeNwAGFltPkp5a3yPczxMjKY4xLsMGcDfpaNtv1B24+7fV77Nyty/gLLT9pUa
FtXLuRfIPSaUK3kFhAuYzGUL/sO9O9jJkNlxxygxQ+VyIgmdw0zWrUi3q+Lfmdya
FFjHdM7LnLrLCjSv3dEoMINngR3+IejsY+98Ehd25O3oW+ZnGIQX0VwykV8sOQWq
rpnnZ+2iHMtF6Vsj40z/Y9y7yVE18AIJFC+Yr/dD/nQyg6SE70wdNcOx0Ay1xHbP
WuV3fqKOfhONR7NEBSO2UbHi6GZAiYMMwwul+4yKAQ4+lHOEXG4JQcKvtZasxq9v
GwIDAQABo4GBMH8wHQYDVR0OBBYEFPPMaH3C0rAkD/E0gtBZwM0x8N9MMB8GA1Ud
IwQYMBaAFPPMaH3C0rAkD/E0gtBZwM0x8N9MMA8GA1UdEwEB/wQFMAMBAf8wLAYD
VR0RBCUwI4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqG
SIb3DQEBCwUAA4ICAQB0DXz59JfQgfJvRJfraa+Cv/3nG4NNmHYtNGhrid5sagH3
LM8jkbA+JKRAn34SmsqUZb1f2XFI64TwrScgMfAvfi+5ibRqBjM/YL06bTlG61Ua
t2IQchV2kcX4zQnaMCIYG0dUj6JoXIspiFULMHyGDs7G9BKVcZxlaLrEvPXBqQjd
nwF80KHS/rCConmICU9uWHPgHxS1VmhQiwYGbrakETilau1ppRS0bpH2k/stVyjc
plttIr1DUD6xaRV4mZ0NZVlIXl2nDf78iQvreJeMrGl6AcNHzV+/rGHpY/gOrziP
PQkB1VtSiHtBe/VMKXcVB69SEzsoGEknqs4GPXuVYm47POo3/U5HmGU+FadSATNP
qtorRECUMbVn0IfDzJX2jBLUjZlhPI9gqO9DhiAT8FWHRV2yPsZKuiBBg5/hUvyb
Qsswtmi/YV5e6AnXEuvylwE3wYzlqDzxwlZM08bWFyZYnSf38d3hAjVwUHAugiaX
4sgE6GPAiONW5FkTZ4Z2oXYiN213QDIIcQeFAl04qSEFkGBV8x2hM0uXgFH1S++j
JePdKBbV/CjxegyyYsmnln+eO1kC8pCalB6k6pEtYMqNYOnmimC8UKrJATrH9EVq
eAehGBiIe514Oz06Ws2Vm4PTiY2x0KVbqphwkuz85ohSF9UXOHUcMryusr1zlg==
-----END CERTIFICATE-----

52
test/integration/testdata/pem/key.pem vendored Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCm3TNckD55ae6p
xXS03iV2P3X/edZT4vRa8D15elsiCSRf6mdU2TVAQyg22GEcMXgsbba7sotJVg75
59LkWAgb3Dj9rbPputdS29ebncatx1nzo1QHMCS/v7nWoPe9fQVlDEf3ebM198f+
5vhccSYFxFa+YvsUmSw9yMF8z1nA6POZTpm6ErByAY9EGvC8EcNOQd9xLOfBZc0e
+mY/rMRxmL+0N+sSRE/ACU+2zxHNKcCiFX5WQdLDYW1ZjX5xAVatCPNlxSQpj97/
ktGsnqwGnJWSTeMUOPv7L0LrQasfk1VXBvfTW2/ZqhI9WA8qfdC5XOuzVwfU14gv
+6vv9AGZnUFmOjeo9XG4xWBxlIKjAQAzeNwAGFltPkp5a3yPczxMjKY4xLsMGcDf
paNtv1B24+7fV77Nyty/gLLT9pUaFtXLuRfIPSaUK3kFhAuYzGUL/sO9O9jJkNlx
xygxQ+VyIgmdw0zWrUi3q+LfmdyaFFjHdM7LnLrLCjSv3dEoMINngR3+IejsY+98
Ehd25O3oW+ZnGIQX0VwykV8sOQWqrpnnZ+2iHMtF6Vsj40z/Y9y7yVE18AIJFC+Y
r/dD/nQyg6SE70wdNcOx0Ay1xHbPWuV3fqKOfhONR7NEBSO2UbHi6GZAiYMMwwul
+4yKAQ4+lHOEXG4JQcKvtZasxq9vGwIDAQABAoICAA3s7URkT/0XTMZOUZcRPanI
p12oGq2Vhd8GUvBjDbKhdgUAgu8fJsUzgD+o1Ic4eaxQ26x+Z1wPb+CF6vZeLQ8Q
1JDB1lSYiy/BuRSmQ4EX30yTQjKiCe8Ws7j9u1nM/Tju9XKUbX2rgr1QeURTDQvz
fr8UyO9xzly5oawmLHoKTDTBzS0s3Md8Pys9NFSoXCxDwxSm3WXTy8fcuHvH51Je
SmFik/OfpSgu9BVwN9lvX+wm7wwzzMBmzmwS1Y0zbLsJbDFUv9fYHJF8/JKeC1fh
6Xme67yG+kB+3o7TmXxhHKt5TBAPfsjOMLIojzDJ9IlY/91PqLpSjRhetdKorRlf
gvTUGLPY8lHXwz6UBpdHmMhNHTBBvgHcOVAMD46Y81SdqMhH6TAYSh7XQVuA06Ql
MTWzGqzKriaQDWmJ6Nx8eZCRDZGXDq4rKiJFvRFUrGYYr818qU8yC+qv5uLrOF1w
YZV0WnZ7DtcaFliBrJVUfeTmrSJBa3yoIKbeaTDuh3TMHqgAbTx0lBdGoI6noRxx
v7fCGho/aSOJ2rtFOjRoLQ5K8onZ226arJEyfkTh16wztQgh9DC430OkL4cQkfA0
BxN8tGh4P0lqwcBnCOyzi4NV1NkwaaVv+pt757Cz+Cy6e2DQOtDkrFEh4p56NqDr
KcJz88LYbbChoFKlb/kBAoIBAQDhcuI0KWTErojWu/dB2Okth8OFaTdvAPEvo+qO
ItJgxyYL8JIdWUzS9vKro6vMctwIXvNa3K2AAwdZ1kHvaxDZaikQbnjnSjOqRlZa
4rVnI6SSKrYj6xmKcsxxTi9YP8b2msjdLuGhPfO8Dw4EQgOt6xg0rq4msnv6bYki
G7vsk/InnKLm8SEhR1XsmtVrpC7KbXniLQEehgs1Kp0nMLptSsOTnA1kGoZDVlXc
u+kBBai6MM0MMDpsJgM1IFkUousQl3ItBcTXD2ZCMcg5psQJbdEhu7oXiGkHdKlL
1UEIdSGNlzHiVM62uNxhNfwh7I6SPesDksJbE0Yd//jz/7FRAoIBAQC9ee+pDsSs
yqunQjMWImTpD5h9fSRTzWT8h0dXsJyYi7s9Dj4mQIuoarscMI6L7njeTqHE8ptc
b9DzIEWL+233nTOS59grCTD84Kyrn+Hw6EebgKYmtpZnvMw5cccoZ3qUsxVGurhA
lzVaKpHtPKWT1fduNmnqt6RkZ7aRBLZre/i9UntZ7VSZYRKMOBvJLpLdqmiSPkvM
w8ra+cedHwDegqLkoX0sxdI1yNYO1GSkJ+w1I1m1rzuCd9X5QXvyQhPezVB9wUwr
anNGb6/YgvthzvMQAXYqv4pmb769przieMJ6geQL3O8QEtvpDAV4SvrwnA+H/wfs
BvwI4MTHNJ6rAoIBADEfnzpOaq6QeTCQ9GdcpDJPisLfEj0Vr3f593nRDJYZzqh7
WtsaQisVs/rCRwTdYiRQzCXYP9XM0yU4ElXgtmMpRplV+PIssOVBPj+/dldq5MkU
lWtuJrqMGQ/3QUmxW+EQCQRo2rEPlrQ7c4pp9/NFbpjMFxZHfcwrYd4UvPXnprQK
5VP85oMh0A8mDarOs4NYJ16o/71u57JF/sgzTevShpr7Pc+6F9dEUKEwMK0QVpt7
VrJ5L8Gw5rIEwmREu4N5/F7jCujxag6yWjZ1p/GGBDOdfAb0qi39tYXYibsWCqGX
eD8gy4n07dAguzeJG+expiu5JrBBmt2ekNhZtoECggEAQ90VoraAaOcaPgju5UGi
ZPtKAcA9r6pEPlJxkg3WuKhrgr3EMs0xeDvqEnmtxJ7AOdduB21hieUesMXhQvbl
9ycd3sMdYKSlIB2Ums/kC/YWF7MnT3xcOIGdoAGJdIZDmFjgCPo9nhzKZiYTKCZt
o5qiSZ5Bp2jo/3FKKXzHnY3ElIKjXZ0sjNcA3qoGAbOltLEhTSf03D1QPcfy3+rH
0+p0T3ErtUqRNORfDuaxuT33Uzz7F6DQrrUfNWxn6WgTV9yvtKr0DiTNbu/3ypN3
WBvYYOY1HbCG8JObfK/ovTDFbz1woXMbSOWIUFsW5nPslxs+UNZeTwJdaQygTj0h
iwKCAQBuXOPtjWGZINgfjo/n67Q8FuzUXxDK/IuXzuDXhi+B3/O3/PcVEDHFByhI
KHOh2mTD25vgFWh+8dNg1R+m5uIeQ5zbZ5U0205XzmrZgBXXCAHKNruTwqZfQ6er
np+8wHhcCbBuy0Z0ponzBGlrDYmbxO9anXGxoe/rE3+pWbzMneZ+cHgNjXCtfZCY
XGfLeJWW3+B8y5Lff39ADawmjm8VWVEdd8DP5o2zulbXhgMMnAsSVsR/XgwBqpbf
82k1bqvN2v08ID5nmTRdzD+D51Hjw80Uoqhm5DJL4IwaoK/YstCu2TCbmLGiyqSk
lrSOZMPTLX1tN/cWa+Ii+/WALnkI
-----END PRIVATE KEY-----

Binary file not shown.

View File