From 64d5ceab0f21508ef9890083e049ebb7a29b4365 Mon Sep 17 00:00:00 2001 From: Rostislav Nazmeev Date: Mon, 30 Sep 2024 07:35:52 +0200 Subject: [PATCH] New planner tests (#6728) Signed-off-by: Rostislav Nazmeev --- .../tests/model/planning/planning-page.ts | 56 ++++++++ .../model/tracker/issues-details-page.ts | 11 ++ tests/sanity/tests/planning/plan.spec.ts | 126 +++++++++++++++++- tests/sanity/tests/planning/todos.spec.ts | 85 +++++++++++- tests/sanity/tests/utils.ts | 11 +- 5 files changed, 284 insertions(+), 5 deletions(-) diff --git a/tests/sanity/tests/model/planning/planning-page.ts b/tests/sanity/tests/model/planning/planning-page.ts index eb38724e01..575bd9d258 100644 --- a/tests/sanity/tests/model/planning/planning-page.ts +++ b/tests/sanity/tests/model/planning/planning-page.ts @@ -33,6 +33,8 @@ export class PlanningPage extends CalendarPage { readonly buttonPopupVisibleToEveryone = (): Locator => this.popup().getByRole('button', { name: 'Visible to everyone' }) + readonly buttonCreateRelatedIssue = (): Locator => this.page.locator('.popup button:has-text("New related issue")') + readonly buttonPopupOnlyVisibleToYou = (): Locator => this.popup().getByRole('button', { name: 'Only visible to you' }) @@ -91,6 +93,15 @@ export class PlanningPage extends CalendarPage { readonly checkboxToDoInToDos = (hasText: string): Locator => this.toDoInToDos(hasText).locator('div.hulyToDoLine-checkbox') + readonly buttonTagByName = (tagName: string): Locator => + this.page.locator(`#navGroup-tags button:has-text("${tagName}")`) + + readonly labelToDoReference = (toDoName: string): Locator => + this.page + .locator('button.hulyToDoLine-container div[class$="overflow-label"]', { hasText: toDoName }) + .locator('xpath=..') + .locator('button.reference') + async dragToCalendar (title: string, column: number, time: string, addHalf: boolean = false): Promise { await this.toDosContainer().getByRole('button', { name: title }).hover() @@ -106,6 +117,27 @@ export class PlanningPage extends CalendarPage { }).toPass(retryOptions) } + async moveToDoBorderByMouse ( + title: string, + column: number, + targetTime: string, + size: 'top' | 'bottom' + ): Promise { + await this.page + .locator(`.calendar-element:has-text("${title}") .calendar-element-${size === 'top' ? 'start' : 'end'}`) + .hover() + + await expect(async () => { + await this.page.mouse.down() + const boundingBox = await this.selectTimeCell(targetTime, column).boundingBox() + expect(boundingBox).toBeTruthy() + if (boundingBox != null) { + await this.page.mouse.move(boundingBox.x + 10, size === 'bottom' ? boundingBox.y - 8 : boundingBox.y + 5) + await this.page.mouse.up() + } + }).toPass(retryOptions) + } + async checkInSchedule (title: string): Promise { await expect(this.eventInSchedule(title)).toBeVisible() } @@ -245,6 +277,12 @@ export class PlanningPage extends CalendarPage { await expect(this.page.locator(`button.hulyToDoLine-container:has-text("${toDoName}")`)).toHaveCount(1) } + async checkToDoExistAndShowDuration (toDoName: string, duration: string): Promise { + await expect( + this.page.locator(`button.hulyToDoLine-container:has-text("${toDoName}"):has-text("${duration}")`) + ).toHaveCount(1) + } + async checkToDo (data: NewToDo): Promise { await expect(this.textPanelToDoTitle()).toHaveValue(data.title) if (data.description != null) { @@ -293,6 +331,24 @@ export class PlanningPage extends CalendarPage { .click() } + async openReferenceToDoByName (toDoName: string): Promise { + await this.labelToDoReference(toDoName).click() + } + + async getReferenceNameToDoByName (toDoName: string): Promise { + return await this.labelToDoReference(toDoName).textContent() + } + + async checkIfReferenceIsOpen (toDoName: string): Promise { + const referenceName = await this.getReferenceNameToDoByName(toDoName) + await this.openReferenceToDoByName(toDoName) + await expect(this.page.locator(`.popupPanel .hulyHeader-row:has-text("${referenceName}")`)).toBeVisible() + } + + async clickButtonTagByName (tagName: string): Promise { + await this.buttonTagByName(tagName).click() + } + async checkToDoExistInCalendar (toDoName: string, count: number): Promise { await expect( this.page.locator('div.calendar-element > div.event-container >> div[class*="label"]', { hasText: toDoName }) diff --git a/tests/sanity/tests/model/tracker/issues-details-page.ts b/tests/sanity/tests/model/tracker/issues-details-page.ts index 270646f99b..53fb1f555f 100644 --- a/tests/sanity/tests/model/tracker/issues-details-page.ts +++ b/tests/sanity/tests/model/tracker/issues-details-page.ts @@ -69,6 +69,11 @@ export class IssuesDetailsPage extends CommonTrackerPage { return this.popup().locator(this.page.getByRole('button', { name: nameDr })) } + readonly rowDecriptionToDo = (hasText: string): Locator => this.page.locator('div.tiptap div.todo-item', { hasText }) + readonly assigneeToDo = (hasText: string): Locator => this.rowDecriptionToDo(hasText).locator('div.assignee') + readonly checkboxToDo = (hasText: string): Locator => this.rowDecriptionToDo(hasText).locator('input.chBox') + readonly slashActionItemsPopup = (): Locator => this.page.locator('.selectPopup') + async clickCloseIssueButton (): Promise { await this.buttonCloseIssue().click() } @@ -230,4 +235,10 @@ export class IssuesDetailsPage extends CommonTrackerPage { async checkIfButtonCbuttonCreatedByHaveTextCreatedBy (createdBy: string): Promise { await expect(this.buttonCreatedBy()).toHaveText(createdBy) } + + async assignToDo (user: string, text: string): Promise { + await this.rowDecriptionToDo(text).hover() + await this.assigneeToDo(text).click() + await this.selectListItem(user) + } } diff --git a/tests/sanity/tests/planning/plan.spec.ts b/tests/sanity/tests/planning/plan.spec.ts index 79fd0ece1a..b1014f984b 100644 --- a/tests/sanity/tests/planning/plan.spec.ts +++ b/tests/sanity/tests/planning/plan.spec.ts @@ -1,4 +1,4 @@ -import { test } from '@playwright/test' +import { expect, test } from '@playwright/test' import { generateId, PlatformSetting, @@ -21,6 +21,8 @@ import { SidebarPage } from '../model/sidebar-page' import { TeamPage } from '../model/team-page' import { SelectWorkspacePage } from '../model/select-workspace-page' import { ChannelPage } from '../model/channel-page' +import { IssuesPage } from '../model/tracker/issues-page' +import { NewIssue } from '../model/tracker/types' test.use({ storageState: PlatformSetting @@ -31,7 +33,7 @@ test.describe('Planning ToDo tests', () => { await (await page.goto(`${PlatformURI}/workbench/sanity-ws/time`))?.finished() }) - test('Add several slots for the same day', async ({ browser, page }) => { + test('Add several slots for the same day', async ({ page }) => { const dateEnd = new Date() const toDoSeveralSlots: NewToDo = { title: 'Add several slots for the same day', @@ -74,6 +76,27 @@ test.describe('Planning ToDo tests', () => { } await planningPage.clickButtonCardClose() + await test.step('User is able to create Related Issue for Action Item', async () => { + const issuesPage = new IssuesPage(page) + const leftMenuPage = new LeftSideMenuPage(page) + const relatedIssueData: NewIssue = { + title: `ToDo Related Issue ${generateId()}`, + description: 'Description', + projectName: 'Default' + } + + await planningPage.eventInSchedule(toDoSeveralSlots.title).first().click({ button: 'right' }) + await planningPage.buttonCreateRelatedIssue().click() + + await issuesPage.fillNewIssueForm(relatedIssueData) + await issuesPage.clickButtonCreateIssue() + await leftMenuPage.clickTracker() + await issuesPage.clickLinkSidebarAll() + await issuesPage.searchIssueByName(relatedIssueData.title) + + await (await page.goto(`${PlatformURI}/workbench/sanity-ws/time`))?.finished() + }) + await planningPage.checkToDoExistInCalendar(toDoSeveralSlots.title, 2) }) @@ -192,6 +215,7 @@ test.describe('Planning ToDo tests', () => { const titleV = `Visible ToDo ${generateId()}` const titleI = `Inisible ToDo ${generateId()}` const time = getTimeForPlanner() + const time2 = getTimeForPlanner(1) const leftSideMenuPage: LeftSideMenuPage = new LeftSideMenuPage(page) const loginPage: LoginPage = new LoginPage(page) @@ -217,6 +241,11 @@ test.describe('Planning ToDo tests', () => { await planningPage.buttonPopupVisibleToEveryone().click() await planningPage.buttonPopupSave().click() + await test.step('User is able to create multiple by dragging slots to the same Action Item', async () => { + await planningPage.dragToCalendar(titleV, 3, time2) + await planningPage.checkToDoExistInCalendar(titleV, 2) + }) + await planningPage.selectInputToDo().fill(titleI) await planningPage.selectInputToDo().press('Enter') await planningPage.dragToCalendar(titleI, 2, time, true) @@ -262,7 +291,98 @@ test.describe('Planning ToDo tests', () => { }) }) - test('User is able to open Planner in Sidebar', async ({ browser, page, request }) => { + test.only('ToDo labels are exist in Tag list', async ({ page }) => { + const planningPage = new PlanningPage(page) + const planningNavigationMenuPage = new PlanningNavigationMenuPage(page) + + const toDoWithLabel: NewToDo = { + title: `ToDo with label-${generateId()}`, + description: 'Description for ToDo with label', + duedate: 'today', + priority: 'Medium', + visible: 'FreeBusy', + labels: `TAG-${generateId()}`, + createLabel: true + } + + const toDoWithoutLabel: NewToDo = { + title: `ToDo without label-${generateId()}`, + description: 'Description for ToDo without label', + duedate: 'today', + priority: 'Medium', + visible: 'FreeBusy' + } + + await test.step('Prepare ToDo with label', async () => { + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.createNewToDo(toDoWithLabel) + await planningPage.openToDoByName(toDoWithLabel.title) + await planningPage.updateToDo(toDoWithLabel) + await planningPage.clickButtonCardClose() + }) + + await test.step('Prepare ToDo without label', async () => { + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.createNewToDo(toDoWithoutLabel) + }) + + await test.step('Labels are added to tag list', async () => { + await planningPage.checkToDoExist(toDoWithLabel.title) + await planningPage.checkToDoExist(toDoWithoutLabel.title) + + if (typeof toDoWithLabel.labels === 'string') { + await expect(planningPage.buttonTagByName(toDoWithLabel.labels)).toBeVisible() + } + }) + + await test.step('Click to the tag and filter todos', async () => { + if (typeof toDoWithLabel.labels === 'string') { + await planningPage.clickButtonTagByName(toDoWithLabel.labels) + await planningPage.checkToDoExist(toDoWithLabel.title) + await planningPage.checkToDoNotExist(toDoWithoutLabel.title) + } + }) + }) + + test('Change ToDo start and end times by dragging', async ({ page }) => { + const planningPage = new PlanningPage(page) + const planningNavigationMenuPage = new PlanningNavigationMenuPage(page) + const dateEnd = new Date() + + const toDoWithLabel: NewToDo = { + title: `ToDo to change duration-${generateId()}`, + description: 'Description for ToDo to change duration', + slots: [ + { + dateStart: 'today', + timeStart: '1400', + dateEnd: { + day: dateEnd.getDate().toString(), + month: (dateEnd.getMonth() + 1).toString(), + year: dateEnd.getFullYear().toString() + }, + timeEnd: '1500' + } + ] + } + + await test.step('Prepare ToDo', async () => { + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.createNewToDo(toDoWithLabel) + }) + + await test.step('Resize ToDo', async () => { + await planningPage.moveToDoBorderByMouse(toDoWithLabel.title, 1, '4pm', 'bottom') + await planningPage.moveToDoBorderByMouse(toDoWithLabel.title, 1, '1pm', 'top') + }) + + await test.step('Check time changes', async () => { + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.checkToDoExistAndShowDuration(toDoWithLabel.title, '3h') + }) + }) + + test('User is able to open Planner in Sidebar', async ({ page }) => { const leftMenuPage = new LeftSideMenuPage(page) const channelPage = new ChannelPage(page) diff --git a/tests/sanity/tests/planning/todos.spec.ts b/tests/sanity/tests/planning/todos.spec.ts index 67459269fa..0dfab53979 100644 --- a/tests/sanity/tests/planning/todos.spec.ts +++ b/tests/sanity/tests/planning/todos.spec.ts @@ -3,6 +3,11 @@ import { generateId, PlatformSetting, PlatformURI } from '../utils' import { PlanningPage } from '../model/planning/planning-page' import { NewToDo } from '../model/planning/types' import { PlanningNavigationMenuPage } from '../model/planning/planning-navigation-menu-page' +import { IssuesPage } from '../model/tracker/issues-page' +import { IssuesDetailsPage } from '../model/tracker/issues-details-page' +import { LeftSideMenuPage } from '../model/left-side-menu-page' +import { DocumentsPage } from '../model/documents/documents-page' +import { DocumentContentPage } from '../model/documents/document-content-page' test.use({ storageState: PlatformSetting @@ -11,6 +16,12 @@ test.use({ const retryOptions = { intervals: [1000, 1500, 2500], timeout: 60000 } test.describe('Planning ToDo tests', () => { + let issuesPage: IssuesPage + let issuesDetailsPage: IssuesDetailsPage + let leftSideMenuPage: LeftSideMenuPage + let documentsPage: DocumentsPage + let documentContentPage: DocumentContentPage + test.beforeEach(async ({ page }) => { await (await page.goto(`${PlatformURI}/workbench/sanity-ws/time`))?.finished() }) @@ -109,7 +120,7 @@ test.describe('Planning ToDo tests', () => { }) }) - test('Delete ToDo', async ({ page }) => { + test('Delete a ToDo', async ({ page }) => { const deleteToDo: NewToDo = { title: 'ToDo For delete' } @@ -151,4 +162,76 @@ test.describe('Planning ToDo tests', () => { await planningPage.checkToDoExist(newToDoPlanned.title) await planningPage.checkToDoExist(newToDoUnPlanned.title) }) + + test('Show ActionItem in Planner from Issue description', async ({ page }) => { + issuesPage = new IssuesPage(page) + issuesDetailsPage = new IssuesDetailsPage(page) + leftSideMenuPage = new LeftSideMenuPage(page) + const planningNavigationMenuPage = new PlanningNavigationMenuPage(page) + const planningPage = new PlanningPage(page) + const toDoName = `ToDo from issue ${generateId()}` + + const newIssue = { + title: `Issue with ToDos ${generateId()}`, + description: '', + projectName: 'Default' + } + + await test.step('Prepare Issue and add ActionItems to that', async () => { + await leftSideMenuPage.clickTracker() + await issuesPage.clickNewIssue() + await issuesPage.fillNewIssueForm(newIssue) + await issuesPage.clickButtonCreateIssue() + await issuesPage.clickLinkSidebarAll() + await issuesPage.openIssueByName(newIssue.title) + await issuesDetailsPage.editIssue({ assignee: 'Appleseed John', status: 'ToDo' }) + + await issuesDetailsPage.addToDescription('/') + await issuesDetailsPage.slashActionItemsPopup().getByText('Action item').click() + await issuesPage.page.keyboard.type(toDoName) + await issuesPage.page.keyboard.press('Escape') + await issuesDetailsPage.assignToDo('Appleseed John', toDoName) + }) + + await test.step('Check ToDo in Planner', async () => { + await leftSideMenuPage.clickPlanner() + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.checkToDoExist(toDoName) + await planningPage.checkIfReferenceIsOpen(toDoName) + }) + }) + + test('Show ActionItem in Planner from Document', async ({ page }) => { + documentsPage = new DocumentsPage(page) + documentContentPage = new DocumentContentPage(page) + leftSideMenuPage = new LeftSideMenuPage(page) + const planningNavigationMenuPage = new PlanningNavigationMenuPage(page) + const planningPage = new PlanningPage(page) + const toDoName = `ToDo from document ${generateId()}` + + const newDocument = { + title: `Document with ToDos ${generateId()}`, + space: 'Default' + } + + await test.step('Prepare Document and add ActionItems to that', async () => { + await leftSideMenuPage.clickDocuments() + await documentsPage.buttonCreateDocument().click() + await documentsPage.createDocument(newDocument) + await documentsPage.openDocument(newDocument.title) + await documentContentPage.addContentToTheNewLine('/') + + await documentContentPage.slashActionItemsPopup().getByText('Action item').click() + await documentContentPage.page.keyboard.type(toDoName) + await documentContentPage.page.keyboard.press('Escape') + await documentContentPage.assignToDo('Appleseed John', toDoName) + }) + + await test.step('Check ToDo in Planner', async () => { + await leftSideMenuPage.clickPlanner() + await planningNavigationMenuPage.clickOnButtonToDoAll() + await planningPage.checkToDoExist(toDoName) + await planningPage.checkIfReferenceIsOpen(toDoName) + }) + }) }) diff --git a/tests/sanity/tests/utils.ts b/tests/sanity/tests/utils.ts index eb591c7e80..ad43112342 100644 --- a/tests/sanity/tests/utils.ts +++ b/tests/sanity/tests/utils.ts @@ -36,8 +36,17 @@ export function generateTestData (): TestData { } } -export function getTimeForPlanner (): string { +export function getTimeForPlanner (plusHours?: number): string { let hour = new Date().getHours() + if (typeof plusHours === 'number') hour += plusHours + const ampm = hour < 13 ? 'am' : 'pm' + hour = hour < 1 ? 1 : hour >= 11 && hour < 13 ? 11 : hour >= 22 ? 10 : hour > 12 ? hour - 12 : hour + + return `${hour}${ampm}` +} + +export function getNextHourTimeForPlanner (): string { + let hour = new Date().getHours() + 1 const ampm = hour < 13 ? 'am' : 'pm' hour = hour < 1 ? 1 : hour >= 11 && hour < 13 ? 11 : hour >= 22 ? 10 : hour > 12 ? hour - 12 : hour