diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2019-08-28 11:22:13 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-28 11:22:13 +0300 |
commit | 3ee86747256355cd26de5f193ad37780f1dad0f2 (patch) | |
tree | 5f42244083edf0e2a3d314fcfd2f2a72fe06e91a /tests | |
parent | c9f390de4f3cfb4b903c62b1a38a21aad98d6022 (diff) | |
parent | 2caa0d2146631cfa4387116f412d10f57445ca06 (diff) |
Merge pull request #1974 from nextcloud/feature/noid/guest-mentions
👤🏷️ Guest mentions
Diffstat (limited to 'tests')
-rw-r--r-- | tests/acceptance/features/app-files.feature | 20 | ||||
-rw-r--r-- | tests/acceptance/features/bootstrap/ChatContext.php | 137 | ||||
-rw-r--r-- | tests/acceptance/features/bootstrap/ParticipantListContext.php | 14 | ||||
-rw-r--r-- | tests/acceptance/features/chat.feature | 133 | ||||
-rw-r--r-- | tests/acceptance/features/public-share-auth.feature | 21 | ||||
-rw-r--r-- | tests/integration/features/bootstrap/FeatureContext.php | 32 | ||||
-rw-r--r-- | tests/integration/features/chat/mentions.feature | 66 | ||||
-rw-r--r-- | tests/php/Chat/AutoComplete/SearchPluginTest.php | 130 | ||||
-rw-r--r-- | tests/php/Chat/Parser/UserMentionTest.php | 170 | ||||
-rw-r--r-- | tests/php/Controller/SignalingControllerTest.php | 1 | ||||
-rw-r--r-- | tests/php/Signaling/BackendNotifierTest.php | 2 |
11 files changed, 690 insertions, 36 deletions
diff --git a/tests/acceptance/features/app-files.feature b/tests/acceptance/features/app-files.feature index 5fd89078f..7cd385236 100644 --- a/tests/acceptance/features/app-files.feature +++ b/tests/acceptance/features/app-files.feature @@ -99,15 +99,21 @@ Feature: app-files And I open the details view for "welcome (2).txt" And I open the Chat tab in the details view of the Files app When I act as John - And I send a new chat message with the text "Hello" + And I send a new chat message with the text "Hello @user0" And I act as Jane - And I see that the message 1 was sent by "admin" with the text "Hello" - And I send a new chat message with the text "Hi!" - Then I see that the message 1 was sent by "admin" with the text "Hello" - And I see that the message 2 was sent by "user0" with the text "Hi!" + And I see that the message 1 was sent by "admin" with the text "Hello user0" + And I type a new chat message with the text "Hi @" + And I choose the candidate mention for "admin" + And I send the current chat message + Then I see that the message 1 was sent by "admin" with the text "Hello user0" + And I see that the message 1 contains a formatted mention of "user0" as current user + And I see that the message 2 was sent by "user0" with the text "Hi admin" + And I see that the message 2 contains a formatted mention of "admin" And I act as John - And I see that the message 1 was sent by "admin" with the text "Hello" - And I see that the message 2 was sent by "user0" with the text "Hi!" + And I see that the message 1 was sent by "admin" with the text "Hello user0" + And I see that the message 1 contains a formatted mention of "user0" + And I see that the message 2 was sent by "user0" with the text "Hi admin" + And I see that the message 2 contains a formatted mention of "admin" as current user # Scenario: chat in a reshared file # Given I act as John diff --git a/tests/acceptance/features/bootstrap/ChatContext.php b/tests/acceptance/features/bootstrap/ChatContext.php index 02fb25729..19f0cbf22 100644 --- a/tests/acceptance/features/bootstrap/ChatContext.php +++ b/tests/acceptance/features/bootstrap/ChatContext.php @@ -154,7 +154,10 @@ class ChatContext implements Context, ActorAwareInterface { * @return Locator */ public static function formattedMentionInChatMessageOf($chatAncestor, $number, $user) { - return Locator::forThe()->xpath("span/span[contains(concat(' ', normalize-space(@class), ' '), ' mention-user ') and normalize-space() = '$user']")-> + // User mentions have an image avatar, but guest mentions have a plain + // text avatar, so the avatar needs to be excluded when matching the + // name. + return Locator::forThe()->xpath("span/span[contains(concat(' ', normalize-space(@class), ' '), ' mention-user ')]//*[normalize-space() = '$user']/ancestor::span")-> descendantOf(self::textOfChatMessage($chatAncestor, $number))-> describedAs("Formatted mention of $user in chat message $number in the list of received messages"); } @@ -162,6 +165,27 @@ class ChatContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function formattedMentionInChatMessageOfAsCurrentUser($chatAncestor, $number, $user) { + // User mentions have an image avatar, but guest mentions have a plain + // text avatar, so the avatar needs to be excluded when matching the + // name. + return Locator::forThe()->xpath("span/span[contains(concat(' ', normalize-space(@class), ' '), ' mention-user ') and contains(concat(' ', normalize-space(@class), ' '), ' currentUser ')]//*[normalize-space() = '$user']/ancestor::span")-> + descendantOf(self::textOfChatMessage($chatAncestor, $number))-> + describedAs("Formatted mention of $user as current user in chat message $number in the list of received messages"); + } + + /** + * @return Locator + */ + public static function formattedMentionInChatMessageOfAllParticipantsOf($chatAncestor, $number, $roomName) { + return Locator::forThe()->xpath("span/span[contains(concat(' ', normalize-space(@class), ' '), ' mention-call ') and contains(concat(' ', normalize-space(@class), ' '), ' currentUser ') and normalize-space() = '$roomName']")-> + descendantOf(self::textOfChatMessage($chatAncestor, $number))-> + describedAs("Formatted mention of all participants of $roomName in chat message $number in the list of received messages"); + } + + /** + * @return Locator + */ public static function formattedLinkInChatMessageTo($chatAncestor, $number, $url) { return Locator::forThe()->xpath("a[normalize-space(@href) = '$url']")-> descendantOf(self::textOfChatMessage($chatAncestor, $number))-> @@ -180,6 +204,33 @@ class ChatContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function guestNameEditableTextLabel($chatAncestor) { + return Locator::forThe()->css(".guest-name.editable-text-label")-> + descendantOf(self::chatView($chatAncestor))-> + describedAs("Guest name editable text label"); + } + + /** + * @return Locator + */ + public static function guestNameEditButton($chatAncestor) { + return Locator::forThe()->css(".edit-button")-> + descendantOf(self::guestNameEditableTextLabel($chatAncestor))-> + describedAs("Guest name edit button"); + } + + /** + * @return Locator + */ + public static function guestNameInput($chatAncestor) { + return Locator::forThe()->css(".username")-> + descendantOf(self::guestNameEditableTextLabel($chatAncestor))-> + describedAs("Guest name input"); + } + + /** + * @return Locator + */ public static function newChatMessageForm($chatAncestor) { return Locator::forThe()->css(".newCommentForm")-> descendantOf(self::chatView($chatAncestor))-> @@ -198,6 +249,15 @@ class ChatContext implements Context, ActorAwareInterface { /** * @return Locator */ + public static function newChatMessageSendIcon($chatAncestor) { + return Locator::forThe()->css(".icon-confirm")-> + descendantOf(self::newChatMessageForm($chatAncestor))-> + describedAs("New chat message send icon"); + } + + /** + * @return Locator + */ public static function newChatMessageWorkingIcon($chatAncestor) { return Locator::forThe()->css(".submitLoading")-> descendantOf(self::newChatMessageForm($chatAncestor))-> @@ -214,6 +274,67 @@ class ChatContext implements Context, ActorAwareInterface { } /** + * @return Locator + */ + public static function mentionAutocompleteContainer() { + // The container is added directly in the body, not in the chat view. + // Moreover, there could be several atwho containers, so it needs to be + // got based on the elements that it contains. + return Locator::forThe()->xpath("//li[contains(concat(' ', normalize-space(@class), ' '), ' chat-view-mention-autocomplete ')]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' atwho-container ')]")-> + describedAs("Mention autocomplete container"); + } + + /** + * @return Locator + */ + public static function mentionAutocompleteCandidateFor($name) { + // User mentions have an image avatar, but guest mentions have a plain + // text avatar, so the avatar needs to be excluded when matching the + // name. + return Locator::forThe()->xpath("//li[contains(concat(' ', normalize-space(@class), ' '), ' chat-view-mention-autocomplete ')]//*[normalize-space() = '$name']/ancestor::li")-> + descendantOf(self::mentionAutocompleteContainer())-> + describedAs("Mention autocomplete candidate for $name"); + } + + /** + * @When I set my guest name to :name + */ + public function iSetMyGuestNameTo($name) { + $this->actor->find(self::guestNameEditButton($this->chatAncestor), 10)->click(); + $this->actor->find(self::guestNameInput($this->chatAncestor), 2)->setValue($name . "\r"); + } + + /** + * @When I type a new chat message with the text :message + */ + public function iTypeANewChatMessageWithTheText($message) { + // Instead of waiting for the input to be enabled before sending a new + // message it is easier to wait for the working icon to not be shown. + if (!WaitFor::elementToBeEventuallyNotShown( + $this->actor, + self::newChatMessageWorkingIcon($this->chatAncestor), + $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) { + PHPUnit_Framework_Assert::fail("The working icon for the new message was still being shown after $timeout seconds"); + } + + $this->actor->find(self::newChatMessageInput($this->chatAncestor), 10)->setValue($message); + } + + /** + * @When I choose the candidate mention for :name + */ + public function iChooseTheCandidateMentionFor($name) { + $this->actor->find(self::mentionAutocompleteCandidateFor($name), 10)->click(); + } + + /** + * @When I send the current chat message + */ + public function iSendTheCurrentChatMessage() { + $this->actor->find(self::newChatMessageSendIcon($this->chatAncestor), 10)->click(); + } + + /** * @When I send a new chat message with the text :message */ public function iSendANewChatMessageWith($message) { @@ -289,6 +410,20 @@ class ChatContext implements Context, ActorAwareInterface { } /** + * @Then I see that the message :number contains a formatted mention of :user as current user + */ + public function iSeeThatTheMessageContainsAFormattedMentionOfAsCurrentUser($number, $user) { + PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::formattedMentionInChatMessageOfAsCurrentUser($this->chatAncestor, $number, $user), 10)); + } + + /** + * @Then I see that the message :number contains a formatted mention of all participants of :roomName + */ + public function iSeeThatTheMessageContainsAFormattedMentionOfAllParticipantsOf($number, $roomName) { + PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::formattedMentionInChatMessageOfAllParticipantsOf($this->chatAncestor, $number, $roomName), 10)); + } + + /** * @Then I see that the message :number contains a formatted link to :user */ public function iSeeThatTheMessageContainsAFormattedLinkTo($number, $url) { diff --git a/tests/acceptance/features/bootstrap/ParticipantListContext.php b/tests/acceptance/features/bootstrap/ParticipantListContext.php index 6e640684e..1907223e4 100644 --- a/tests/acceptance/features/bootstrap/ParticipantListContext.php +++ b/tests/acceptance/features/bootstrap/ParticipantListContext.php @@ -115,4 +115,18 @@ class ParticipantListContext implements Context, ActorAwareInterface { PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::moderatorIndicatorFor($participantName), 10)); } + /** + * @Then I see that :participantName is shown in the list of participants as a normal participant + */ + public function iSeeThatIsShownInTheListOfParticipantsAsANormalParticipant($participantName) { + PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::itemInParticipantsListFor($participantName), 10)); + + if (!WaitFor::elementToBeEventuallyNotShown( + $this->actor, + self::moderatorIndicatorFor($participantName), + $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) { + PHPUnit_Framework_Assert::fail("Participant $participantName is still marked as a moderator after $timeout seconds but it should be a normal participant instead"); + } + } + } diff --git a/tests/acceptance/features/chat.feature b/tests/acceptance/features/chat.feature index 3579d0f2e..b039582cc 100644 --- a/tests/acceptance/features/chat.feature +++ b/tests/acceptance/features/chat.feature @@ -129,13 +129,140 @@ Feature: chat And I see that the message 6 was sent by "admin" with the text "Fine too!" Scenario: mention another user - Given I am logged in + Given I act as John + And I am logged in And I have opened the Talk app - And I create a group conversation named "Group" + And I create a one-to-one conversation with "admin" + And I see that the chat is shown in the main view + And I act as Jane + And I am logged in as the admin + And I have opened the Talk app + And I open the "user0" conversation And I see that the chat is shown in the main view - When I send a new chat message with the text "Hello @admin" + When I act as John + And I send a new chat message with the text "Hello @admin" Then I see that the message 1 was sent by "user0" with the text "Hello admin" And I see that the message 1 contains a formatted mention of "admin" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello admin" + And I see that the message 1 contains a formatted mention of "admin" as current user + + Scenario: mention another user from the candidate mentions + Given I act as John + And I am logged in + And I have opened the Talk app + And I create a one-to-one conversation with "admin" + And I see that the chat is shown in the main view + And I act as Jane + And I am logged in as the admin + And I have opened the Talk app + And I open the "user0" conversation + And I see that the chat is shown in the main view + When I act as John + And I type a new chat message with the text "Hello @" + And I choose the candidate mention for "admin" + And I send the current chat message + Then I see that the message 1 was sent by "user0" with the text "Hello admin" + And I see that the message 1 contains a formatted mention of "admin" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello admin" + And I see that the message 1 contains a formatted mention of "admin" as current user + + Scenario: mention a guest from the candidate mentions + Given I act as John + And I am logged in + And I have opened the Talk app + And I create a public conversation named "Public" + And I see that the chat is shown in the main view + And I write down the public conversation link + And I act as Jane + And I visit the public conversation link I wrote down + And I see that the current page is the public conversation link I wrote down + And I see that the chat is shown in the main view + And I set my guest name to "Rob" + When I act as John + And I see that "Rob" is shown in the list of participants as a normal participant + And I type a new chat message with the text "Hello @" + And I choose the candidate mention for "Rob" + And I send the current chat message + # The generated avatar is plain text, so it appears in the message itself + Then I see that the message 1 was sent by "user0" with the text "Hello RRob" + And I see that the message 1 contains a formatted mention of "Rob" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello RRob" + And I see that the message 1 contains a formatted mention of "Rob" as current user + + Scenario: mention a guest that has not set her name yet from the candidate mentions + Given I act as John + And I am logged in + And I have opened the Talk app + And I create a public conversation named "Public" + And I see that the chat is shown in the main view + And I write down the public conversation link + And I act as Jane + And I visit the public conversation link I wrote down + And I see that the current page is the public conversation link I wrote down + And I see that the chat is shown in the main view + When I act as John + And I see that "Guest" is shown in the list of participants as a normal participant + And I type a new chat message with the text "Hello @" + And I choose the candidate mention for "Guest" + And I send the current chat message + # The generated avatar is plain text, so it appears in the message itself + Then I see that the message 1 was sent by "user0" with the text "Hello ?Guest" + And I see that the message 1 contains a formatted mention of "Guest" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello ?Guest" + And I see that the message 1 contains a formatted mention of "Guest" as current user + + Scenario: mention a guest that has cleared her name from the candidate mentions + Given I act as John + And I am logged in + And I have opened the Talk app + And I create a public conversation named "Public" + And I see that the chat is shown in the main view + And I write down the public conversation link + And I act as Jane + And I visit the public conversation link I wrote down + And I see that the current page is the public conversation link I wrote down + And I see that the chat is shown in the main view + And I set my guest name to "Rob" + And I act as John + And I see that "Rob" is shown in the list of participants as a normal participant + And I act as Jane + And I set my guest name to "" + When I act as John + And I see that "Guest" is shown in the list of participants as a normal participant + And I type a new chat message with the text "Hello @" + And I choose the candidate mention for "Guest" + And I send the current chat message + # The generated avatar is plain text, so it appears in the message itself + Then I see that the message 1 was sent by "user0" with the text "Hello ?Guest" + And I see that the message 1 contains a formatted mention of "Guest" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello ?Guest" + And I see that the message 1 contains a formatted mention of "Guest" as current user + + Scenario: mention all users in a public room from the candidate mentions + Given I act as John + And I am logged in + And I have opened the Talk app + And I create a public conversation named "Public" + And I see that the chat is shown in the main view + And I write down the public conversation link + And I act as Jane + And I visit the public conversation link I wrote down + And I see that the current page is the public conversation link I wrote down + And I see that the chat is shown in the main view + When I act as John + And I type a new chat message with the text "Hello @" + And I choose the candidate mention for "Public" + And I send the current chat message + Then I see that the message 1 was sent by "user0" with the text "Hello Public" + And I see that the message 1 contains a formatted mention of all participants of "Public" + And I act as Jane + And I see that the message 1 was sent by "user0" with the text "Hello Public" + And I see that the message 1 contains a formatted mention of all participants of "Public" Scenario: mention another user and a URL Given I am logged in diff --git a/tests/acceptance/features/public-share-auth.feature b/tests/acceptance/features/public-share-auth.feature index cda2e1ce1..967b4d46a 100644 --- a/tests/acceptance/features/public-share-auth.feature +++ b/tests/acceptance/features/public-share-auth.feature @@ -39,17 +39,24 @@ Feature: public share auth And I visit the shared link I wrote down And I see that the current page is the Authenticate page for the shared link I wrote down When I request the password - And I send a new chat message with the text "Hello" - And I see that the message 1 was sent by "Guest" with the text "Hello" + And I send a new chat message with the text "Hello @user0" + And I see that the message 1 was sent by "Guest" with the text "Hello user0" And I act as John And I have opened the Talk app And I open the "Password request: welcome.txt" conversation - And I send a new chat message with the text "Hi!" - Then I see that the message 1 was sent by "Guest" with the text "Hello" - And I see that the message 2 was sent by "user0" with the text "Hi!" + And I type a new chat message with the text "Hi @" + And I choose the candidate mention for "Guest" + And I send the current chat message + Then I see that the message 1 was sent by "Guest" with the text "Hello user0" + And I see that the message 1 contains a formatted mention of "user0" as current user + # The generated avatar is plain text, so it appears in the message itself + And I see that the message 2 was sent by "user0" with the text "Hi ?Guest" + And I see that the message 2 contains a formatted mention of "Guest" And I act as Jane - And I see that the message 1 was sent by "Guest" with the text "Hello" - And I see that the message 2 was sent by "user0" with the text "Hi!" + And I see that the message 1 was sent by "Guest" with the text "Hello user0" + And I see that the message 1 contains a formatted mention of "user0" + And I see that the message 2 was sent by "user0" with the text "Hi ?Guest" + And I see that the message 2 contains a formatted mention of "Guest" as current user Scenario: access a link share with a password protected by Talk after a chat Given I act as John diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php index cff239bee..0c81e2fea 100644 --- a/tests/integration/features/bootstrap/FeatureContext.php +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -780,13 +780,31 @@ class FeatureContext implements Context, SnippetAcceptingContext { } PHPUnit_Framework_Assert::assertCount(count($formData->getHash()), $mentions, 'Mentions count does not match'); - PHPUnit_Framework_Assert::assertEquals($formData->getHash(), array_map(function($mention) { - return [ - 'id' => (string) $mention['id'], - 'label' => (string) $mention['label'], - 'source' => (string) $mention['source'], - ]; - }, $mentions)); + + foreach ($formData->getHash() as $key => $row) { + if ($row['id'] === 'GUEST_ID') { + PHPUnit_Framework_Assert::assertRegExp('/^guest\/[0-9a-f]{40}$/', $mentions[$key]['id']); + $mentions[$key]['id'] = 'GUEST_ID'; + } + PHPUnit_Framework_Assert::assertEquals($row, $mentions[$key]); + } + } + + /** + * @Then /^guest "([^"]*)" sets name to "([^"]*)" in room "([^"]*)" with (\d+)$/ + * + * @param string $user + * @param string $name + * @param string $identifier + * @param string $statusCode + */ + public function guestSetsName($user, $name, $identifier, $statusCode) { + $this->setCurrentUser($user); + $this->sendRequest( + 'POST', '/apps/spreed/api/v1/guest/' . self::$identifierToToken[$identifier] . '/name', + new TableNode([['displayName', $name]]) + ); + $this->assertStatusCode($this->response, $statusCode); } /** diff --git a/tests/integration/features/chat/mentions.feature b/tests/integration/features/chat/mentions.feature index a1d1ce644..504e78f54 100644 --- a/tests/integration/features/chat/mentions.feature +++ b/tests/integration/features/chat/mentions.feature @@ -132,16 +132,25 @@ Feature: chat/mentions | all | room | calls | | participant2 | participant2-displayname | users | | participant3 | participant3-displayname | users | + | GUEST_ID | Guest | guests | And user "participant2" gets the following candidate mentions in room "public room" for "" with 200 | id | label | source | | all | room | calls | | participant1 | participant1-displayname | users | | participant3 | participant3-displayname | users | + | GUEST_ID | Guest | guests | And user "participant3" gets the following candidate mentions in room "public room" for "" with 200 | id | label | source | | all | room | calls | | participant1 | participant1-displayname | users | | participant2 | participant2-displayname | users | + | GUEST_ID | Guest | guests | + And user "guest" gets the following candidate mentions in room "public room" for "" with 200 + | id | label | source | + | all | room | calls | + | participant1 | participant1-displayname | users | + | participant2 | participant2-displayname | users | + | participant3 | participant3-displayname | users | Scenario: get matched mentions in a public room When user "participant1" creates room "public room" @@ -162,6 +171,62 @@ Feature: chat/mentions | id | label | source | | participant1 | participant1-displayname | users | | participant2 | participant2-displayname | users | + And user "guest" gets the following candidate mentions in room "public room" for "part" with 200 + | id | label | source | + | participant1 | participant1-displayname | users | + | participant2 | participant2-displayname | users | + | participant3 | participant3-displayname | users | + + Scenario: get matched guest mentions in a public room + When user "participant1" creates room "public room" + | roomType | 3 | + | roomName | room | + And user "participant1" adds "participant2" to room "public room" with 200 + And user "participant3" joins room "public room" with 200 + And user "guest1" joins room "public room" with 200 + And user "guest2" joins room "public room" with 200 + Then user "participant1" gets the following candidate mentions in room "public room" for "uest" with 200 + | id | label | source | + | GUEST_ID | Guest | guests | + | GUEST_ID | Guest | guests | + And user "participant2" gets the following candidate mentions in room "public room" for "uest" with 200 + | id | label | source | + | GUEST_ID | Guest | guests | + | GUEST_ID | Guest | guests | + And user "participant3" gets the following candidate mentions in room "public room" for "uest" with 200 + | id | label | source | + | GUEST_ID | Guest | guests | + | GUEST_ID | Guest | guests | + And user "guest1" gets the following candidate mentions in room "public room" for "uest" with 200 + | id | label | source | + | GUEST_ID | Guest | guests | + And user "guest2" gets the following candidate mentions in room "public room" for "uest" with 200 + | id | label | source | + | GUEST_ID | Guest | guests | + + Scenario: get matched named guest mentions in a public room + When user "participant1" creates room "public room" + | roomType | 3 | + | roomName | room | + And user "participant1" adds "participant2" to room "public room" with 200 + And user "participant3" joins room "public room" with 200 + And user "guest1" joins room "public room" with 200 + And guest "guest1" sets name to "FooBar" in room "public room" with 200 + And user "guest2" joins room "public room" with 200 + Then user "participant1" gets the following candidate mentions in room "public room" for "oob" with 200 + | id | label | source | + | GUEST_ID | FooBar | guests | + And user "participant2" gets the following candidate mentions in room "public room" for "oob" with 200 + | id | label | source | + | GUEST_ID | FooBar | guests | + And user "participant3" gets the following candidate mentions in room "public room" for "oob" with 200 + | id | label | source | + | GUEST_ID | FooBar | guests | + And user "guest1" gets the following candidate mentions in room "public room" for "oob" with 200 + | id | label | source | + And user "guest2" gets the following candidate mentions in room "public room" for "oob" with 200 + | id | label | source | + | GUEST_ID | FooBar | guests | Scenario: get unmatched mentions in a public room When user "participant1" creates room "public room" @@ -173,6 +238,7 @@ Feature: chat/mentions Then user "participant1" gets the following candidate mentions in room "public room" for "unknown" with 200 And user "participant2" gets the following candidate mentions in room "public room" for "unknown" with 200 And user "participant3" gets the following candidate mentions in room "public room" for "unknown" with 200 + And user "guest" gets the following candidate mentions in room "public room" for "unknown" with 200 Scenario: get mentions in a public room with a participant not in the room When user "participant1" creates room "public room" diff --git a/tests/php/Chat/AutoComplete/SearchPluginTest.php b/tests/php/Chat/AutoComplete/SearchPluginTest.php index 7ce7bfd55..60ce03b5e 100644 --- a/tests/php/Chat/AutoComplete/SearchPluginTest.php +++ b/tests/php/Chat/AutoComplete/SearchPluginTest.php @@ -19,26 +19,34 @@ * */ -namespace OCA\Spreed\Tests\php\Chat; +namespace OCA\Spreed\Tests\php\Chat\AutoComplete; use OCA\Spreed\Chat\AutoComplete\SearchPlugin; use OCA\Spreed\Files\Util; +use OCA\Spreed\GuestManager; +use OCA\Spreed\Participant; use OCA\Spreed\Room; +use OCA\Spreed\TalkSession; use OCP\Collaboration\Collaborators\ISearchResult; +use OCP\IL10N; use OCP\IUser; use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; class SearchPluginTest extends \Test\TestCase { - /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ + /** @var IUserManager|MockObject */ protected $userManager; - - /** @var Util|\PHPUnit_Framework_MockObject_MockObject */ + /** @var GuestManager|MockObject */ + protected $guestManager; + /** @var TalkSession|MockObject */ + protected $talkSession; + /** @var Util|MockObject */ protected $util; - + /** @var IL10N|MockObject */ + protected $l; /** @var string */ protected $userId; - /** @var SearchPlugin */ protected $plugin; @@ -46,8 +54,16 @@ class SearchPluginTest extends \Test\TestCase { parent::setUp(); $this->userManager = $this->createMock(IUserManager::class); + $this->guestManager = $this->createMock(GuestManager::class); + $this->talkSession = $this->createMock(TalkSession::class); $this->util = $this->createMock(Util::class); $this->userId = 'current'; + $this->l = $this->createMock(IL10N::class); + $this->l->expects($this->any()) + ->method('t') + ->willReturnCallback(function($text, $parameters = []) { + return vsprintf($text, $parameters); + }); } /** @@ -58,30 +74,57 @@ class SearchPluginTest extends \Test\TestCase { if (empty($methods)) { return new SearchPlugin( $this->userManager, + $this->guestManager, + $this->talkSession, $this->util, - $this->userId + $this->userId, + $this->l ); } return $this->getMockBuilder(SearchPlugin::class) ->setConstructorArgs([ $this->userManager, + $this->guestManager, + $this->talkSession, $this->util, $this->userId, + $this->l, ]) ->setMethods($methods) ->getMock(); } + protected function createParticipantMock(string $uid, string $session = ''): Participant { + /** @var Participant|MockObject $p */ + $p = $this->createMock(Participant::class); + $p->expects($this->any()) + ->method('getUser') + ->willReturn($uid); + $p->expects($this->any()) + ->method('isGuest') + ->willReturn($uid === ''); + $p->expects($this->any()) + ->method('getSessionId') + ->willReturn($session); + return $p; + } + public function testSearch() { $result = $this->createMock(ISearchResult::class); $room = $this->createMock(Room::class); $room->expects($this->once()) - ->method('getParticipantUserIds') - ->willReturn(['123', 'foo', 'bar']); + ->method('getParticipants') + ->willReturn([ + $this->createParticipantMock('123'), + $this->createParticipantMock('foo'), + $this->createParticipantMock('', '123456'), + $this->createParticipantMock('bar'), + $this->createParticipantMock('', 'abcdef'), + ]); - $plugin = $this->getPlugin(['searchUsers']); + $plugin = $this->getPlugin(['searchUsers', 'searchGuests']); $plugin->setContext(['room' => $room]); $plugin->expects($this->once()) ->method('searchUsers') @@ -91,6 +134,15 @@ class SearchPluginTest extends \Test\TestCase { $this->assertInternalType('string', $user); }, $users); }); + $plugin->expects($this->once()) + ->method('searchGuests') + ->with('fo', $this->anything(), $result) + ->willReturnCallback(function($search, $guests, $result) { + array_map(function($guest) { + $this->assertInternalType('string', $guest); + $this->assertSame(40, strlen($guest)); + }, $guests); + }); $plugin->search('fo', 10, 0, $result); } @@ -145,6 +197,45 @@ class SearchPluginTest extends \Test\TestCase { self::invokePrivate($plugin, 'searchUsers', [$search, $userIds, $result]); } + public function dataSearchGuests() { + return [ + ['test', [], [], [], []], + ['', ['abcdef'], [], [['abcdef' => 'Guest']], []], + ['Guest', ['abcdef'], [], [], [['abcdef' => 'Guest']]], + ['est', ['abcdef', 'foobar'], ['foobar' => 'est'], [['abcdef' => 'Guest']], [['foobar' => 'est']]], + ['Ast', ['abcdef', 'foobar'], ['foobar' => 'ast'], [], [['foobar' => 'ast']]], + ]; + } + + /** + * @dataProvider dataSearchGuests + * @param string $search + * @param string[] $sessionHashes + * @param array $displayNames + * @param array $expected + * @param array $expectedExact + */ + public function testSearchGuests($search, array $sessionHashes, array $displayNames, array $expected, array $expectedExact) { + $result = $this->createMock(ISearchResult::class); + $result->expects($this->once()) + ->method('addResultSet') + ->with($this->anything(), $expected, $expectedExact); + + $this->guestManager->expects($this->any()) + ->method('getNamesBySessionHashes') + ->with($sessionHashes) + ->willReturn($displayNames); + + $plugin = $this->getPlugin(['createGuestResult']); + $plugin->expects($this->any()) + ->method('createGuestResult') + ->willReturnCallback(function($hash, $name) { + return [$hash => $name]; + }); + + self::invokePrivate($plugin, 'searchGuests', [$search, $sessionHashes, $result]); + } + protected function createUserMock(array $userData) { $user = $this->createMock(IUser::class); $user->expects($this->any()) @@ -189,4 +280,23 @@ class SearchPluginTest extends \Test\TestCase { $plugin = $this->getPlugin(); $this->assertEquals($expected, self::invokePrivate($plugin, 'createResult', [$type, $uid, $name])); } + + + public function dataCreateGuestResult(): array { + return [ + ['1234', 'foo', ['label' => 'foo', 'value' => ['shareType' => 'guest', 'shareWith' => 'guest/1234']]], + ['abcd', 'bar', ['label' => 'bar', 'value' => ['shareType' => 'guest', 'shareWith' => 'guest/abcd']]], + ]; + } + + /** + * @dataProvider dataCreateGuestResult + * @param string $sessionHash + * @param string $name + * @param array $expected + */ + public function testCreateGuestResult(string $sessionHash, string $name, array $expected): void { + $plugin = $this->getPlugin(); + $this->assertEquals($expected, self::invokePrivate($plugin, 'createGuestResult', [$sessionHash, $name])); + } } diff --git a/tests/php/Chat/Parser/UserMentionTest.php b/tests/php/Chat/Parser/UserMentionTest.php index c021cf0e8..85eebdc44 100644 --- a/tests/php/Chat/Parser/UserMentionTest.php +++ b/tests/php/Chat/Parser/UserMentionTest.php @@ -24,6 +24,8 @@ declare(strict_types=1); namespace OCA\Spreed\Tests\php\Chat\Parser; use OCA\Spreed\Chat\Parser\UserMention; +use OCA\Spreed\Exceptions\ParticipantNotFoundException; +use OCA\Spreed\GuestManager; use OCA\Spreed\Model\Message; use OCA\Spreed\Participant; use OCA\Spreed\Room; @@ -40,6 +42,8 @@ class UserMentionTest extends \Test\TestCase { protected $commentsManager; /** @var IUserManager|MockObject */ protected $userManager; + /** @var GuestManager|MockObject */ + protected $guestManager; /** @var IL10N|MockObject */ protected $l; @@ -51,9 +55,14 @@ class UserMentionTest extends \Test\TestCase { $this->commentsManager = $this->createMock(ICommentsManager::class); $this->userManager = $this->createMock(IUserManager::class); + $this->guestManager = $this->createMock(GuestManager::class); $this->l = $this->createMock(IL10N::class); - $this->parser = new UserMention($this->commentsManager, $this->userManager, $this->l); + $this->parser = new UserMention( + $this->commentsManager, + $this->userManager, + $this->guestManager, + $this->l); } /** @@ -310,4 +319,163 @@ class UserMentionTest extends \Test\TestCase { $this->assertEquals($expectedMessageParameters, $chatMessage->getMessageParameters()); } + public function testGetRichMessageWithAtAll(): void { + $mentions = [ + ['type' => 'user', 'id' => 'all'], + ]; + $comment = $this->newComment($mentions); + + /** @var Room|MockObject $room */ + $room = $this->createMock(Room::class); + $room->expects($this->once()) + ->method('getType') + ->willReturn(Room::GROUP_CALL); + $room->expects($this->once()) + ->method('getToken') + ->willReturn('token'); + $room->expects($this->once()) + ->method('getDisplayName') + ->willReturn('name'); + /** @var Participant|MockObject $participant */ + $participant = $this->createMock(Participant::class); + /** @var IL10N|MockObject $l */ + $l = $this->createMock(IL10N::class); + $chatMessage = new Message($room, $participant, $comment, $l); + $chatMessage->setMessage('Mention to @all', []); + + $this->parser->parseMessage($chatMessage); + + $expectedMessageParameters = [ + 'mention-call1' => [ + 'type' => 'call', + 'id' => 'token', + 'name' => 'name', + 'call-type' => 'group', + ] + ]; + + $this->assertEquals('Mention to {mention-call1}', $chatMessage->getMessage()); + $this->assertEquals($expectedMessageParameters, $chatMessage->getMessageParameters()); + } + + public function testGetRichMessageWhenAGuestWithoutNameIsMentioned(): void { + $mentions = [ + ['type' => 'guest', 'id' => 'guest/123456'], + ]; + $comment = $this->newComment($mentions); + + /** @var Room|MockObject $room */ + $room = $this->createMock(Room::class); + /** @var Participant|MockObject $participant */ + $participant = $this->createMock(Participant::class); + /** @var IL10N|MockObject $l */ + $l = $this->createMock(IL10N::class); + + $this->guestManager->expects($this->once()) + ->method('getNameBySessionHash') + ->with('123456') + ->willThrowException(new ParticipantNotFoundException()); + $this->l->expects($this->any()) + ->method('t') + ->willReturnCallback(function($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + + $chatMessage = new Message($room, $participant, $comment, $l); + $chatMessage->setMessage('Mention to @"guest/123456"', []); + + $this->parser->parseMessage($chatMessage); + + $expectedMessageParameters = [ + 'mention-guest1' => [ + 'type' => 'guest', + 'id' => 'guest/123456', + 'name' => 'Guest', + ] + ]; + + $this->assertEquals('Mention to {mention-guest1}', $chatMessage->getMessage()); + $this->assertEquals($expectedMessageParameters, $chatMessage->getMessageParameters()); + } + + public function testGetRichMessageWhenAGuestWithoutNameIsMentionedMultipleTimes(): void { + $mentions = [ + ['type' => 'guest', 'id' => 'guest/123456'], + ]; + $comment = $this->newComment($mentions); + + /** @var Room|MockObject $room */ + $room = $this->createMock(Room::class); + /** @var Participant|MockObject $participant */ + $participant = $this->createMock(Participant::class); + /** @var IL10N|MockObject $l */ + $l = $this->createMock(IL10N::class); + + $this->guestManager->expects($this->once()) + ->method('getNameBySessionHash') + ->with('123456') + ->willThrowException(new ParticipantNotFoundException()); + $this->l->expects($this->any()) + ->method('t') + ->willReturnCallback(function($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + + $chatMessage = new Message($room, $participant, $comment, $l); + $chatMessage->setMessage('Mention to @"guest/123456", and again @"guest/123456"', []); + + $this->parser->parseMessage($chatMessage); + + $expectedMessageParameters = [ + 'mention-guest1' => [ + 'type' => 'guest', + 'id' => 'guest/123456', + 'name' => 'Guest', + ] + ]; + + $this->assertEquals('Mention to {mention-guest1}, and again {mention-guest1}', $chatMessage->getMessage()); + $this->assertEquals($expectedMessageParameters, $chatMessage->getMessageParameters()); + } + + public function testGetRichMessageWhenAGuestWithANameIsMentionedMultipleTimes(): void { + $mentions = [ + ['type' => 'guest', 'id' => 'guest/abcdef'], + ]; + $comment = $this->newComment($mentions); + + /** @var Room|MockObject $room */ + $room = $this->createMock(Room::class); + /** @var Participant|MockObject $participant */ + $participant = $this->createMock(Participant::class); + /** @var IL10N|MockObject $l */ + $l = $this->createMock(IL10N::class); + + $this->guestManager->expects($this->once()) + ->method('getNameBySessionHash') + ->with('abcdef') + ->willReturn('Name'); + $this->l->expects($this->any()) + ->method('t') + ->willReturnCallback(function($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + + $chatMessage = new Message($room, $participant, $comment, $l); + $chatMessage->setMessage('Mention to @"guest/abcdef", and again @"guest/abcdef"', []); + + $this->parser->parseMessage($chatMessage); + + $expectedMessageParameters = [ + 'mention-guest1' => [ + 'type' => 'guest', + 'id' => 'guest/abcdef', + 'name' => 'Name', + ] + ]; + + $this->assertEquals('Mention to {mention-guest1}, and again {mention-guest1}', $chatMessage->getMessage()); + $this->assertEquals($expectedMessageParameters, $chatMessage->getMessageParameters()); + } + } diff --git a/tests/php/Controller/SignalingControllerTest.php b/tests/php/Controller/SignalingControllerTest.php index c93ee8d09..49d67f8cf 100644 --- a/tests/php/Controller/SignalingControllerTest.php +++ b/tests/php/Controller/SignalingControllerTest.php @@ -700,6 +700,7 @@ class SignalingControllerTest extends \Test\TestCase { $this->secureRandom, $this->createMock(IUserManager::class), $this->createMock(CommentsManager::class), + $this->createMock(TalkSession::class), $dispatcher, $this->timeFactory, $this->createMock(IHasher::class), diff --git a/tests/php/Signaling/BackendNotifierTest.php b/tests/php/Signaling/BackendNotifierTest.php index 078b8f8a0..d62653879 100644 --- a/tests/php/Signaling/BackendNotifierTest.php +++ b/tests/php/Signaling/BackendNotifierTest.php @@ -29,6 +29,7 @@ use OCA\Spreed\Manager; use OCA\Spreed\Participant; use OCA\Spreed\Room; use OCA\Spreed\Signaling\BackendNotifier; +use OCA\Spreed\TalkSession; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Http\Client\IClientService; use OCP\IGroupManager; @@ -129,6 +130,7 @@ class BackendNotifierTest extends \Test\TestCase { $this->secureRandom, $this->createMock(IUserManager::class), $this->createMock(CommentsManager::class), + $this->createMock(TalkSession::class), $dispatcher, $this->timeFactory, $this->createMock(IHasher::class), |