Merge pull request #768 from nextcloud/add-acceptance-tests

Add acceptance tests
This commit is contained in:
Ivan Sein 2018-04-13 10:34:34 +02:00 коммит произвёл GitHub
Родитель dc57803052 137e7c6727
Коммит 0c159d5b7f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 873 добавлений и 0 удалений

Просмотреть файл

@ -151,6 +151,21 @@ pipeline:
when:
matrix:
TESTS: jsunit
acceptance-conversation:
image: nextcloudci/acceptance-php7.1:acceptance-php7.1-2
commands:
# Pre-setup steps
- git clone --depth 1 -b master https://github.com/nextcloud/server ../server
- cp -R . ../server/apps/spreed
- cd ../server
- git submodule update --init
- ln --symbolic `pwd` /var/www/html
# Run acceptance tests
- tests/acceptance/run-local.sh --acceptance-tests-dir apps/spreed/tests/acceptance --timeout-multiplier 10 --nextcloud-server-domain acceptance-conversation --selenium-server selenium:4444 allow-git-repository-modifications features/conversation.feature
when:
matrix:
TESTS-ACCEPTANCE: conversation
matrix:
include:
@ -171,6 +186,8 @@ matrix:
DB: pgsql
DATABASEHOST: postgres-10
- TESTS: jsunit
- TESTS: acceptance
TESTS-ACCEPTANCE: conversation
services:
mysql-5.7:
@ -191,3 +208,12 @@ services:
when:
matrix:
DATABASEHOST: postgres-10
selenium:
image: selenium/standalone-firefox:2.53.1-beryllium
environment:
# Reduce default log level for Selenium server (INFO) as it is too
# verbose.
- JAVA_OPTS=-Dselenium.LOGGER.level=WARNING
when:
matrix:
TESTS: acceptance

Просмотреть файл

@ -0,0 +1,34 @@
default:
autoload:
'': %paths.base%/../features/bootstrap
suites:
default:
paths:
- %paths.base%/../features
contexts:
# Base contexts
- ActorContext
- NextcloudTestServerContext:
nextcloudTestServerHelper: NextcloudTestServerLocalApacheHelper
- FeatureContext
- FileListContext
- FilesAppContext
- LoginPageContext
# Talk app contexts
- ChatContext
- ConversationInfoContext
- ConversationListContext
- ParticipantListContext
- TalkAppContext
extensions:
Behat\MinkExtension:
sessions:
default:
selenium2: ~
John:
selenium2: ~
Jane:
selenium2: ~

Просмотреть файл

@ -0,0 +1,66 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
/**
* Helper trait to set the ancestor of the chat.
*
* The ChatContext provides steps to interact with and check the behaviour of
* the chat view. However, the ChatContext does not know the right chat ancestor
* that has to be used by the chat steps; this has to be set from other
* contexts, for example, when the user joins or leaves a call.
*
* Contexts that "know" that certain chat ancestor has to be used by the
* ChatContext steps should use this trait and call "setChatAncestorForActor"
* when needed.
*/
trait ChatAncestorSetter {
/**
* @var ChatContext
*/
private $chatContext;
/**
* @BeforeScenario
*/
public function getSiblingChatContext(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();
$this->chatContext = $environment->getContext("ChatContext");
}
/**
* Sets the chat ancestor to be used in the chat steps performed by the
* given actor.
*
* @param null|Locator $chatAncestor the chat ancestor
* @param Actor $actor the actor
*/
private function setChatAncestorForActor($chatAncestor, Actor $actor) {
$this->chatContext->setChatAncestorForActor($chatAncestor, $actor);
}
}

Просмотреть файл

