diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bac1d0ffa3..4d3a0dd0ba 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -55,7 +55,7 @@ jobs: php-versions: ['8.1'] databases: ['sqlite'] server-versions: ['stable30'] - 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: ['stable30'] - 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: ['stable30'] - 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: ['stable30'] - 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 0000000000..42496f8560 Binary files /dev/null and b/tests/data/form.odt differ 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'), + ); + } +}