diff --git a/tests/sanity/tests/model/common-page.ts b/tests/sanity/tests/model/common-page.ts index cedea42fd6..f732f76d30 100644 --- a/tests/sanity/tests/model/common-page.ts +++ b/tests/sanity/tests/model/common-page.ts @@ -3,7 +3,7 @@ import { Page } from '@playwright/test' export class CommonPage { async selectMenuItem (page: Page, name: string): Promise { if (name !== 'first') { - await page.locator('div.selectPopup input').fill(name) + await page.locator('div.selectPopup input').fill(name.split(' ')[0]) } await page.locator('div.selectPopup div.list-item:first-child').click() } @@ -37,4 +37,19 @@ export class CommonPage { async pressYesDeletePopup (page: Page): Promise { await page.locator('form[id="view:string:DeleteObject"] button.primary').click() } + + async addNewTagPopup (page: Page, title: string, description: string): Promise { + await page.locator('div.popup form[id="tags:string:AddTag"] input[placeholder$="title"]').fill(title) + await page + .locator('div.popup form[id="tags:string:AddTag"] input[placeholder="Please type description here"]') + .fill(description) + await page.locator('div.popup form[id="tags:string:AddTag"] button[type="submit"]').click() + } + + async selectAssignee (page: Page, name: string): Promise { + if (name !== 'first') { + await page.locator('div.selectPopup input').fill(name.split(' ')[0]) + } + await page.locator('div.selectPopup div.list-item').click() + } } diff --git a/tests/sanity/tests/model/left-side-menu-page.ts b/tests/sanity/tests/model/left-side-menu-page.ts index 65ba39fc65..ef47bde6a5 100644 --- a/tests/sanity/tests/model/left-side-menu-page.ts +++ b/tests/sanity/tests/model/left-side-menu-page.ts @@ -4,10 +4,12 @@ export class LeftSideMenuPage { readonly page: Page readonly buttonChunter: Locator readonly buttonContacts: Locator + readonly buttonTracker: Locator constructor (page: Page) { this.page = page this.buttonChunter = page.locator('button[id$="ApplicationLabelChunter"]') this.buttonContacts = page.locator('button[id$="Contacts"]') + this.buttonTracker = page.locator('button[id$="TrackerApplication"]') } } diff --git a/tests/sanity/tests/model/recruiting/common-recruiting-page.ts b/tests/sanity/tests/model/recruiting/common-recruiting-page.ts index deb557a1a1..c791374d22 100644 --- a/tests/sanity/tests/model/recruiting/common-recruiting-page.ts +++ b/tests/sanity/tests/model/recruiting/common-recruiting-page.ts @@ -59,14 +59,6 @@ export class CommonRecruitingPage extends CommonPage { await page.locator('div.popup form[id="recruit:string:CreateReviewParams"] button[type="submit"]').click() } - async addNewTagPopup (page: Page, title: string, description: string): Promise { - await page.locator('div.popup form[id="tags:string:AddTag"] input[placeholder$="title"]').fill(title) - await page - .locator('div.popup form[id="tags:string:AddTag"] input[placeholder="Please type description here"]') - .fill(description) - await page.locator('div.popup form[id="tags:string:AddTag"] button[type="submit"]').click() - } - async deleteEntity (): Promise { await this.buttonMoreActions.click() await this.buttonDelete.click() diff --git a/tests/sanity/tests/model/tracker/common-tracker-page.ts b/tests/sanity/tests/model/tracker/common-tracker-page.ts new file mode 100644 index 0000000000..a1cf0e37bc --- /dev/null +++ b/tests/sanity/tests/model/tracker/common-tracker-page.ts @@ -0,0 +1,11 @@ +import { Page } from '@playwright/test' +import { CommonPage } from '../common-page' + +export class CommonTrackerPage extends CommonPage { + readonly page: Page + + constructor (page: Page) { + super() + this.page = page + } +} diff --git a/tests/sanity/tests/model/tracker/issues-details-page.ts b/tests/sanity/tests/model/tracker/issues-details-page.ts new file mode 100644 index 0000000000..ed1d3c2374 --- /dev/null +++ b/tests/sanity/tests/model/tracker/issues-details-page.ts @@ -0,0 +1,56 @@ +import { expect, type Locator, type Page } from '@playwright/test' +import { CommonTrackerPage } from './common-tracker-page' +import { NewIssue } from './types' + +export class IssuesDetailsPage extends CommonTrackerPage { + readonly page: Page + readonly inputTitle: Locator + readonly inputDescription: Locator + readonly textStatus: Locator + readonly textPriority: Locator + readonly textAssignee: Locator + readonly textLabels: Locator + readonly textComponent: Locator + readonly textMilestone: Locator + readonly textEstimation: Locator + + constructor (page: Page) { + super(page) + this.page = page + this.inputTitle = page.locator('div.popupPanel-body input[type="text"]') + this.inputDescription = page.locator('div.popupPanel-body div.textInput p') + this.textStatus = page.locator('//span[text()="Status"]/../button[1]//span') + this.textPriority = page.locator('//span[text()="Status"]/../button[2]//span') + this.textAssignee = page.locator('(//span[text()="Assignee"]/../div/button)[2]') + this.textLabels = page.locator('div.step-container div.listitems-container') + this.textComponent = page.locator('(//span[text()="Component"]/../div/div/button)[2]') + this.textMilestone = page.locator('(//span[text()="Milestone"]/../div/div/button)[3]') + this.textEstimation = page.locator('(//span[text()="Estimation"]/../div/button)[4]') + } + + async checkIssueDescription (data: NewIssue): Promise { + await expect(this.inputTitle).toHaveValue(data.title) + await expect(this.inputDescription).toHaveText(data.description) + if (data.status != null) { + await expect(this.textStatus).toHaveText(data.status) + } + if (data.priority != null) { + await expect(this.textPriority).toHaveText(data.priority) + } + if (data.assignee != null) { + await expect(this.textAssignee).toHaveText(data.assignee) + } + if (data.labels != null) { + await expect(this.textLabels).toHaveText(data.labels) + } + if (data.component != null) { + await expect(this.textComponent).toHaveText(data.component) + } + if (data.milestone != null) { + await expect(this.textMilestone).toHaveText(data.milestone) + } + if (data.estimation != null) { + await expect(this.textEstimation).toHaveText(data.estimation) + } + } +} diff --git a/tests/sanity/tests/model/tracker/issues-page.ts b/tests/sanity/tests/model/tracker/issues-page.ts new file mode 100644 index 0000000000..d43bf14df6 --- /dev/null +++ b/tests/sanity/tests/model/tracker/issues-page.ts @@ -0,0 +1,126 @@ +import { expect, type Locator, type Page } from '@playwright/test' +import { NewIssue } from './types' +import path from 'path' +import { CommonTrackerPage } from './common-tracker-page' + +export class IssuesPage extends CommonTrackerPage { + readonly page: Page + readonly pageHeader: Locator + readonly buttonCreateNewIssue: Locator + readonly inputPopupCreateNewIssueTitle: Locator + readonly inputPopupCreateNewIssueDescription: Locator + readonly buttonPopupCreateNewIssueStatus: Locator + readonly buttonPopupCreateNewIssuePriority: Locator + readonly buttonPopupCreateNewIssueAssignee: Locator + readonly buttonPopupCreateNewIssueLabels: Locator + readonly buttonPopupCreateNewIssueComponent: Locator + readonly buttonPopupCreateNewIssueEstimation: Locator + readonly buttonPopupCreateNewIssueMilestone: Locator + readonly buttonPopupCreateNewIssueDuedate: Locator + readonly buttonDatePopupToday: Locator + readonly inputPopupCreateNewIssueFile: Locator + readonly textPopupCreateNewIssueFile: Locator + readonly buttonCreateIssue: Locator + readonly inputSearch: Locator + + constructor (page: Page) { + super(page) + this.page = page + this.pageHeader = page.locator('span[class*="header"]', { hasText: 'Issues' }) + this.buttonCreateNewIssue = page.locator('button > span', { hasText: 'New issue' }) + this.inputPopupCreateNewIssueTitle = page.locator('form[id="tracker:string:NewIssue"] input[type="text"]') + this.inputPopupCreateNewIssueDescription = page.locator('form[id="tracker:string:NewIssue"] div.tiptap') + this.buttonPopupCreateNewIssueStatus = page.locator('form[id="tracker:string:NewIssue"] div#status-editor button') + this.buttonPopupCreateNewIssuePriority = page.locator( + 'form[id="tracker:string:NewIssue"] div#priority-editor button' + ) + this.buttonPopupCreateNewIssueAssignee = page.locator( + 'form[id="tracker:string:NewIssue"] div#assignee-editor button' + ) + this.buttonPopupCreateNewIssueLabels = page.locator('form[id="tracker:string:NewIssue"] button span', { + hasText: 'Labels' + }) + this.buttonPopupCreateNewIssueComponent = page.locator( + 'form[id="tracker:string:NewIssue"] button span[title="No component"]' + ) + this.buttonPopupCreateNewIssueEstimation = page.locator( + 'form[id="tracker:string:NewIssue"] div#estimation-editor button' + ) + this.buttonPopupCreateNewIssueMilestone = page.locator( + 'form[id="tracker:string:NewIssue"] div#milestone-editor button' + ) + this.buttonPopupCreateNewIssueDuedate = page.locator('form[id="tracker:string:NewIssue"] div#duedate-editor button') + this.buttonDatePopupToday = page.locator('div.popup div.today') + this.inputPopupCreateNewIssueFile = page.locator('form[id="tracker:string:NewIssue"] input[type="file"]') + this.textPopupCreateNewIssueFile = page.locator('div[class*="attachments"] > div[class*="attachment"]') + this.buttonCreateIssue = page.locator('button > span', { hasText: 'Create issue' }) + this.inputSearch = page.locator('input[placeholder="Search"]') + } + + async createNewIssue (data: NewIssue): Promise { + await this.buttonCreateNewIssue.click() + + await this.inputPopupCreateNewIssueTitle.fill(data.title) + await this.inputPopupCreateNewIssueDescription.fill(data.description) + if (data.status != null) { + await this.buttonPopupCreateNewIssueStatus.click() + await this.selectFromDropdown(this.page, data.status) + } + if (data.priority != null) { + await this.buttonPopupCreateNewIssuePriority.click() + await this.selectMenuItem(this.page, data.priority) + } + if (data.assignee != null) { + await this.buttonPopupCreateNewIssueAssignee.click() + await this.selectAssignee(this.page, data.assignee) + } + if (data.labels != null && data.createLabel != null) { + await this.buttonPopupCreateNewIssueLabels.click() + if (data.createLabel) { + await this.pressCreateButtonSelectPopup(this.page) + await this.addNewTagPopup(this.page, data.labels, 'Tag from createNewIssue') + } + await this.checkFromDropdown(this.page, data.labels) + await this.inputPopupCreateNewIssueTitle.click({ force: true }) + } + if (data.component != null) { + await this.buttonPopupCreateNewIssueComponent.click() + await this.selectMenuItem(this.page, data.component) + } + if (data.estimation != null) { + await this.buttonPopupCreateNewIssueEstimation.click({ delay: 100 }) + await this.fillToSelectPopup(this.page, data.estimation) + } + if (data.milestone != null) { + await this.buttonPopupCreateNewIssueMilestone.click() + await this.selectMenuItem(this.page, data.milestone) + } + if (data.duedate != null) { + await this.buttonPopupCreateNewIssueDuedate.click() + if (data.duedate === 'today') { + await this.buttonDatePopupToday.click() + } else { + await this.fillToSelectPopup(this.page, data.duedate) + } + } + if (data.filePath != null) { + await this.inputPopupCreateNewIssueFile.setInputFiles(path.join(__dirname, `../../files/${data.filePath}`)) + await expect(await this.textPopupCreateNewIssueFile.filter({ hasText: data.filePath })).toBeVisible() + } + + await this.buttonCreateIssue.click() + } + + async searchIssueByName (issueName: string): Promise { + await this.inputSearch.fill(issueName) + await this.page.waitForTimeout(3000) + } + + async openIssueByName (issueName: string): Promise { + await this.page.locator('a', { hasText: issueName }).click() + } + + async checkIssueNotExist (issueName: string): Promise { + await expect(this.page.locator('tr', { hasText: issueName })).toHaveCount(0) + } +} diff --git a/tests/sanity/tests/model/tracker/tracker-navigation-menu-page.ts b/tests/sanity/tests/model/tracker/tracker-navigation-menu-page.ts new file mode 100644 index 0000000000..4b72642ca9 --- /dev/null +++ b/tests/sanity/tests/model/tracker/tracker-navigation-menu-page.ts @@ -0,0 +1,11 @@ +import { type Locator, type Page } from '@playwright/test' + +export class TrackerNavigationMenuPage { + readonly page: Page + readonly buttonIssues: Locator + + constructor (page: Page) { + this.page = page + this.buttonIssues = page.locator('a span', { hasText: 'Issues' }) + } +} diff --git a/tests/sanity/tests/model/tracker/types.ts b/tests/sanity/tests/model/tracker/types.ts new file mode 100644 index 0000000000..d2c6f730fd --- /dev/null +++ b/tests/sanity/tests/model/tracker/types.ts @@ -0,0 +1,14 @@ +export interface NewIssue { + title: string + description: string + status?: string + priority?: string + assignee?: string + createLabel?: boolean + labels?: string + component?: string + estimation?: string + milestone?: string + duedate?: string + filePath?: string +} diff --git a/tests/sanity/tests/tracker/issues.spec.ts b/tests/sanity/tests/tracker/issues.spec.ts new file mode 100644 index 0000000000..7b03a71023 --- /dev/null +++ b/tests/sanity/tests/tracker/issues.spec.ts @@ -0,0 +1,48 @@ +import { test } from '@playwright/test' +import { generateId, PlatformSetting, PlatformURI } from '../utils' +import { LeftSideMenuPage } from '../model/left-side-menu-page' +import { IssuesPage } from '../model/tracker/issues-page' +import { IssuesDetailsPage } from '../model/tracker/issues-details-page' +import { NewIssue } from '../model/tracker/types' + +test.use({ + storageState: PlatformSetting +}) + +test.describe('tracker issue tests', () => { + test.beforeEach(async ({ page }) => { + await (await page.goto(`${PlatformURI}/workbench/sanity-ws`))?.finished() + }) + + test('Create an issue with all parameters and attachments', async ({ page }) => { + const newIssue: NewIssue = { + title: `Issue with all parameters and attachments-${generateId()}`, + description: 'Created issue with all parameters and attachments description', + status: 'In Progress', + priority: 'Urgent', + assignee: 'Appleseed John', + createLabel: true, + labels: `CREATE-ISSUE-${generateId()}`, + component: 'No component', + estimation: '2', + milestone: 'No Milestone', + duedate: 'today', + filePath: 'cat.jpeg' + } + + const leftSideMenuPage = new LeftSideMenuPage(page) + await leftSideMenuPage.buttonTracker.click() + + const issuesPage = new IssuesPage(page) + await issuesPage.createNewIssue(newIssue) + await issuesPage.searchIssueByName(newIssue.title) + await issuesPage.openIssueByName(newIssue.title) + + const issuesDetailsPage = new IssuesDetailsPage(page) + await issuesDetailsPage.checkIssueDescription({ + ...newIssue, + milestone: 'Milestone', + estimation: '2h' + }) + }) +}) diff --git a/tests/sanity/tests/tracker.layout.spec.ts b/tests/sanity/tests/tracker/tracker.layout.spec.ts similarity index 98% rename from tests/sanity/tests/tracker.layout.spec.ts rename to tests/sanity/tests/tracker/tracker.layout.spec.ts index 70bd84f8e1..9ca6a4fc2a 100644 --- a/tests/sanity/tests/tracker.layout.spec.ts +++ b/tests/sanity/tests/tracker/tracker.layout.spec.ts @@ -13,7 +13,7 @@ import { setViewOrder, ViewletSelectors } from './tracker.utils' -import { fillSearch, generateId, PlatformSetting } from './utils' +import { fillSearch, generateId, PlatformSetting } from '../utils' test.use({ storageState: PlatformSetting }) diff --git a/tests/sanity/tests/tracker.loading.spec.ts b/tests/sanity/tests/tracker/tracker.loading.spec.ts similarity index 91% rename from tests/sanity/tests/tracker.loading.spec.ts rename to tests/sanity/tests/tracker/tracker.loading.spec.ts index 3a0b957b42..1bad19caa3 100644 --- a/tests/sanity/tests/tracker.loading.spec.ts +++ b/tests/sanity/tests/tracker/tracker.loading.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from '@playwright/test' -import { PlatformSetting, PlatformURI } from './utils' +import { PlatformSetting, PlatformURI } from '../utils' test.use({ storageState: PlatformSetting }) diff --git a/tests/sanity/tests/tracker.projects.spec.ts b/tests/sanity/tests/tracker/tracker.projects.spec.ts similarity index 98% rename from tests/sanity/tests/tracker.projects.spec.ts rename to tests/sanity/tests/tracker/tracker.projects.spec.ts index 9c8806de0d..bbad6ea945 100644 --- a/tests/sanity/tests/tracker.projects.spec.ts +++ b/tests/sanity/tests/tracker/tracker.projects.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from '@playwright/test' import { navigate } from './tracker.utils' -import { generateId, PlatformSetting, PlatformURI, fillSearch } from './utils' +import { generateId, PlatformSetting, PlatformURI, fillSearch } from '../utils' test.use({ storageState: PlatformSetting diff --git a/tests/sanity/tests/tracker.spec.ts b/tests/sanity/tests/tracker/tracker.spec.ts similarity index 96% rename from tests/sanity/tests/tracker.spec.ts rename to tests/sanity/tests/tracker/tracker.spec.ts index abd90b2a60..ec6f2f76e0 100644 --- a/tests/sanity/tests/tracker.spec.ts +++ b/tests/sanity/tests/tracker/tracker.spec.ts @@ -8,9 +8,10 @@ import { createIssue, fillIssueForm, navigate, - openIssue + openIssue, + toTime } from './tracker.utils' -import { PlatformSetting, fillSearch, generateId } from './utils' +import { PlatformSetting, fillSearch, generateId } from '../utils' test.use({ storageState: PlatformSetting }) @@ -127,18 +128,6 @@ test('my-issues', async ({ page }) => { await expect(page.locator('.antiPanel-component')).not.toContainText(name) }) -function floorFractionDigits (n: number | string, amount: number): number { - return Number(Number(n).toFixed(amount)) -} - -function toTime (value: number): string { - if (value > 0 && value < 8) { - return `${floorFractionDigits(value, 2)}h` - } else { - return `${floorFractionDigits(value / 8, 3)}d` - } -} - test('report-time-from-issue-card', async ({ page }) => { await navigate(page) const assignee = 'Chen Rosamund' @@ -168,7 +157,7 @@ test('report-time-from-issue-card', async ({ page }) => { await page.click('button:has-text("Create")') await page.click('#card-close') - await expect(page.locator('#ReportedTimeEditor')).toContainText(toTime(time)) + await expect(page.locator('#ReportedTimeEditor')).toContainText(await toTime(time)) } }) @@ -245,7 +234,7 @@ test('report-time-from-main-view', async ({ page }) => { await page.click('button:has-text("Create")') await page.click('#card-close') - await expect(page.locator('.estimation-container >> span').first()).toContainText(toTime(count)) + await expect(page.locator('.estimation-container >> span').first()).toContainText(await toTime(count)) } }) diff --git a/tests/sanity/tests/tracker.utils.ts b/tests/sanity/tests/tracker/tracker.utils.ts similarity index 94% rename from tests/sanity/tests/tracker.utils.ts rename to tests/sanity/tests/tracker/tracker.utils.ts index a423055732..b65f6d0176 100644 --- a/tests/sanity/tests/tracker.utils.ts +++ b/tests/sanity/tests/tracker/tracker.utils.ts @@ -1,5 +1,5 @@ import { expect, Page } from '@playwright/test' -import { PlatformURI } from './utils' +import { PlatformURI } from '../utils' export interface IssueProps { name: string @@ -203,3 +203,15 @@ export async function openIssue (page: Page, name: string): Promise { timeout: 15000 }) } + +export async function floorFractionDigits (n: number | string, amount: number): Promise { + return Number(Number(n).toFixed(amount)) +} + +export async function toTime (value: number): Promise { + if (value > 0 && value < 8) { + return `${await floorFractionDigits(value, 2)}h` + } else { + return `${await floorFractionDigits(value / 8, 3)}d` + } +}