@ -0,0 +1,97 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
class ChatContext implements Context, ActorAwareInterface {
/**
* @var Actor
*/
private $actor;
/**
* @var array
*/
private $chatAncestorsByActor;
/**
* @var Locator
*/
private $chatAncestor;
/**
* @BeforeScenario
*/
public function initializeChatAncestors() {
$this->chatAncestorsByActor = array();
$this->chatAncestor = null;
}
/**
* @param Actor $actor
*/
public function setCurrentActor(Actor $actor) {
$this->actor = $actor;
if (array_key_exists($actor->getName(), $this->chatAncestorsByActor)) {
$this->chatAncestor = $this->chatAncestorsByActor[$actor->getName()];
} else {
$this->chatAncestor = null;
}
}
/**
* Sets the chat ancestor to be used in the steps performed by the given
* actor from that point on (until changed again).
*
* This is meant to be called from other contexts, for example, when the
* user joins or leaves a video call.
*
* The ChatAncestorSetter trait can be used to reduce the boilerplate needed
* to set the chat ancestor from other contexts.
*
* @param null|Locator $chatAncestor the chat ancestor
* @param Actor $actor the actor
*/
public function setChatAncestorForActor($chatAncestor, Actor $actor) {
$this->chatAncestorsByActor[$actor->getName()] = $chatAncestor;
}
/**
* @return Locator
*/
public static function chatView($chatAncestor) {
return Locator::forThe()->css(".chat")->
descendantOf($chatAncestor)->
describedAs("Chat view in Talk app");
}
/**
* @Then I see that the chat is shown in the main view
*/
public function iSeeThatTheChatIsShownInTheMainView() {
PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::chatView($this->chatAncestor), 10)->isVisible());
}
}

Просмотреть файл

@ -0,0 +1,75 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
class ConversationInfoContext implements Context, ActorAwareInterface {
use ActorAware;
/**
* @return Locator
*/
public static function conversationInfoContainer() {
return Locator::forThe()->css(".detailCallInfoContainer")->
descendantOf(TalkAppContext::sidebar())->
describedAs("Conversation info container in the sidebar");
}
/**
* @return Locator
*/
public static function conversationNameEditableTextLabel() {
return Locator::forThe()->css(".room-name")->
descendantOf(self::conversationInfoContainer())->
describedAs("Conversation name label in conversation info");
}
/**
* @return Locator
*/
public static function editConversationNameButton() {
return Locator::forThe()->css(".edit-button")->
descendantOf(self::conversationNameEditableTextLabel())->
describedAs("Edit conversation name button in conversation info");
}
/**
* @return Locator
*/
public static function conversationNameTextInput() {
return Locator::forThe()->xpath("//input[@type = 'text']")->
descendantOf(self::conversationNameEditableTextLabel())->
describedAs("Conversation name text input in conversation info");
}
/**
* @Given I rename the conversation to :newConversationName
*/
public function iRenameTheConversationTo($newConversationName) {
$this->actor->find(self::conversationNameEditableTextLabel(), 10)->click();
$this->actor->find(self::editConversationNameButton(), 2)->click();
$this->actor->find(self::conversationNameTextInput(), 2)->setValue($newConversationName . "\r");
}
}

Просмотреть файл

