diff --git a/tests/e2e/cucumber/features/smoke/fullTextSearch.ocis.feature b/tests/e2e/cucumber/features/smoke/fullTextSearch.ocis.feature new file mode 100644 index 00000000000..adf755b1d68 --- /dev/null +++ b/tests/e2e/cucumber/features/smoke/fullTextSearch.ocis.feature @@ -0,0 +1,103 @@ +Feature: Search + As a user + I want to search for resources + So that I can find them quickly + + Background: + Given "Admin" creates following users using API + | id | + | Alice | + | Brian | + And "Admin" sets the default folder for received shares to "Shares" + And "Admin" disables share auto accepting + And "Admin" assigns following roles to the users using API + | id | role | + | Brian | Space Admin | + + And "Alice" logs in + And "Alice" creates the following folder in personal space using API + | name | + | folderToShare | + And "Alice" uploads the following local file into personal space using API + | localFile | to | + | filesForUpload/textfile.txt | folderToShare/fileToShare.txt | + And "Alice" shares the following resource using API + | resource | recipient | type | role | + | folderToShare | Brian | user | Can edit | + + And "Brian" logs in + And "Brian" accepts the following share using API + | name | + | folderToShare | + And "Brian" creates the following folder in personal space using API + | name | + | testFolder | + And "Brian" uploads the following local file into personal space using API + | localFile | to | + | filesForUpload/textfile.txt | textfile.txt | + | filesForUpload/textfile.txt | fileWithTag.txt | + | filesForUpload/textfile.txt | withTag.txt | + | filesForUpload/textfile.txt | testFolder/innerTextfile.txt | + + And "Brian" creates the following project spaces using API + | name | id | + | FullTextSearch | fulltextsearch.1 | + And "Brian" creates the following folder in space "FullTextSearch" using API + | name | + | spaceFolder | + And "Brian" creates the following file in space "FullTextSearch" using API + | name | content | + | spaceFolder/spaceTextfile.txt | This is test file. | + + And "Brian" opens the "files" app +# And "Brian" adds the following tags for the following resources using API +# | resource | tags | +# | fileWithTag.txt | tag 1 | +# | withTag.txt | tag 1 | + And "Brian" adds the following tags for the following resources using the sidebar panel + | resource | tags | + | fileWithTag.txt | tag 1 | + | withTag.txt | tag 1 | + + Scenario: Search for content of file + And "Brian" opens the "files" app + + When "Brian" searches "" using the global search bar + Then "Brian" should see the message "Search for files" on the webUI + + When "Brian" selects tag "tag 1" from the search result filter chip + Then following resources should be displayed in the files list for user "Brian" + | resource | + | fileWithTag.txt | + | withTag.txt | + + When "Brian" searches "file" using the global search bar + Then following resources should be displayed in the files list for user "Brian" + | resource | + | fileWithTag.txt | + + When "Brian" clear tag filter from the search result filter chip + Then following resources should be displayed in the files list for user "Brian" + | resource | + | textfile.txt | + | fileWithTag.txt | + | testFolder/innerTextfile.txt | + | fileToShare.txt | + | spaceFolder/spaceTextfile.txt | + + When "Brian" enables the option to search in file content + And "Brian" searches "Cheers" using the global search bar + Then following resources should be displayed in the files list for user "Brian" + | resource | + | textfile.txt | + | testFolder/innerTextfile.txt | + | fileToShare.txt | + | fileWithTag.txt | + | withTag.txt | + + When "Brian" opens the following file in texteditor + | resource | + | textfile.txt | + And "Brian" closes the editor + Then "Brian" should see the message "No results found" on the webUI + And "Brian" logs out diff --git a/tests/e2e/cucumber/steps/api.ts b/tests/e2e/cucumber/steps/api.ts index 80ea257e137..52842a628ce 100644 --- a/tests/e2e/cucumber/steps/api.ts +++ b/tests/e2e/cucumber/steps/api.ts @@ -298,3 +298,22 @@ Given( } } ) + +// Given( +// '{string} adds the following tags for the following resources using API', +// async function ( +// this: World, +// stepUser: string, +// stepTable: DataTable +// ): Promise { +// const user = this.usersEnvironment.getUser({ key: stepUser }) +// for (const info of stepTable.hashes()) { +// await api.graph.addTagsToTheResource({ +// user, +// shareWith: info.user, +// shareType: info.shareType, +// role: info.role +// }) +// } +// } +// ) diff --git a/tests/e2e/cucumber/steps/ui/resources.ts b/tests/e2e/cucumber/steps/ui/resources.ts index 4de7deb015f..b4aaf162727 100644 --- a/tests/e2e/cucumber/steps/ui/resources.ts +++ b/tests/e2e/cucumber/steps/ui/resources.ts @@ -261,6 +261,7 @@ Then( const actualList = await resourceObject.getDisplayedResources({ keyword: listType as displayedResourceType }) + console.log(actualList) for (const info of stepTable.hashes()) { expect(actualList.includes(info.resource)).toBe(actionType === 'should') } @@ -433,15 +434,15 @@ When( ) When( - /^"([^"].*)" opens the following file(?:s)? in (mediaviewer|pdfviewer)$/, + /^"([^"].*)" opens the following file(?:s)? in (mediaviewer|pdfviewer|texteditor)$/, async function (this: World, stepUser: string, actionType: string, stepTable: DataTable) { const { page } = this.actorsEnvironment.getActor({ key: stepUser }) const resourceObject = new objects.applicationFiles.Resource({ page }) for (const info of stepTable.hashes()) { - await resourceObject.openFileInViewer({ + await resourceObject.openFile({ name: info.resource, - actionType: actionType as 'mediaviewer' | 'pdfviewer' + actionType: actionType as 'mediaviewer' | 'pdfviewer' | 'texteditor' }) } } diff --git a/tests/e2e/cucumber/steps/ui/search.ts b/tests/e2e/cucumber/steps/ui/search.ts new file mode 100644 index 00000000000..2ce68f9dfb9 --- /dev/null +++ b/tests/e2e/cucumber/steps/ui/search.ts @@ -0,0 +1,44 @@ +import { When, Then } from "@cucumber/cucumber"; +import { World } from "../../environment"; +import { objects } from '../../../support' +import { expect } from '@playwright/test' + +When( + '{string} searches {string} using the global search bar', + async function (this: World, stepUser: string, keyword: string): Promise { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const searchObject = new objects.applicationFiles.Search({ page }) + await searchObject.fullTextSearch({ keyword }) + } +) + +Then( + '{string} should see the message {string} on the webUI', + async function (this: World, stepUser: string, message: string): Promise { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const searchObject = new objects.applicationFiles.Search({ page }) + const actualMessage = await searchObject.getSearchResultMessage() + console.log(actualMessage) + expect(actualMessage).toBe(message); + } +) + +When('{string} selects tag {string} from the search result filter chip', async function (this: World, stepUser: string, tag: string): Promise { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const searchObject = new objects.applicationFiles.Search({ page }) + await searchObject.selectTagFilter({ tag }) +}); + +When('{string} clear tag filter from the search result filter chip', async function (this: World, stepUser: string): Promise { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const searchObject = new objects.applicationFiles.Search({ page }) + await searchObject.clearTagFilter() +}); + +When(/^"([^"]*)" (enable|disable)s the option to search in file content?$/, async function (this: World, stepUser: string, enableOrDisable: string): Promise { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const searchObject = new objects.applicationFiles.Search({ page }) + await searchObject.toggleSearchInFileContent({ enableOrDisable }) +}); + + diff --git a/tests/e2e/support/objects/app-files/index.ts b/tests/e2e/support/objects/app-files/index.ts index 65c97d86c35..d55795899dd 100644 --- a/tests/e2e/support/objects/app-files/index.ts +++ b/tests/e2e/support/objects/app-files/index.ts @@ -4,3 +4,4 @@ export { Resource } from './resource' export { Share } from './share' export { Spaces } from './spaces' export { Trashbin } from './trashbin' +export { Search } from './search' diff --git a/tests/e2e/support/objects/app-files/resource/actions.ts b/tests/e2e/support/objects/app-files/resource/actions.ts index 961a2343d7d..151a00bdd22 100644 --- a/tests/e2e/support/objects/app-files/resource/actions.ts +++ b/tests/e2e/support/objects/app-files/resource/actions.ts @@ -23,7 +23,7 @@ const checkBoxForTrashbin = `//*[@data-test-resource-path="%s"]//ancestor::tr//i export const fileRow = '//ancestor::*[(contains(@class, "oc-tile-card") or contains(@class, "oc-tbody-tr"))]' export const resourceNameSelector = - ':is(#files-space-table, .oc-tiles-item, #files-shared-with-me-accepted-section) [data-test-resource-name="%s"]' + ':is(#files-space-table, .oc-tiles-item, #files-shared-with-me-accepted-section, .files-table) [data-test-resource-name="%s"]' const breadcrumbResourceNameSelector = '//span[contains(@class, "oc-breadcrumb-item-text") and text()="%s"]' const addNewResourceButton = `#new-file-menu-btn` @@ -1106,13 +1106,13 @@ export const removeTagsFromResource = async (args: resourceTagsArgs): Promise => { +export const openFile = async (args: openFileArgs): Promise => { const { page, name, actionType } = args if (actionType === 'mediaviewer') { @@ -1137,7 +1137,7 @@ export const openFileInViewer = async (args: openFileInViewerArgs): Promise): Promise { - await po.openFileInViewer({ ...args, page: this.#page }) + async openFile(args: Omit): Promise { + await po.openFile({ ...args, page: this.#page }) } async addTags(args: Omit): Promise { diff --git a/tests/e2e/support/objects/app-files/search/actions.ts b/tests/e2e/support/objects/app-files/search/actions.ts new file mode 100644 index 00000000000..f00c5492248 --- /dev/null +++ b/tests/e2e/support/objects/app-files/search/actions.ts @@ -0,0 +1,38 @@ +import {Page} from 'playwright' +import util from 'util' + +const globalSearchInputSelector = '.oc-search-input' +const searchResultMessageSelector = '//p[@class="oc-text-muted"]' +const selectTagDropdownSelector = '.files-search-filter-tags' +const tagFilterChipSelector = '//button[contains(@data-test-value,"%s")]' +const clearTagFilterSelector = '//div[contains(@class,"files-search-filter-tags")]//button[contains(@class,"oc-filter-chip-clear")]' +const enableSearchInFileContentSelector = '//div[contains(@class,"files-search-filter-full-text")]//button[contains(@class,"oc-filter-chip-button")]' +const disableSearchInFileContentSelector = '//div[contains(@class,"files-search-filter-full-text")]//button[contains(@class,"oc-filter-chip-clear")]' +export interface fullTextSearchArgs { + keyword: string + page: Page +} +export const fullTextSearch = async ( + args: fullTextSearchArgs +): Promise => { + const { page, keyword } = args + await page.locator(globalSearchInputSelector).fill(keyword) + await page.keyboard.press('Enter') +} + +export const getSearchResultMessage = async ({ page }): Promise => { + return await page.locator(searchResultMessageSelector).innerText() +} + +export const selectTagFilter = async ({ tag, page }): Promise => { + await page.locator(selectTagDropdownSelector).click() + await page.locator(util.format(tagFilterChipSelector, tag)).click() +} + +export const clearTagFilter = async ({ page }): Promise => { + await page.locator(clearTagFilterSelector).click() +} + +export const toggleSearchInFileContent = async ({ enableOrDisable, page }): Promise => { + enableOrDisable === 'enable' ? await page.locator(enableSearchInFileContentSelector).click() : await page.locator(disableSearchInFileContentSelector).click() +} diff --git a/tests/e2e/support/objects/app-files/search/index.ts b/tests/e2e/support/objects/app-files/search/index.ts new file mode 100644 index 00000000000..ca4d718dd95 --- /dev/null +++ b/tests/e2e/support/objects/app-files/search/index.ts @@ -0,0 +1,30 @@ +import {Page} from 'playwright' +import * as po from "../search/actions"; + +export class Search { + #page: Page + + constructor({page}: { page: Page }) { + this.#page = page + } + + async fullTextSearch(args: Omit): Promise { + await po.fullTextSearch({...args, page: this.#page}) + } + + async getSearchResultMessage(): Promise { + return await po.getSearchResultMessage({page: this.#page}) + } + + async selectTagFilter({tag: string}): Promise { + await po.selectTagFilter({tag: string, page: this.#page}) + } + + async clearTagFilter(): Promise { + await po.clearTagFilter({page: this.#page}) + } + + async toggleSearchInFileContent({enableOrDisable: string}): Promise { + await po.toggleSearchInFileContent({ enableOrDisable: string, page: this.#page}) + } +}