Integration tests for search

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2021-04-12 08:07:53 +02:00
parent c960d21b37
commit a6c4912bff
8 changed files with 510 additions and 47 deletions

View File

@@ -5,10 +5,7 @@ default:
- '%paths.base%/../features/'
contexts:
- ServerContext:
baseUrl: http://localhost:8080/index.php/ocs/
admin:
- admin
- admin
regular_user_password: 123456
- BoardContext:
baseUrl: http://localhost:8080/
- RequestContext
- BoardContext
- SearchContext

View File

@@ -1,6 +1,7 @@
<?php
use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Gherkin\Node\TableNode;
use PHPUnit\Framework\Assert;
@@ -16,25 +17,35 @@ class BoardContext implements Context {
/** @var array last card response */
private $card = null;
/** @var ServerContext */
private $serverContext;
/** @BeforeScenario */
public function gatherContexts(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();
$this->serverContext = $environment->getContext('ServerContext');
}
/**
* @Given /^creates a board named "([^"]*)" with color "([^"]*)"$/
*/
public function createsABoardNamedWithColor($title, $color) {
$this->sendJSONrequest('POST', '/index.php/apps/deck/boards', [
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/boards', [
'title' => $title,
'color' => $color
]);
$this->response->getBody()->seek(0);
$this->board = json_decode((string)$this->response->getBody(), true);
$this->getResponse()->getBody()->seek(0);
$this->board = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
* @When /^fetches the board named "([^"]*)"$/
*/
public function fetchesTheBoardNamed($boardName) {
$this->sendJSONrequest('GET', '/index.php/apps/deck/boards/' . $this->board['id'], []);
$this->response->getBody()->seek(0);
$this->board = json_decode((string)$this->response->getBody(), true);
$this->requestContext->sendJSONrequest('GET', '/index.php/apps/deck/boards/' . $this->board['id'], []);
$this->getResponse()->getBody()->seek(0);
$this->board = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
@@ -48,7 +59,7 @@ class BoardContext implements Context {
];
$tableRows = isset($permissions) ? $permissions->getRowsHash() : [];
$result = array_merge($defaults, $tableRows);
$this->sendJSONrequest('POST', '/index.php/apps/deck/boards/' . $this->board['id'] . '/acl', [
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/boards/' . $this->board['id'] . '/acl', [
'type' => 0,
'participant' => $user,
'permissionEdit' => $result['permissionEdit'] === '1',
@@ -68,7 +79,7 @@ class BoardContext implements Context {
];
$tableRows = isset($permissions) ? $permissions->getRowsHash() : [];
$result = array_merge($defaults, $tableRows);
$this->sendJSONrequest('POST', '/index.php/apps/deck/boards/' . $this->board['id'] . '/acl', [
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/boards/' . $this->board['id'] . '/acl', [
'type' => 1,
'participant' => $group,
'permissionEdit' => $result['permissionEdit'] === '1',
@@ -82,38 +93,38 @@ class BoardContext implements Context {
* @When /^fetching the board list$/
*/
public function fetchingTheBoardList() {
$this->sendJSONrequest('GET', '/index.php/apps/deck/boards');
$this->requestContext->sendJSONrequest('GET', '/index.php/apps/deck/boards');
}
/**
* @When /^fetching the board with id "([^"]*)"$/
*/
public function fetchingTheBoardWithId($id) {
$this->sendJSONrequest('GET', '/index.php/apps/deck/boards/' . $id);
$this->requestContext->sendJSONrequest('GET', '/index.php/apps/deck/boards/' . $id);
}
/**
* @Given /^create a stack named "([^"]*)"$/
*/
public function createAStackNamed($name) {
$this->sendJSONrequest('POST', '/index.php/apps/deck/stacks', [
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/stacks', [
'title' => $name,
'boardId' => $this->board['id']
]);
$this->response->getBody()->seek(0);
$this->stack = json_decode((string)$this->response->getBody(), true);
$this->requestContext->getResponse()->getBody()->seek(0);
$this->stack = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
* @Given /^create a card named "([^"]*)"$/
*/
public function createACardNamed($name) {
$this->sendJSONrequest('POST', '/index.php/apps/deck/cards', [
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/cards', [
'title' => $name,
'stackId' => $this->stack['id']
]);
$this->response->getBody()->seek(0);
$this->card = json_decode((string)$this->response->getBody(), true);
$this->requestContext->getResponse()->getBody()->seek(0);
$this->card = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
@@ -151,4 +162,70 @@ class BoardContext implements Context {
]);
$this->serverContext->creatingShare($table);
}
/**
* @Given /^set the description to "([^"]*)"$/
*/
public function setTheDescriptionTo($description) {
$this->requestContext->sendJSONrequest('PUT', '/index.php/apps/deck/cards/' . $this->card['id'], array_merge(
$this->card,
['description' => $description]
));
$this->requestContext->getResponse()->getBody()->seek(0);
$this->card = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
* @Given /^set the card attribute "([^"]*)" to "([^"]*)"$/
*/
public function setCardAttribute($attribute, $value) {
$this->requestContext->sendJSONrequest('PUT', '/index.php/apps/deck/cards/' . $this->card['id'], array_merge(
$this->card,
[$attribute => $value]
));
$this->requestContext->getResponse()->getBody()->seek(0);
$this->card = json_decode((string)$this->getResponse()->getBody(), true);
}
/**
* @Given /^set the card duedate to "([^"]*)"$/
*/
public function setTheCardDuedateTo($arg1) {
$date = new DateTime($arg1);
$this->setCardAttribute('duedate', $date->format(DateTimeInterface::ATOM));
}
/**
* @Given /^assign the card to the user "([^"]*)"$/
*/
public function assignTheCardToTheUser($user) {
$this->assignToCard($user, 0);
}
/**
* @Given /^assign the card to the group "([^"]*)"$/
*/
public function assignTheCardToTheGroup($user) {
$this->assignToCard($user, 1);
}
private function assignToCard($participant, $type) {
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/cards/' . $this->card['id'] .'/assign', [
'userId' => $participant,
'type' => $type
]);
$this->requestContext->getResponse()->getBody()->seek(0);
}
/**
* @Given /^assign the tag "([^"]*)" to the card$/
*/
public function assignTheTagToTheCard($tag) {
$filteredLabels = array_filter($this->board['labels'], function ($label) use ($tag) {
return $label['title'] === $tag;
});
$label = array_shift($filteredLabels);
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/cards/' . $this->card['id'] .'/label/' . $label['id']);
$this->requestContext->getResponse()->getBody()->seek(0);
}
}

View File

@@ -5,11 +5,12 @@ use Behat\Gherkin\Node\TableNode;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use PHPUnit\Framework\Assert;
use Behat\Behat\Context\Context;
use Psr\Http\Message\ResponseInterface;
require_once __DIR__ . '/../../vendor/autoload.php';
trait RequestTrait {
class RequestContext implements Context {
private $response;
/** @var ServerContext */
@@ -22,6 +23,9 @@ trait RequestTrait {
$this->serverContext = $environment->getContext('ServerContext');
}
private function getBaseUrl() {
}
/**
* @Then the response should have a status code :code
* @param string $code
@@ -90,12 +94,12 @@ trait RequestTrait {
}
}
private function sendJSONrequest($method, $url, $data = []) {
public function sendJSONrequest($method, $url, $data = []) {
$client = new Client;
try {
$this->response = $client->request(
$method,
$this->severContext->getBaseUrl() . $url,
rtrim($this->serverContext->getBaseUrl(), '/') . '/' . ltrim($url, '/'),
[
'cookies' => $this->serverContext->getCookieJar(),
'json' => $data,
@@ -109,18 +113,19 @@ trait RequestTrait {
}
}
private function sendOCSRequest($method, $url, $data = []) {
public function sendOCSRequest($method, $url, $data = []) {
$client = new Client;
try {
$this->response = $client->request(
$method,
$this->severContext->getBaseUrl() . $url,
rtrim($this->serverContext->getBaseUrl(), '/') . '/ocs/v2.php/' . ltrim($url, '/'),
[
'cookies' => $this->serverContext->getCookieJar(),
'json' => $data,
'headers' => [
'requesttoken' => $this->serverContext->getReqestToken(),
'OCS-APIRequest' => true,
'OCS-APIREQUEST' => 'true',
'Accept' => 'application/json'
]
]
);
@@ -128,4 +133,8 @@ trait RequestTrait {
$this->response = $e->getResponse();
}
}
public function getResponse(): ResponseInterface {
return $this->response;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* @copyright Copyright (c) 2021 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
declare(strict_types=1);
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
require_once __DIR__ . '/../../vendor/autoload.php';
trait RequestTrait {
/** @var RequestContext */
protected $requestContext;
/** @BeforeScenario */
public function gatherRequestTraitContext(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();
$this->requestContext = $environment->getContext('RequestContext');
}
public function getResponse() {
return $this->requestContext->getResponse();
}
}

View File

@@ -0,0 +1,81 @@
<?php
use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use PHPUnit\Framework\Assert;
require_once __DIR__ . '/../../vendor/autoload.php';
class SearchContext implements Context {
use RequestTrait;
/** @var BoardContext */
protected $boardContext;
private $searchResults;
/** @BeforeScenario */
public function gatherContexts(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();
$this->boardContext = $environment->getContext('BoardContext');
}
/**
* @When /^searching for "([^"]*)"$/
* @param string $term
*/
public function searchingFor(string $term) {
$this->requestContext->sendOCSRequest('GET', '/apps/deck/api/v1.0/search?term=' . urlencode($term), []);
$this->requestContext->getResponse()->getBody()->seek(0);
$data = (string)$this->getResponse()->getBody();
$this->searchResults = json_decode($data, true);
}
/**
* @When /^searching for '([^']*)'$/
* @param string $term
*/
public function searchingForQuotes(string $term) {
$this->searchingFor($term);
}
/**
* @Then /^the board "([^"]*)" is found$/
*/
public function theBoardIsFound($arg1) {
$ocsData = $this->searchResults['ocs']['data'];
$found = false;
foreach ($ocsData as $result) {
if ($result['title'] === $arg1) {
$found = true;
}
}
Assert::assertTrue($found, 'Board can be found');
}
private function cardIsFound($arg1) {
$ocsData = $this->searchResults['ocs']['data'];
$found = false;
foreach ($ocsData as $result) {
if ($result['title'] === $arg1) {
$found = true;
}
}
return $found;
}
/**
* @Then /^the card "([^"]*)" is found$/
*/
public function theCardIsFound($arg1) {
Assert::assertTrue($this->cardIsFound($arg1), 'Card can be found');
}
/**
* @Then /^the card "([^"]*)" is not found$/
*/
public function theCardIsNotFound($arg1) {
Assert::assertFalse($this->cardIsFound($arg1), 'Card can not be found');
}
}

View File

@@ -6,7 +6,14 @@ use GuzzleHttp\Cookie\CookieJar;
require_once __DIR__ . '/../../vendor/autoload.php';
class ServerContext implements Context {
use WebDav;
use WebDav {
WebDav::__construct as private __tConstruct;
}
public function __construct($baseUrl) {
$this->rawBaseUrl = $baseUrl;
$this->__tConstruct($baseUrl . '/index.php/ocs/', ['admin', 'admin'], '123456');
}
/** @var string */
private $mappedUserId;
@@ -28,6 +35,10 @@ class ServerContext implements Context {
$this->asAn($user);
}
public function getBaseUrl(): string {
return $this->rawBaseUrl;
}
public function getCookieJar(): CookieJar {
return $this->cookieJar;
}

View File

@@ -4,23 +4,6 @@ Feature: decks
Given user "admin" exists
Given user "user0" exists
Scenario: Request the main frontend page
Given Logging in using web as "admin"
When Sending a "GET" to "/index.php/apps/deck" without requesttoken
Then the HTTP status code should be "200"
Scenario: Fetch the board list
Given Logging in using web as "admin"
When fetching the board list
Then the response should have a status code "200"
And the response Content-Type should be "application/json; charset=utf-8"
Scenario: Fetch board details of a nonexisting board
Given Logging in using web as "admin"
When fetching the board with id "99999999"
Then the response should have a status code "403"
And the response Content-Type should be "application/json; charset=utf-8"
Scenario: Create a new board
Given Logging in using web as "admin"
When creates a board named "MyBoard" with color "000000"

View File

@@ -0,0 +1,259 @@
Feature: Searching for cards
Background:
Given user "admin" exists
Given user "user0" exists
Given Logging in using web as "admin"
When creates a board named "MyBoard" with color "000000"
When create a stack named "ToDo"
And create a card named "Example task 1"
And create a card named "Example task 2"
When create a stack named "In progress"
And create a card named "Progress task 1"
And create a card named "Progress task 2"
When create a stack named "Done"
And create a card named "Done task 1"
And set the description to "Done task description 1"
And create a card named "Done task 2"
And set the description to "Done task description 2"
And shares the board with user "user0"
Scenario: Search for a card with multiple terms
When searching for "Example task"
Then the card "Example task 1" is found
Then the card "Example task 2" is found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Scenario: Search for a card in a specific list
When searching for "task list:Done"
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Scenario: Search for a card with one term
When searching for "task"
Then the card "Example task 1" is found
Then the card "Example task 2" is found
Then the card "Progress task 1" is found
Then the card "Progress task 2" is found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Scenario: Search for a card with an differently cased term
When searching for "tAsk"
Then the card "Example task 1" is found
Then the card "Example task 2" is found
Then the card "Progress task 1" is found
Then the card "Progress task 2" is found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Scenario: Search for a card title
When searching for 'title:"Done task 1"'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is found
Then the card "Done task 2" is not found
Scenario: Search for a card description
When searching for 'description:"Done task description"'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Scenario: Search for a non-existing card description
When searching for 'description:"Example"'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Scenario: Search on shared boards
Given Logging in using web as "user0"
When searching for "task"
Then the card "Example task 1" is found
Then the card "Example task 2" is found
Then the card "Progress task 1" is found
Then the card "Progress task 2" is found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Scenario: Search for a card due date
Given create a card named "Overdue task"
And set the card attribute "duedate" to "2020-12-12"
And create a card named "Future task"
And set the card attribute "duedate" to "3000-12-12"
And create a card named "Tomorrow task"
And set the card duedate to "tomorrow"
When searching for 'date:overdue'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is found
Then the card "Future task" is not found
Scenario: Search for a card due date
And create a card named "Overdue task"
And set the card attribute "duedate" to "2020-12-12"
And create a card named "Future task"
And set the card attribute "duedate" to "3000-12-12"
And create a card named "Tomorrow task"
And set the card duedate to "+12 hours"
And create a card named "Next week task"
And set the card duedate to "+5 days"
When searching for 'date:today'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is not found
Then the card "Future task" is not found
Then the card "Tomorrow task" is found
Then the card "Next week task" is not found
When searching for 'date:week'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is not found
Then the card "Future task" is not found
Then the card "Tomorrow task" is found
Then the card "Next week task" is found
When searching for 'date:month'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is not found
Then the card "Future task" is not found
Then the card "Tomorrow task" is found
Then the card "Next week task" is found
When searching for 'date:none'
Then the card "Example task 1" is found
Then the card "Example task 2" is found
Then the card "Progress task 1" is found
Then the card "Progress task 2" is found
Then the card "Done task 1" is found
Then the card "Done task 2" is found
Then the card "Overdue task" is not found
Then the card "Future task" is not found
Then the card "Tomorrow task" is not found
Then the card "Next week task" is not found
When searching for 'date:<"+7 days"'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is found
Then the card "Future task" is not found
Then the card "Tomorrow task" is found
Then the card "Next week task" is found
When searching for 'date:>"+10 days"'
Then the card "Example task 1" is not found
Then the card "Example task 2" is not found
Then the card "Progress task 1" is not found
Then the card "Progress task 2" is not found
Then the card "Done task 1" is not found
Then the card "Done task 2" is not found
Then the card "Overdue task" is not found
Then the card "Future task" is found
Then the card "Tomorrow task" is not found
Then the card "Next week task" is not found
Scenario: Search for assigned user
Given user "user1" exists
And shares the board with user "user1"
Given create a card named "Assigned card to user1"
And assign the card to the user "user1"
When searching for 'assigned:user1'
Then the card "Example task 1" is not found
And the card "Assigned card to user1" is found
Scenario: Search for assigned user by displayname
Given user "ada" with displayname "Ada Lovelace" exists
And shares the board with user "ada"
Given create a card named "Assigned card to ada"
And assign the card to the user "ada"
When searching for 'assigned:"Ada Lovelace"'
Then the card "Example task 1" is not found
And the card "Assigned card to ada" is found
Scenario: Search for assigned users
Given user "user1" exists
And shares the board with user "user1"
Given create a card named "Assigned card to user0"
And assign the card to the user "user0"
Given create a card named "Assigned card to user01"
And assign the card to the user "user0"
And assign the card to the user "user1"
When searching for 'assigned:user0 assigned:user1'
Then the card "Example task 1" is not found
And the card "Assigned card to user0" is not found
And the card "Assigned card to user01" is found
Scenario: Search for assigned group
Given user "user1" exists
And shares the board with user "user1"
Given group "group1" exists
And shares the board with group "group1"
Given user "user1" belongs to group "group1"
Given create a card named "Assigned card to group1"
And assign the card to the group "group1"
When searching for 'assigned:user1'
Then the card "Example task 1" is not found
And the card "Assigned card to group1" is found
When searching for 'assigned:group1'
Then the card "Example task 1" is not found
And the card "Assigned card to group1" is found
Scenario: Search for assigned tag
Given create a card named "Labeled card"
# Default labels from boards are used for this test case
And assign the tag "Finished" to the card
When searching for 'tag:Finished'
Then the card "Example task 1" is not found
And the card "Labeled card" is found
Given create a card named "Multi labeled card"
And assign the tag "Finished" to the card
And assign the tag "To review" to the card
When searching for 'tag:Finished tag:Later'
Then the card "Example task 1" is not found
And the card "Multi labeled card" is not found
When searching for 'tag:Finished tag:"To review"'
Then the card "Example task 1" is not found
And the card "Labeled card" is not found
And the card "Multi labeled card" is found