@ -0,0 +1,197 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
class ConversationListContext implements Context, ActorAwareInterface {
use ActorAware;
use ChatAncestorSetter;
/**
* @return Locator
*/
public static function appNavigation() {
return Locator::forThe()->id("app-navigation")->
describedAs("App navigation");
}
/**
* @return Locator
*/
public static function showCreateConversationDropdownButton() {
return Locator::forThe()->css("#oca-spreedme-add-room .select2-choice")->
descendantOf(self::appNavigation())->
describedAs("Show create conversation dropdown button in App navigation");
}
/**
* @return Locator
*/
public static function conversationList() {
return Locator::forThe()->id("spreedme-room-list")->
descendantOf(self::appNavigation())->
describedAs("Conversation list in App navigation");
}
/**
* @return Locator
*/
public static function conversationListItemFor($conversation) {
return Locator::forThe()->xpath("//a[normalize-space() = '$conversation']/ancestor::li")->
descendantOf(self::conversationList())->
describedAs("$conversation item in conversation list in App navigation");
}
/**
* @return Locator
*/
public static function activeConversationListItemFor($conversation) {
return Locator::forThe()->xpath("//a[normalize-space() = '$conversation']/ancestor::li[contains(concat(' ', normalize-space(@class), ' '), ' active ')]")->
descendantOf(self::conversationList())->
describedAs("$conversation item in conversation list in App navigation");
}
/**
* @return Locator
*/
public static function conversationMenuButtonFor($conversation) {
return Locator::forThe()->css(".app-navigation-entry-utils-menu-button button")->
descendantOf(self::conversationListItemFor($conversation))->
describedAs("Menu button for $conversation in conversation list in App navigation");
}
/**
* @return Locator
*/
public static function conversationMenuFor($conversation) {
return Locator::forThe()->css(".app-navigation-entry-menu")->
descendantOf(self::conversationListItemFor($conversation))->
describedAs("Menu for $conversation in conversation list in App navigation");
}
/**
* @return Locator
*/
private static function conversationMenuItemFor($conversation, $item) {
return Locator::forThe()->xpath("//button[normalize-space() = '$item']")->
descendantOf(self::conversationMenuFor($conversation))->
describedAs("$item item in menu for $conversation in conversation list in App navigation");
}
/**
* @return Locator
*/
public static function removeConversationFromListMenuItemFor($conversation) {
return self::conversationMenuItemFor($conversation, "Remove conversation from list");
}
/**
* @Given I create a group conversation
*/
public function iCreateAGroupConversation() {
// When the Talk app is opened and there are no conversations the
// dropdown is automatically shown, and when the dropdown is shown
// clicking on the button to open it fails because it is covered by the
// search field of the dropdown. Due to that first it is assumed that
// the dropdown is shown and the item is directly clicked; if it was not
// shown, then it is explicitly shown and after that the item is
// clicked.
try {
$this->actor->find(TalkAppContext::itemInSelect2DropdownFor("New group conversation"), 2)->click();
} catch (NoSuchElementException $exception) {
$this->actor->find(self::showCreateConversationDropdownButton(), 10)->click();
$this->actor->find(TalkAppContext::itemInSelect2DropdownFor("New group conversation"), 2)->click();
}
$this->setChatAncestorForActor(TalkAppContext::mainView(), $this->actor);
}
/**
* @Given I create a one-to-one conversation with :userName
*/
public function iCreateAOneToOneConversationWith($userName) {
// When the Talk app is opened and there are no conversations the
// dropdown is automatically shown, and when the dropdown is shown
// clicking on the button to open it fails because it is covered by the
// search field of the dropdown. Due to that first it is assumed that
// the dropdown is shown and the item is directly clicked; if it was not
// shown, then it is explicitly shown and after that the item is
// clicked.
try {
$this->actor->find(TalkAppContext::itemInSelect2DropdownFor($userName), 2)->click();
} catch (NoSuchElementException $exception) {
$this->actor->find(self::showCreateConversationDropdownButton(), 10)->click();
$this->actor->find(TalkAppContext::itemInSelect2DropdownFor($userName), 2)->click();
}
$this->setChatAncestorForActor(TalkAppContext::mainView(), $this->actor);
}
/**
* @Given I open the :conversation conversation
*/
public function iOpenTheConversation($conversation) {
$this->actor->find(self::conversationListItemFor($conversation), 10)->click();
}
/**
* @Given I remove the :conversation conversation from the list
*/
public function iRemoveTheConversationFromTheList($conversation) {
$this->actor->find(self::conversationMenuButtonFor($conversation), 10)->click();
$this->actor->find(self::removeConversationFromListMenuItemFor($conversation), 2)->click();
}
/**
* @Then I see that the :conversation conversation is not shown in the list
*/
public function iSeeThatTheConversationIsNotShownInTheList($conversation) {
if (!WaitFor::elementToBeEventuallyNotShown(
$this->actor,
self::conversationListItemFor($conversation),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The $conversation conversation is still shown in the list after $timeout seconds");
}
}
/**
* @Then I see that the :conversation conversation is active
*/
public function iSeeThatTheConversationIsActive($conversation) {
PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::activeConversationListItemFor($conversation), 10)->isVisible());
}
/**
* @Then I see that the :conversation conversation is not active
*/
public function iSeeThatTheConversationIsNotActive($conversation) {
if (!WaitFor::elementToBeEventuallyNotShown(
$this->actor,
self::activeConversationListItemFor($conversation),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The $conversation conversation is still active after $timeout seconds");
}
}
}

Просмотреть файл

