From 8899df0d9219ce21c104eacce62d61f0e839c0b7 Mon Sep 17 00:00:00 2001 From: Julius Knorr Date: Tue, 10 Sep 2024 15:46:47 +0200 Subject: [PATCH] tests: Add integration tests for form extract/filling Signed-off-by: Julius Knorr --- .github/workflows/integration.yml | 8 +- REUSE.toml | 2 +- tests/config/behat.yml | 1 + tests/data/form.odt | Bin 0 -> 28599 bytes tests/features/api.feature | 43 +++++++ tests/features/bootstrap/ApiContext.php | 142 ++++++++++++++++++++++++ 6 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 tests/data/form.odt create mode 100644 tests/features/api.feature create mode 100644 tests/features/bootstrap/ApiContext.php diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ff6e997d26..161fbe0b1c 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -55,7 +55,7 @@ jobs: php-versions: ['8.1'] databases: ['sqlite'] server-versions: ['master'] - scenarios: ['wopi', 'direct', 'federation'] + scenarios: ['wopi', 'direct', 'federation', 'api'] name: integration-${{ matrix.code-image }}-${{ matrix.scenarios }}-${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }} @@ -127,7 +127,7 @@ jobs: php-versions: ['8.1'] databases: ['mysql'] server-versions: ['master'] - scenarios: ['wopi', 'direct', 'federation'] + scenarios: ['wopi', 'direct', 'federation', 'api'] name: integration-${{ matrix.scenarios }}-${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }} @@ -206,7 +206,7 @@ jobs: php-versions: ['8.1'] databases: ['pgsql'] server-versions: ['master'] - scenarios: ['wopi', 'direct', 'federation'] + scenarios: ['wopi', 'direct', 'federation', 'api'] name: integration-${{ matrix.scenarios }}-${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }} @@ -287,7 +287,7 @@ jobs: php-versions: ['8.1'] databases: ['oci'] server-versions: ['master'] - scenarios: ['wopi', 'direct', 'federation'] + scenarios: ['wopi', 'direct', 'federation', 'api'] name: integration-${{ matrix.scenarios }}-${{ matrix.php-versions }}-${{ matrix.databases }}-${{ matrix.server-versions }} diff --git a/REUSE.toml b/REUSE.toml index 18fc90295f..a269540dfc 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -18,7 +18,7 @@ SPDX-FileCopyrightText = "2016 Nextcloud contributors" SPDX-License-Identifier = "AGPL-3.0-or-later" [[annotations]] -path = ["js/**.js.map", "js/**.js", "js/**.mjs", "js/**.mjs.map", "js/templates/**.handlebars", "emptyTemplates/**", "cypress/fixtures/**", "tests/features/**.feature", "tests/psalm-baseline.xml"] +path = ["js/**.js.map", "js/**.js", "js/**.mjs", "js/**.mjs.map", "js/templates/**.handlebars", "emptyTemplates/**", "cypress/fixtures/**", "tests/data/**", "tests/features/**.feature", "tests/psalm-baseline.xml"] precedence = "aggregate" SPDX-FileCopyrightText = "2016 Nextcloud GmbH and Nextcloud contributors" SPDX-License-Identifier = "AGPL-3.0-or-later" diff --git a/tests/config/behat.yml b/tests/config/behat.yml index 9875d8e7c3..66f5a9111e 100644 --- a/tests/config/behat.yml +++ b/tests/config/behat.yml @@ -21,6 +21,7 @@ default: - WopiContext - DirectContext - FederationContext + - ApiContext extensions: diff --git a/tests/data/form.odt b/tests/data/form.odt new file mode 100644 index 0000000000000000000000000000000000000000..42496f8560dd97d2a8786ca98731795dcf90170f GIT binary patch literal 28599 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 literal 0 HcmV?d00001 diff --git a/tests/features/api.feature b/tests/features/api.feature new file mode 100644 index 0000000000..0852d3a7d6 --- /dev/null +++ b/tests/features/api.feature @@ -0,0 +1,43 @@ +Feature: API + + Background: + Given user "user1" exists + + Scenario: Extract field values + Given as user "user1" + And User "user1" uploads file "./data/form.odt" to "/form.odt" + Then User "user1" requests the form field data of "/form.odt" + And the response contains the field "Name of the Organizer/Organization" + And the response contains the field "Road closures - Length of road closures (in meters)" + + Scenario: Extract field values and fill in field + Given as user "user1" + And User "user1" uploads file "./data/form.odt" to "/form.odt" + Then User "user1" requests the form field data of "/form.odt" + And the response contains the field "Name of the Organizer/Organization" + And the response contains the field "Road closures - Length of road closures (in meters)" + Then User "user1" fills in fields of "/form.odt" with values as "odt" to "/filled.odt" + | ContentControls.ByIndex.19 | 100 | + Then User "user1" requests the form field data of "/filled.odt" + And the response contains the field "Road closures - Length of road closures (in meters)" with "100" + And the resulting file is a "application/vnd.oasis.opendocument.text" + + Scenario: Extract field values and fill in field as pdf + Given as user "user1" + And User "user1" uploads file "./data/form.odt" to "/form.odt" + Then User "user1" requests the form field data of "/form.odt" + And the response contains the field "Name of the Organizer/Organization" + And the response contains the field "Road closures - Length of road closures (in meters)" + Then User "user1" fills in fields of "/form.odt" with values as "pdf" to "/filled.pdf" + | ContentControls.ByIndex.19 | 100 | + And the resulting file is a "application/pdf" + + Scenario: Extract field values and fill in field as pdf + Given as user "user1" + And User "user1" uploads file "./data/form.odt" to "/form.odt" + Then User "user1" requests the form field data of "/form.odt" + And the response contains the field "Name of the Organizer/Organization" + And the response contains the field "Road closures - Length of road closures (in meters)" + Then User "user1" fills in fields of "/form.odt" with values as "pdf" + | ContentControls.ByIndex.19 | 100 | + And the resulting file is a "application/pdf" diff --git a/tests/features/bootstrap/ApiContext.php b/tests/features/bootstrap/ApiContext.php new file mode 100644 index 0000000000..465b971312 --- /dev/null +++ b/tests/features/bootstrap/ApiContext.php @@ -0,0 +1,142 @@ +getEnvironment(); + $this->serverContext = $environment->getContext(ServerContext::class); + $this->filesContext = $environment->getContext(FilesContext::class); + } + + /** + * @Then /^User "([^"]*)" requests the form field data of "([^"]*)"$/ + */ + public function userRequestsTheFormFieldData($user, $filePath) { + $davClient = $this->filesContext->getSabreClient($user); + $davPath = $this->filesContext->makeSabrePath($user, $filePath); + $result = $davClient->propFind($davPath, ['{http://owncloud.org/ns}fileid']); + $fileId = $result['{http://owncloud.org/ns}fileid']; + $this->serverContext->sendOCSRequest('GET', 'apps/richdocuments/api/v1/template/fields/extract/' . $fileId); + + $body = (string)$this->serverContext->getResponse()->getBody(); + ; + $this->extractResult = json_decode($body, true); + + $this->serverContext->assertHttpStatusCode(200); + } + + /** + * @Given /^the response contains the field "([^"]*)"$/ + */ + public function theResponseContainsTheField($arg1) { + $found = false; + foreach ($this->extractResult['ocs']['data'] as $index => $field) { + if ($field['alias'] === $arg1) { + $found = true; + } + } + Assert::assertTrue($found, 'Field was not found'); + } + + /** + * @Then /^User "([^"]*)" fills in fields of "([^"]*)" with values as "([^"]*)" to "([^"]*)"$/ + */ + public function userFillsInFieldsOfWithValuesAsTo($user, $source, ?string $convert = null, ?string $target = null, ?TableNode $table = null) { + $davClient = $this->filesContext->getSabreClient($user); + $davPath = $this->filesContext->makeSabrePath($user, $source); + $result = $davClient->propFind($davPath, ['{http://owncloud.org/ns}fileid']); + $fileId = $result['{http://owncloud.org/ns}fileid']; + + $formData = []; + foreach ($table->getRows() as $row) { + $formData[$row[0]] = [ + 'content' => $row[1], + ]; + } + + $this->serverContext->sendOCSRequest('POST', 'apps/richdocuments/api/v1/template/fields/fill/' . $fileId . '?' + . ($convert ? '&convert=' . $convert : '') + . ($target ? '&destination=' . $target : ''), ['fields' => $formData]); + + $this->serverContext->assertHttpStatusCode(200); + + if ($target === null) { + file_put_contents('data/output.pdf', $this->serverContext->getResponse()->getBody()); + } else { + $this->serverContext->sendRawRequest('GET', '/remote.php/dav/files/' . $user . '/' . $target); + file_put_contents('data/output.pdf', $this->serverContext->getResponse()->getBody()); + } + } + + /** + * @Given /^the response contains the field "([^"]*)" with "([^"]*)"$/ + */ + public function theResponseContainsTheFieldWith($arg1, $arg2) { + $found = false; + foreach ($this->extractResult['ocs']['data'] as $index => $field) { + if ($field['alias'] === $arg1) { + Assert::assertEquals($arg2, $field['content']); + $found = true; + } + } + Assert::assertTrue($found, 'Field was not found'); + } + + /** + * @Then /^User "([^"]*)" fills in fields of "([^"]*)" with values as "([^"]*)"$/ + */ + public function userFillsInFieldsOfWithValuesAs($arg1, $arg2, $arg3, TableNode $table) { + $this->userFillsInFieldsOfWithValuesAsTo($arg1, $arg2, $arg3, null, $table); + } + + /** + * @Then /^User "([^"]*)" downloads the file and compares it with the baseline$/ + */ + public function userDownloadsTheFile($arg1) { + $this->serverContext->setCurrentUser($arg1); + $this->serverContext->sendRawRequest('GET', '/remote.php/dav/files/' . $arg1 . '/filled.pdf'); + file_put_contents('data/output.pdf', $this->serverContext->getResponse()->getBody()); + + Assert::assertEquals( + sha1_file('data/filled.pdf'), + sha1_file('data/output.pdf'), + ); + } + + /** + * @Given /^the resulting file is a "([^"]*)"$/ + */ + public function theResultingFileIsA($mimetype) { + $filetype = mime_content_type('data/output.pdf'); + Assert::assertEquals($mimetype, $filetype); + } + + /** + * @Then /^compares the returned file with the baseline$/ + */ + public function comparesTheReturnedFileWithTheBaseline() { + file_put_contents('data/output.pdf', $this->serverContext->getResponse()->getBody()); + + Assert::assertEquals( + sha1_file('data/filled.pdf'), + sha1_file('data/output.pdf'), + ); + } +}