UBERF-8005: Add tests to tracker projects, fix failed tests (#6454)

Signed-off-by: Rostislav Nazmeev <rostropovich@culturalcode.ru>
This commit is contained in:
Rostislav Nazmeev 2024-09-04 08:52:38 +02:00 committed by GitHub
parent 60444ebdab
commit b0e523eb17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 234 additions and 39 deletions

View File

@ -13,7 +13,7 @@ export class UserProfilePage {
selectProfile = (name: string): Locator => this.page.locator(`text=${name}`)
leaveWorkspaceButton = (): Locator => this.page.getByRole('button', { name: 'Leave workspace' })
leaveWorkspaceCancelButton = (): Locator => this.page.getByRole('button', { name: 'Cancel' })
leaveWorkspaceConfirmButton = (): Locator => this.page.getByRole('button', { name: 'Ok' })
leaveWorkspaceConfirmButton = (): Locator => this.page.getByRole('button', { name: 'Ok', exact: true })
accountDissabledMessage = (): Locator => this.page.getByRole('heading')
changeAccount = (): Locator => this.page.getByRole('link', { name: 'Change account' })
settings = (): Locator => this.page.getByRole('button', { name: 'Settings' })

View File

@ -0,0 +1,31 @@
import { expect, type Locator } from '@playwright/test'
import { CommonTrackerPage } from './common-tracker-page'
export class AllProjectsPage extends CommonTrackerPage {
projectTitleCells = (): Locator => this.page.locator('.antiTable-body__row .antiTable-cells__firstCell')
async checkProjectExistInTable (projectName: string): Promise<void> {
await expect(this.projectTitleCells().filter({ hasText: projectName })).toBeVisible()
}
async checkProjectNotExistInTable (projectName: string): Promise<void> {
await expect(this.projectTitleCells().filter({ hasText: projectName })).toBeHidden()
}
async joinProject (title: string): Promise<void> {
const projectRow = this.page.locator('.antiTable-body__row', { has: this.page.locator(`td:has-text("${title}")`) })
const joinButton = projectRow.locator('button:has-text("Join")')
await joinButton.click()
}
async unarchiveProject (title: string): Promise<void> {
const projectRow = this.page.locator('.antiTable-body__row', { has: this.page.locator(`td:has-text("${title}")`) })
await projectRow.click({ button: 'right' })
await this.page.locator('.popup button:has-text("Unarchive")').click()
await this.page.locator('.popup button:has-text("Ok")').click()
}
async checkProjecInTableIsNotArchived (title: string): Promise<void> {
await this.projectTitleCells().filter({ hasText: title }).filter({ hasNotText: '(archived)' }).waitFor()
}
}

View File

@ -150,7 +150,7 @@ export class IssuesPage extends CommonTrackerPage {
this.page.locator('[id="tracker\\:string\\:TimeSpendReportAdd"] >> text=Add time report')
estimationSpan = (): Locator => this.page.locator('.estimation-container >> span').first()
okButton = (): Locator => this.page.getByRole('button', { name: 'Ok' })
okButton = (): Locator => this.page.getByRole('button', { name: 'Ok', exact: true })
newIssueButton = (): Locator => this.page.locator('#new-issue')
issueNameInput = (): Locator => this.page.locator('#issue-name >> input')
issueDescriptionInput = (): Locator => this.page.locator('#issue-description >> [contenteditable]')
@ -159,7 +159,7 @@ export class IssuesPage extends CommonTrackerPage {
priorityEditor = (): Locator => this.page.locator('#priority-editor')
urgentButton = (): Locator => this.page.locator('button:has-text("Urgent")')
assigneeEditor = (): Locator => this.page.locator('#assignee-editor')
appleseedJohnButton = (): Locator => this.page.locator('button:has-text("Appleseed John")')
appleseedJohnButton = (): Locator => this.page.locator('button.menu-item:has-text("Appleseed John")')
estimationEditor = (): Locator => this.page.locator('#estimation-editor')
dueDateButton = (): Locator => this.page.locator('button:has-text("Due date")')
specificDay = (day: string): Locator => this.page.locator(`.date-popup-container div.day >> text=${day}`).first()

View File

@ -9,11 +9,16 @@ export class TrackerNavigationMenuPage extends CommonPage {
this.page = page
}
buttonCreateProject = (): Locator => this.page.locator('div#navGroup-tree-projects').locator('xpath=../button[1]')
yoursProjectsMenuSelector = '#navGroup-tree-projects'
starredProjectsMenuSelector = '#navGroup-tree-stared'
buttonCreateProject = (): Locator => this.page.locator(this.yoursProjectsMenuSelector).locator('xpath=../button[1]')
buttonProjectsParent = (): Locator => this.page.locator('button.hulyNavGroup-header span')
templateLinkForProject = (projectName: string): Locator =>
this.page.locator(`a[href$="templates"][href*="${projectName}"]`)
starredProjectsInMenu = (): Locator => this.page.locator(`${this.starredProjectsMenuSelector} span`)
issuesLinkForProject = (projectName: string): Locator =>
this.page
.getByRole('button', { name: projectName, exact: true })
@ -49,6 +54,22 @@ export class TrackerNavigationMenuPage extends CommonPage {
await expect(this.buttonProjectsParent().filter({ hasText: projectName })).toHaveCount(1)
}
async checkProjectStarred (projectName: string): Promise<void> {
await expect(this.starredProjectsInMenu().filter({ hasText: projectName })).toHaveCount(1)
}
async checkProjectWillBeRemovedFromYours (projectName: string): Promise<void> {
await this.page.waitForSelector(`${this.yoursProjectsMenuSelector} span:has-text("${projectName}")`, {
state: 'detached'
})
}
async checkProjectWillBeRemovedFromStarred (projectName: string): Promise<void> {
await this.page.waitForSelector(`${this.starredProjectsMenuSelector} span:has-text("${projectName}")`, {
state: 'detached'
})
}
async checkProjectNotExist (projectName: string): Promise<void> {
await expect(this.buttonProjectsParent().filter({ hasText: projectName })).toHaveCount(0)
}
@ -75,6 +96,16 @@ export class TrackerNavigationMenuPage extends CommonPage {
await this.selectFromDropdown(this.page, action)
}
async makeActionWithStarredProject (projectName: string, action: string): Promise<void> {
await this.starredProjectsInMenu().filter({ hasText: projectName }).hover()
await this.starredProjectsInMenu()
.filter({ hasText: projectName })
.locator('xpath=../..')
.locator('div[class*="tools"] button')
.click()
await this.selectFromDropdown(this.page, action)
}
async openMilestonesForProject (projectName: string): Promise<void> {
await this.milestonesLinkForProject(projectName).click()
}
@ -96,4 +127,8 @@ export class TrackerNavigationMenuPage extends CommonPage {
await expect(this.milestone()).toBeVisible()
await expect(this.templates()).toBeVisible()
}
async openAllProjects (): Promise<void> {
await this.allProjects().click()
}
}

View File

@ -15,7 +15,7 @@ export async function prepareNewIssueStep (page: Page, issue: NewIssue): Promise
}
export async function prepareNewIssueWithOpenStep (page: Page, issue: NewIssue): Promise<string> {
return await test.step('Prepare document', async () => {
return await test.step('Prepare Issue', async () => {
const issuesPage = new IssuesPage(page)
await issuesPage.linkSidebarAll().click()
await issuesPage.clickModelSelectorAll()

View File

@ -174,6 +174,8 @@ test.describe('Tracker issue tests', () => {
await issuesDetailsPage.checkIssue({
...moveIssue
})
await trackerNavigationMenuPage.openIssuesForProject('Default')
// TODO need to return back after bug with activity fixed
// await issuesDetailsPage.checkActivityExist('changed project in')
// await issuesDetailsPage.checkActivityExist('changed number in')
@ -221,9 +223,11 @@ test.describe('Tracker issue tests', () => {
test('Delete an issue', async ({ page }) => {
const deleteIssue: NewIssue = {
title: 'Issue for deletion',
title: `Issue-to-delete-${generateId()}`,
description: 'Description Issue for deletion'
}
await prepareNewIssueWithOpenStep(page, deleteIssue)
await issuesPage.navigateToIssues()
await issuesPage.clickModelSelectorAll()
await issuesPage.searchIssueByName(deleteIssue.title)
await issuesPage.openIssueByName(deleteIssue.title)

View File

@ -4,6 +4,8 @@ import { TrackerNavigationMenuPage } from '../model/tracker/tracker-navigation-m
import { NewProjectPage } from '../model/tracker/new-project-page'
import { NewProject } from '../model/tracker/types'
import { EditProjectPage } from '../model/tracker/edit-project-page'
import { AllProjectsPage } from '../model/tracker/all-projects-page'
import { generateProjectId } from './tracker.utils'
test.use({
storageState: PlatformSetting
@ -13,76 +15,189 @@ test.describe('Tracker Projects tests', () => {
let trackerNavigationMenuPage: TrackerNavigationMenuPage
let newProjectPage: NewProjectPage
let editProjectPage: EditProjectPage
let allProjectsPage: AllProjectsPage
test.beforeEach(async ({ page }) => {
trackerNavigationMenuPage = new TrackerNavigationMenuPage(page)
newProjectPage = new NewProjectPage(page)
editProjectPage = new EditProjectPage(page)
allProjectsPage = new AllProjectsPage(page)
await (await page.goto(`${PlatformURI}/workbench/sanity-ws`))?.finished()
})
test('Create project', async () => {
test('User can create project', async () => {
const projectId = generateProjectId()
const newProjectData: NewProject = {
title: 'TestProject',
identifier: 'QWERT',
description: 'Test Project description',
title: `NewProject-${projectId}`,
identifier: projectId,
description: 'New Project description',
private: true,
defaultAssigneeForIssues: 'Dirak Kainin',
defaultIssueStatus: 'In Progress'
}
await trackerNavigationMenuPage.checkProjectNotExist(newProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(newProjectData)
await trackerNavigationMenuPage.checkProjectExist(newProjectData.title)
await trackerNavigationMenuPage.openProject(newProjectData.title)
await test.step('User create project', async () => {
await trackerNavigationMenuPage.checkProjectNotExist(newProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(newProjectData)
})
await test.step('User see project in menu', async () => {
await trackerNavigationMenuPage.checkProjectExist(newProjectData.title)
})
await test.step('User see project in all projects table', async () => {
await trackerNavigationMenuPage.openAllProjects()
await allProjectsPage.checkProjectExistInTable(newProjectData.title)
})
await test.step('User can open created project', async () => {
await trackerNavigationMenuPage.openProject(newProjectData.title)
})
})
test('Edit project', async () => {
test('User can edit project', async () => {
const projectId = generateProjectId()
const editProjectData: NewProject = {
title: 'EditProject',
identifier: 'EDIT',
title: `EditProject-${projectId}`,
identifier: projectId,
description: 'Edit Project description',
private: true,
defaultAssigneeForIssues: 'Dirak Kainin',
defaultIssueStatus: 'In Progress'
}
const updateProjectData: NewProject = {
title: 'UpdateProject',
identifier: 'EDIT',
title: `UpdateProject-${projectId}`,
identifier: projectId,
description: 'Updated Project description',
private: true,
defaultAssigneeForIssues: 'Chen Rosamund',
defaultIssueStatus: 'Done'
}
await trackerNavigationMenuPage.checkProjectNotExist(editProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(editProjectData)
await trackerNavigationMenuPage.checkProjectExist(editProjectData.title)
await trackerNavigationMenuPage.makeActionWithProject(editProjectData.title, 'Edit project')
await editProjectPage.checkProject(editProjectData)
await editProjectPage.updateProject(updateProjectData)
await trackerNavigationMenuPage.makeActionWithProject(updateProjectData.title, 'Edit project')
await editProjectPage.checkProject(updateProjectData)
await test.step('User prepare project', async () => {
await trackerNavigationMenuPage.checkProjectNotExist(editProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(editProjectData)
await trackerNavigationMenuPage.checkProjectExist(editProjectData.title)
})
await test.step('User edit project', async () => {
await trackerNavigationMenuPage.makeActionWithProject(editProjectData.title, 'Edit project')
await editProjectPage.checkProject(editProjectData)
await editProjectPage.updateProject(updateProjectData)
await trackerNavigationMenuPage.makeActionWithProject(updateProjectData.title, 'Edit project')
await editProjectPage.checkProject(updateProjectData)
await editProjectPage.buttonSaveProject().click()
})
})
test('Archive Project', async ({ page }) => {
test('User can archive and unarchive Project', async ({ page }) => {
const projectId = generateProjectId()
const archiveProjectData: NewProject = {
title: 'PROJECT_ARCHIVE',
identifier: 'ARCH',
title: `ArchiveProject-${projectId}`,
identifier: projectId,
description: 'Archive Project description',
private: true,
defaultAssigneeForIssues: 'Dirak Kainin',
defaultIssueStatus: 'In Progress'
}
await trackerNavigationMenuPage.checkProjectNotExist(archiveProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(archiveProjectData)
await trackerNavigationMenuPage.checkProjectExist(archiveProjectData.title)
await trackerNavigationMenuPage.makeActionWithProject(archiveProjectData.title, 'Archive')
await trackerNavigationMenuPage.pressYesForPopup(page)
await trackerNavigationMenuPage.checkProjectNotExist(archiveProjectData.title)
await test.step('User prepare project', async () => {
await trackerNavigationMenuPage.checkProjectNotExist(archiveProjectData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(archiveProjectData)
})
await test.step('User archive project', async () => {
await trackerNavigationMenuPage.checkProjectExist(archiveProjectData.title)
await trackerNavigationMenuPage.makeActionWithProject(archiveProjectData.title, 'Archive')
await trackerNavigationMenuPage.pressYesForPopup(page)
await trackerNavigationMenuPage.checkProjectNotExist(archiveProjectData.title)
await trackerNavigationMenuPage.openAllProjects()
await allProjectsPage.checkProjectExistInTable(`${archiveProjectData.title} (archived)`)
})
await test.step('User unarchive project', async () => {
await allProjectsPage.unarchiveProject(archiveProjectData.title)
await allProjectsPage.checkProjecInTableIsNotArchived(`${archiveProjectData.title}`)
await trackerNavigationMenuPage.checkProjectExist(archiveProjectData.title)
})
await test.step('Finally archive project again', async () => {
await trackerNavigationMenuPage.makeActionWithProject(archiveProjectData.title, 'Archive')
await trackerNavigationMenuPage.pressYesForPopup(page)
await trackerNavigationMenuPage.checkProjectNotExist(archiveProjectData.title)
})
})
test('Star and Unstar Project', async () => {
const projectId = generateProjectId()
const projectToStarData: NewProject = {
title: `ProjectToStar-${projectId}`,
identifier: projectId,
description: 'Starred Project description',
private: true,
defaultAssigneeForIssues: 'Dirak Kainin',
defaultIssueStatus: 'In Progress'
}
await test.step('User prepare project', async () => {
await trackerNavigationMenuPage.checkProjectNotExist(projectToStarData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(projectToStarData)
await trackerNavigationMenuPage.checkProjectExist(projectToStarData.title)
})
await test.step('User star project', async () => {
await trackerNavigationMenuPage.makeActionWithProject(projectToStarData.title, 'Star')
await trackerNavigationMenuPage.checkProjectStarred(projectToStarData.title)
await trackerNavigationMenuPage.checkProjectWillBeRemovedFromYours(projectToStarData.title)
})
await test.step('User unstar project', async () => {
await trackerNavigationMenuPage.makeActionWithStarredProject(projectToStarData.title, 'Unstar')
await trackerNavigationMenuPage.checkProjectExist(projectToStarData.title)
await trackerNavigationMenuPage.checkProjectWillBeRemovedFromStarred(projectToStarData.title)
})
})
test('Leave and Join Project', async () => {
const projectId = generateProjectId()
const projectToLeaveData: NewProject = {
title: `ProjectToLeave-${projectId}`,
identifier: projectId,
description: 'Project to leave description',
private: true,
defaultAssigneeForIssues: 'Appleseed John',
defaultIssueStatus: 'In Progress'
}
await test.step('User prepare project', async () => {
await trackerNavigationMenuPage.checkProjectNotExist(projectToLeaveData.title)
await trackerNavigationMenuPage.pressCreateProjectButton()
await newProjectPage.createNewProject(projectToLeaveData)
await trackerNavigationMenuPage.checkProjectExist(projectToLeaveData.title)
})
await test.step('User leave project', async () => {
await trackerNavigationMenuPage.makeActionWithProject(projectToLeaveData.title, 'Leave')
await trackerNavigationMenuPage.checkProjectWillBeRemovedFromYours(projectToLeaveData.title)
})
await test.step('User join project', async () => {
await trackerNavigationMenuPage.openAllProjects()
await allProjectsPage.checkProjectExistInTable(projectToLeaveData.title)
await allProjectsPage.joinProject(projectToLeaveData.title)
await trackerNavigationMenuPage.checkProjectExist(projectToLeaveData.title)
})
})
test.afterEach(async () => {
await trackerNavigationMenuPage.openIssuesForProject('Default')
})
})

View File

@ -253,6 +253,16 @@ export async function toTime (value: number): Promise<string> {
].join(' ')
}
export const getIssueName = (postfix: string = generateId()): string => `issue-${postfix}`
/**
* Return random capitalized string like "AFJKD"
*
* @returns string
*/
export function generateProjectId (size: number = 5): string {
return Array.from({ length: size }, () => String.fromCharCode(65 + Math.floor(Math.random() * 26))).join('')
}
export async function performPanelTest (page: Page, statuses: string[], panel: string, mode: string): Promise<void> {
const locator = page.locator('.list-container')
const excluded = DEFAULT_STATUSES.filter((status) => !statuses.includes(status))