@ -0,0 +1,101 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
class ParticipantListContext implements Context, ActorAwareInterface {
use ActorAware;
/**
* @return Locator
*/
public static function participantsTabView() {
return Locator::forThe()->id("participantsTabView")->
describedAs("Participants tab in the sidebar");
}
/**
* @return Locator
*/
public static function participantsList() {
return Locator::forThe()->css(".participantWithList")->
descendantOf(self::participantsTabView())->
describedAs("Participants list in the sidebar");
}
/**
* @return Locator
*/
public static function itemInParticipantsListFor($participantName) {
return Locator::forThe()->xpath("//a/text()[normalize-space() = '$participantName']/..")->
descendantOf(self::participantsList())->
describedAs("Item for $participantName in the participants list");
}
/**
* @return Locator
*/
public static function moderatorIndicatorFor($participantName) {
return Locator::forThe()->css(".participant-moderator-indicator")->
descendantOf(self::itemInParticipantsListFor($participantName))->
describedAs("Moderator indicator for $participantName in the participants list");
}
/**
* @return array
*/
public function participantsListItems() {
return $this->actor->find(self::participantsList(), 10)
->getWrappedElement()->findAll('xpath', '/li');
}
/**
* @Then I see that the number of participants shown in the list is :numberOfParticipants
*/
public function iSeeThatTheNumberOfParticipantsShownInTheListIs($numberOfParticipants) {
$numberOfParticipantsMatchCallback = function() use ($numberOfParticipants) {
try {
return count($this->participantsListItems()) === intval($numberOfParticipants);
} catch (NoSuchElementException $exception) {
return false;
}
};
if (!Utils::waitFor(
$numberOfParticipantsMatchCallback,
$timeout = 10 * $this->actor->getFindTimeoutMultiplier(),
$timeoutStep = 1)) {
PHPUnit_Framework_Assert::fail("The number of participants is still not $numberOfParticipants after $timeout seconds");
}
}
/**
* @Then I see that :participantName is shown in the list of participants as a moderator
*/
public function iSeeThatIsShownInTheListOfParticipantsAsAModerator($participantName) {
PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::itemInParticipantsListFor($participantName), 10));
PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::moderatorIndicatorFor($participantName), 10));
}
}

Просмотреть файл

@ -0,0 +1,155 @@
<?php
/**
*
* @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
*
* @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/>.
*
*/
use Behat\Behat\Context\Context;
class TalkAppContext implements Context, ActorAwareInterface {
use ActorAware;
/**
* @return Locator
*/
private static function appMenu() {
return Locator::forThe()->id("appmenu")->
describedAs("App menu in header");
}
/**
* @return Locator
*/
public static function talkItemInAppMenu() {
return Locator::forThe()->xpath("/li[@data-id = 'spreed']")->
descendantOf(self::appMenu())->
describedAs("Talk item in app menu in header");
}
/**
* @return Locator
*/
public static function mainView() {
return Locator::forThe()->id("app-content-wrapper")->
describedAs("Main view in Talk app");
}
/**
* @return Locator
*/
public static function emptyContent() {
return Locator::forThe()->id("emptycontent")->
descendantOf(self::mainView())->
describedAs("Empty content in main view");
}
/**
* @return Locator
*/
public static function sidebar() {
return Locator::forThe()->id("app-sidebar")->
describedAs("Sidebar in Talk app");
}
/**
* @return Locator
*/
private static function select2Dropdown() {
return Locator::forThe()->css("#select2-drop")->
describedAs("Select2 dropdown in Talk app");
}
/**
* @return Locator
*/
public static function itemInSelect2DropdownFor($text) {
return Locator::forThe()->xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' select2-result-label ')]//span/text()[normalize-space() = '$text']/ancestor::li")->
descendantOf(self::select2Dropdown())->
describedAs("Item in select2 dropdown for $text in Talk app");
}
/**
* @Given I open the Talk app
*/
public function iOpenTheTalkApp() {
$this->actor->find(self::talkItemInAppMenu(), 10)->click();
}
/**
* @Then I see that the current page is the Talk app
*/
public function iSeeThatTheCurrentPageIsTheTalkApp() {
PHPUnit_Framework_Assert::assertStringStartsWith(
$this->actor->locatePath("/apps/spreed/"),
$this->actor->getSession()->getCurrentUrl());
}
/**
* @Then I see that the empty content message is shown in the main view
*/
public function iSeeThatTheEmptyContentMessageIsShownInTheMainView() {
// The empty content always exists in the DOM, so it has to be explictly
// waited for it to be visible instead of relying on the implicit wait
// made to find the element.
if (!WaitFor::elementToBeEventuallyShown(
$this->actor,
self::emptyContent(),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The empty content was not shown yet after $timeout seconds");
}
}
/**
* @Then I see that the sidebar is open
*/
public function iSeeThatTheSidebarIsOpen() {
// The sidebar always exists in the DOM, so it has to be explicitly
// waited for it to be visible instead of relying on the implicit wait
// made to find the element.
if (!WaitFor::elementToBeEventuallyShown(
$this->actor,
self::sidebar(),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The sidebar was not shown yet after $timeout seconds");
}
}
/**
* @Then I see that the sidebar is closed
*/
public function iSeeThatTheSidebarIsClosed() {
if (!WaitFor::elementToBeEventuallyNotShown(
$this->actor,
self::sidebar(),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The sidebar is still shown after $timeout seconds");
}
}
/**
* @Given I have opened the Talk app
*/
public function iHaveOpenedTheTalkApp() {
$this->iOpenTheTalkApp();
$this->iSeeThatTheCurrentPageIsTheTalkApp();
}
}

Просмотреть файл

@ -0,0 +1,55 @@
Feature: conversation
Scenario: create a group conversation
Given I am logged in
And I have opened the Talk app
When I create a group conversation
Then I see that the "You" conversation is active
And I see that the chat is shown in the main view
And I see that the sidebar is open
And I see that the number of participants shown in the list is "1"
And I see that "user0" is shown in the list of participants as a moderator
Scenario: create a one-to-one conversation
Given I am logged in
And I have opened the Talk app
When I create a one-to-one conversation with "admin"
Then I see that the "admin" conversation is active
And I see that the chat is shown in the main view
And I see that the sidebar is open
And I see that the number of participants shown in the list is "2"
And I see that "user0" is shown in the list of participants as a moderator
And I see that "admin" is shown in the list of participants as a moderator
Scenario: rename a conversation
Given I am logged in
And I have opened the Talk app
And I create a group conversation
And I see that the "You" conversation is active
When I rename the conversation to "Test conversation"
Then I see that the "Test conversation" conversation is active
Scenario: change between conversations
Given I am logged in
And I have opened the Talk app
And I create a group conversation
And I see that the "You" conversation is active
And I see that the number of participants shown in the list is "1"
And I create a one-to-one conversation with "admin"
And I see that the "You" conversation is not active
And I see that the "admin" conversation is active
And I see that the number of participants shown in the list is "2"
When I open the "You" conversation
Then I see that the "You" conversation is active
And I see that the "admin" conversation is not active
And I see that the number of participants shown in the list is "1"
Scenario: remove a conversation from the list
Given I am logged in
And I have opened the Talk app
And I create a group conversation
And I see that the "You" conversation is active
When I remove the "You" conversation from the list
Then I see that the "You" conversation is not shown in the list
And I see that the empty content message is shown in the main view
And I see that the sidebar is closed

Просмотреть файл

@ -0,0 +1,33 @@
#!/bin/bash
# @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
#
# @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/>.
# Helper script to install and configure the Nextcloud server as expected by the
# acceptance tests.
#
# This script is not meant to be called manually; it is called when needed by
# the acceptance tests launchers.
#
# It simply extends the default script by enabling the Talk app so it is already
# available when the acceptance tests are run.
set -o errexit
tests/acceptance/installAndConfigureServer.sh "$@"
php occ app:enable spreed

34
tests/acceptance/run.sh Executable file
Просмотреть файл

@ -0,0 +1,34 @@
#!/bin/bash
# @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
#
# @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/>.
# Helper script to run the acceptance tests, which test a running Nextcloud
# Talk instance from the point of view of a real user.
#
# It simply calls the main "run.sh" script from the Nextcloud server setting a
# specific acceptance tests directory (the one for the Talk app), and as such it
# is expected that the grandparent directory of the root directory of the Talk
# app is the root directory of the Nextcloud server.
set -o errexit
# Ensure working directory is script directory, as it is expected when the
# script from the server is called.
cd "$(dirname $0)"
../../../../tests/acceptance/run.sh --acceptance-tests-dir apps/spreed/tests/acceptance/ "$@"