Onboarding workspace test preparation (#5708)

Signed-off-by: Jasmin <jasmin@hardcoreeng.com>
This commit is contained in:
JasminMus 2024-06-07 18:08:21 +02:00 committed by GitHub
parent 3f34143b16
commit e818265c76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 726 additions and 1 deletions

View File

@ -10,6 +10,10 @@ export class NotificationPage {
notificationLocator = (name: string): Locator => notificationLocator = (name: string): Locator =>
this.page.locator('div[class*="inbox-activity"] span', { hasText: name }) this.page.locator('div[class*="inbox-activity"] span', { hasText: name })
async clickOnNotification (name: string): Promise<void> {
await this.notificationLocator(name).click()
}
async checkNotificationIssue (name: string, assignee: string): Promise<void> { async checkNotificationIssue (name: string, assignee: string): Promise<void> {
const notification = this.notificationLocator(name) const notification = this.notificationLocator(name)
await expect(notification.locator('xpath=../../..').locator('a span.ap-label')).toHaveText(assignee) await expect(notification.locator('xpath=../../..').locator('a span.ap-label')).toHaveText(assignee)

View File

@ -16,6 +16,18 @@ export class UserProfilePage {
leaveWorkspaceConfirmButton = (): Locator => this.page.getByRole('button', { name: 'Ok' }) leaveWorkspaceConfirmButton = (): Locator => this.page.getByRole('button', { name: 'Ok' })
accountDissabledMessage = (): Locator => this.page.getByRole('heading') accountDissabledMessage = (): Locator => this.page.getByRole('heading')
changeAccount = (): Locator => this.page.getByRole('link', { name: 'Change account' }) changeAccount = (): Locator => this.page.getByRole('link', { name: 'Change account' })
settings = (): Locator => this.page.getByRole('button', { name: 'Settings' })
accountSettings = (): Locator => this.page.getByRole('button', { name: 'Account settings' })
userAvatarMenu = (): Locator => this.page.locator('.mr-8 > .cursor-pointer')
savaAvatarButton = (): Locator => this.page.getByRole('button', { name: 'Save' }).nth(1)
selectWorkspace = (): Locator => this.page.getByRole('button', { name: 'Select workspace' })
changePasswordButton = (): Locator => this.page.getByRole('button', { name: 'Change password' })
currentPassword = (): Locator => this.page.getByPlaceholder('Enter current password')
newPassword = (): Locator => this.page.getByPlaceholder('Enter new password')
repeatPassword = (): Locator => this.page.getByPlaceholder('Repeat new password')
savePassword = (): Locator => this.page.getByRole('button', { name: 'Save' })
savedButton = (): Locator => this.page.getByRole('button', { name: 'Saved' })
signOutButton = (): Locator => this.page.getByRole('button', { name: 'Sign out' })
constructor (page: Page) { constructor (page: Page) {
this.page = page this.page = page
@ -33,6 +45,26 @@ export class UserProfilePage {
await this.profileButton().click() await this.profileButton().click()
} }
async clickSelectWorkspace (): Promise<void> {
await this.selectWorkspace().click()
}
async clickSettings (): Promise<void> {
await this.settings().click()
}
async clickAccountSettings (): Promise<void> {
await this.accountSettings().click()
}
async openUserAvatarMenu (): Promise<void> {
await this.userAvatarMenu().click()
}
async clickSavaAvatarButton (): Promise<void> {
await this.savaAvatarButton().click()
}
async clickChangeAccount (): Promise<void> { async clickChangeAccount (): Promise<void> {
await this.changeAccount().click() await this.changeAccount().click()
} }
@ -63,6 +95,21 @@ export class UserProfilePage {
await this.locationInput().fill(newLocation) await this.locationInput().fill(newLocation)
} }
async changePassword (currentPassword: string, newPassword: string): Promise<void> {
await this.changePasswordButton().click()
await this.currentPassword().fill(currentPassword)
await expect(this.savePassword()).toBeDisabled()
await this.newPassword().fill(newPassword)
await expect(this.savePassword()).toBeDisabled()
await this.repeatPassword().fill(newPassword)
await this.savePassword().click()
await expect(this.savedButton()).toBeDisabled()
}
async clickOnSignOutButton (): Promise<void> {
await this.signOutButton().click()
}
async addOrEditPhone (): Promise<void> { async addOrEditPhone (): Promise<void> {
if ((await this.phoneContactInput().count()) === 0) { if ((await this.phoneContactInput().count()) === 0) {
await this.addSocialLinksButton().click() await this.addSocialLinksButton().click()

View File

@ -15,7 +15,8 @@ export class SelectWorkspacePage extends CommonPage {
buttonCreateNewWorkspace = (): Locator => this.page.locator('div.form-row button') buttonCreateNewWorkspace = (): Locator => this.page.locator('div.form-row button')
workspaceButtonByName = (workspace: string): Locator => this.buttonWorkspace().filter({ hasText: workspace }) workspaceButtonByName = (workspace: string): Locator => this.buttonWorkspace().filter({ hasText: workspace })
createAnotherWorkspace = (): Locator => this.page.getByRole('link', { name: 'Create workspace' }) createAnotherWorkspace = (): Locator => this.page.getByRole('link', { name: 'Create workspace' })
workspaceLogo = (): Locator => this.page.getByText('N', { exact: true })
workspaceList = (workspaceName: string): Locator => this.page.getByRole('button', { name: workspaceName })
async selectWorkspace (workspace: string): Promise<void> { async selectWorkspace (workspace: string): Promise<void> {
await this.workspaceButtonByName(workspace).click() await this.workspaceButtonByName(workspace).click()
} }
@ -24,6 +25,10 @@ export class SelectWorkspacePage extends CommonPage {
await this.buttonWorkspaceName().fill(workspaceName) await this.buttonWorkspaceName().fill(workspaceName)
} }
async clickCreateWorkspaceLogo (): Promise<void> {
await this.workspaceLogo().click()
}
async createWorkspace (workspaceName: string, worskpaceNew: boolean = true): Promise<void> { async createWorkspace (workspaceName: string, worskpaceNew: boolean = true): Promise<void> {
if (worskpaceNew) { if (worskpaceNew) {
await this.buttonCreateWorkspace().waitFor({ state: 'visible' }) await this.buttonCreateWorkspace().waitFor({ state: 'visible' })
@ -37,4 +42,8 @@ export class SelectWorkspacePage extends CommonPage {
await this.buttonCreateNewWorkspace().click() await this.buttonCreateNewWorkspace().click()
} }
} }
async checkIfWorkspaceExists (workspace: string): Promise<void> {
await expect(this.workspaceList(workspace)).toBeVisible()
}
} }

View File

@ -0,0 +1,59 @@
import { expect, type Locator, type Page } from '@playwright/test'
export class ClassesPage {
readonly page: Page
constructor (page: Page) {
this.page = page
}
member = (): Locator => this.page.getByRole('button', { name: 'Member' })
contact = (): Locator => this.page.getByRole('button', { name: 'Contact' })
person = (): Locator => this.page.getByRole('button', { name: 'Person' })
employee = (): Locator => this.page.getByRole('button', { name: 'Employee' })
worker = (): Locator => this.page.getByRole('button', { name: 'Worker' })
talent = (): Locator => this.page.getByRole('button', { name: 'Talent' })
company = (): Locator => this.page.getByRole('button', { name: 'Company' })
customer = (): Locator => this.page.getByRole('button', { name: 'Customer' })
vacancy = (): Locator => this.page.getByRole('button', { name: 'Vacancy', exact: true })
defaultVacancy = (): Locator => this.page.getByRole('button', { name: 'Default vacancy', exact: true })
funnel = (): Locator => this.page.getByRole('button', { name: 'Funnel', exact: true })
defaultFunnel = (): Locator => this.page.getByRole('button', { name: 'Default funnel' })
project = (): Locator => this.page.getByRole('button', { name: 'Project', exact: true })
classicProject = (): Locator => this.page.getByRole('button', { name: 'Classic project', exact: true })
board = (): Locator => this.page.getByRole('button', { name: 'Board' })
task = (): Locator => this.page.getByRole('button', { name: 'Task' })
application = (): Locator => this.page.getByRole('button', { name: 'Application' })
applicant = (): Locator => this.page.getByRole('button', { name: 'Applicant' })
lead = (): Locator => this.page.getByRole('button', { name: 'Lead' })
issue = (): Locator => this.page.getByRole('button', { name: 'Issue' })
card = (): Locator => this.page.getByRole('button', { name: 'Card' })
product = (): Locator => this.page.getByRole('button', { name: 'Product' })
async checkIfClassesExists (): Promise<void> {
await expect(this.member()).toBeVisible()
await expect(this.contact()).toBeVisible()
await expect(this.person()).toBeVisible()
await expect(this.employee()).toBeVisible()
await expect(this.worker()).toBeVisible()
await expect(this.talent()).toBeVisible()
await expect(this.company()).toBeVisible()
await expect(this.customer()).toBeVisible()
await expect(this.vacancy()).toBeVisible()
await expect(this.defaultVacancy()).toBeVisible()
await expect(this.funnel()).toBeVisible()
await expect(this.defaultFunnel()).toBeVisible()
await expect(this.project()).toBeVisible()
await expect(this.classicProject()).toBeVisible()
await expect(this.board()).toBeVisible()
await expect(this.task()).toBeVisible()
await expect(this.application()).toBeVisible()
await expect(this.applicant()).toBeVisible()
await expect(this.lead().nth(0)).toBeVisible()
await expect(this.lead().nth(1)).toBeVisible()
await expect(this.issue().nth(0)).toBeVisible()
await expect(this.issue().nth(1)).toBeVisible()
await expect(this.card()).toBeVisible()
await expect(this.product()).toBeVisible()
}
}

View File

@ -0,0 +1,77 @@
import { expect, type Locator, type Page } from '@playwright/test'
export class OwnersPage {
readonly page: Page
constructor (page: Page) {
this.page = page
}
owner = (ownerName: string): Locator => this.page.getByRole('link', { name: ownerName })
spacesAdminText = (): Locator => this.page.getByText('Admin Members')
addMemberButton = (): Locator => this.page.getByRole('button', { name: 'Members' })
selectMember = (memberName: string): Locator => this.page.getByRole('button', { name: memberName })
workspaceLogo = (): Locator => this.page.locator('.hulyComponent > .cursor-pointer')
publicTemplate = (): Locator => this.page.getByText('Public templates')
createTemplate = (): Locator => this.page.getByRole('button', { name: 'CREATE TEMPLATE' })
saveTemplate = (): Locator => this.page.getByRole('button', { name: 'Save template' })
newTemplateName = (): Locator => this.page.getByPlaceholder('New template')
templateName = (name: string): Locator => this.page.locator('span').filter({ hasText: name })
createEnum = (): Locator => this.page.getByRole('button', { name: 'Create enum' })
addEnum = (): Locator => this.page.locator('.buttons-group > button:nth-child(2)')
enterEnumTitle = (): Locator => this.page.getByPlaceholder('Enum title')
enterEnumName = (): Locator => this.page.getByPlaceholder('Enter option title')
saveButton = (): Locator => this.page.getByRole('button', { name: 'Save' })
createdEnum = (name: string): Locator => this.page.getByRole('button', { name: `${name} 1 option` })
enum = (name: string): Locator => this.page.getByRole('button', { name })
linkValidFor = (): Locator => this.page.getByRole('spinbutton')
emailMask = (): Locator => this.page.getByRole('textbox', { name: 'Type text...' })
noLimitToggleButton = (): Locator => this.page.locator('label span')
avatarLarge = (): Locator => this.page.locator('.hulyAvatarSize-x-large.ava-image')
async addMember (memberName: string): Promise<void> {
await expect(this.spacesAdminText()).toBeVisible()
await this.addMemberButton().click()
await this.selectMember(memberName).click()
await this.page.keyboard.press('Escape')
await expect(this.selectMember(memberName)).toBeVisible()
}
async clickOnWorkspaceLogo (): Promise<void> {
await this.workspaceLogo().click()
}
async checkIfOwnerExists (ownerName: string): Promise<void> {
await expect(this.owner(ownerName)).toBeVisible()
}
async createTemplateWithName (templateName: string): Promise<void> {
await expect(this.publicTemplate()).toBeVisible()
await this.createTemplate().click()
await this.newTemplateName().fill(templateName)
await this.saveTemplate().click()
await expect(this.templateName(templateName)).toBeVisible()
}
async createEnumWithName (enumTitle: string, enumName: string): Promise<void> {
await this.createEnum().click()
await this.enterEnumTitle().fill(enumTitle)
await this.addEnum().click()
await this.enterEnumName().fill(enumName)
await this.page.keyboard.press('Enter')
await this.saveButton().click()
await expect(this.createdEnum(enumTitle)).toBeVisible()
await this.createdEnum(enumTitle).click()
await expect(this.enum(enumName)).toBeVisible()
}
async saveUploadedLogo (): Promise<void> {
await this.saveButton().nth(1).click()
await this.saveButton().click()
}
async checkIfPictureIsUploaded (): Promise<void> {
await expect(this.avatarLarge()).toBeVisible()
await expect(this.avatarLarge()).toHaveAttribute('src')
}
}

View File

@ -0,0 +1,60 @@
import { type Locator, type Page } from '@playwright/test'
export enum ButtonType {
Owners,
Spaces,
Branding,
TextTemplate,
RelatedIssues,
Classes,
Enums,
InviteSettings
}
export class WorkspaceSettingsPage {
readonly page: Page
constructor (page: Page) {
this.page = page
}
owners = (): Locator => this.page.getByRole('button', { name: 'Owners' })
spaces = (): Locator => this.page.getByRole('button', { name: 'Spaces', exact: true })
branding = (): Locator => this.page.getByRole('button', { name: 'Branding' })
textTemplate = (): Locator => this.page.getByRole('button', { name: 'Text Templates' })
relatedIssues = (): Locator => this.page.getByRole('button', { name: 'Related issues' })
classes = (): Locator => this.page.getByRole('button', { name: 'Classes' })
enums = (): Locator => this.page.getByRole('button', { name: 'Enums' })
inviteSettings = (): Locator => this.page.getByRole('button', { name: 'Invite settings' })
async selectWorkspaceSettingsTab (button: ButtonType): Promise<void> {
switch (button) {
case ButtonType.Owners:
await this.owners().click()
break
case ButtonType.Spaces:
await this.spaces().click()
break
case ButtonType.Branding:
await this.branding().click()
break
case ButtonType.TextTemplate:
await this.textTemplate().click()
break
case ButtonType.RelatedIssues:
await this.relatedIssues().click()
break
case ButtonType.Classes:
await this.classes().click()
break
case ButtonType.Enums:
await this.enums().click()
break
case ButtonType.InviteSettings:
await this.inviteSettings().click()
break
default:
throw new Error('Unknown button type')
}
}
}

View File

@ -0,0 +1,81 @@
export const helloAndWelcomeToHuly = [
'Hello and Welcome to Huly! 🌟 Embark on an exciting journey to master our next-generation project management tool.',
"As you tackle these initial issues, you'll uncover essential features and ProTips designed to streamline your workflow.",
"Once you're familiar with Huly, feel free to delete these starter issues or share them with your team.",
'Start by Creating Your First Issue',
'Simply press C from any view to create a new issue.',
'You can also click the New Issue button for the same action.',
"Dynamic Features of Your Issue Editor: Huly's issue editor is versatile, supporting Markdown for rich text formatting and offering several advanced features:",
'Real-Time Collaborative Editor for Issue Descriptions: Uniquely designed for team synergy, the issue description in Huly allows for real-time, collaborative editing.',
'Your team can work together on the same description simultaneously, enhancing productivity and collaboration.',
'Enhanced Communication in Comments: Although comments are not collaboratively editable, you can still enrich them with @mentions, videos, and emojis.',
'This flexibility ensures clear and engaging communication across your team.',
'Enhance Team Collaboration:',
'Use @mention to involve teammates or reference other items within Huly, making collaboration seamless.',
'Drag and drop images or videos into your issues and comments for a comprehensive and visual communication experience.',
'Add emojis ✅ to bring personality and clarity to your discussions.',
'Dive into the world of Huly, where creating impactful issues and harnessing the power of collaborative project management is just the beginning.',
'Discover the ease and efficiency of managing your projects with us!'
]
export const toolsAndTimeBlocking = [
'In Huly, Todos and Issues serve distinct yet interconnected purposes.',
'While Issues are collaborative and represent various processes like a Feature Development cycle, Todos are personalized tasks crucial for advancing these processes.',
'Please read more about Todos here @Understanding Todos in Huly.',
'Step-by-Step Guide to Managing a Todo',
'Assign the Issue to Yourself: First, ensure the Issue is assigned to you. Change its status from Backlog to Todo, as shown in the image below:',
"Todo Creation in Personal Planner: Once you've done this, Huly automatically creates a corresponding Todo in your Personal Planner:",
"Find Your Unscheduled Todo: In your Personal Planner, you'll find the newly created Todo listed as Unscheduled.",
"Scheduling Your Todo: Its time to plan when to work on this Todo. Let's schedule it from 15:00 to 17:00.",
'You can do this either by dragging the Todo to your desired time slot on the Calendar or by opening the Todo and adding one or more work slots:',
'Tracking Progress: After scheduling the Todo, the state of the corresponding Task in Huly changes to In Progress.',
'The system also accounts for the 2 hours of work committed to the task, which in this case is @HI-2.',
'In the upcoming sections of this tutorial, well explore the multifaceted benefits and applications of Todos in process management, planning, and execution within Huly.',
'Example of such benefits is @Team Planning in Huly.',
'Stay tuned to learn how to make the most out of this powerful feature!'
]
export const navigationHully = [
'In Huly, we offer three intuitive ways to navigate and manage your workflow: using the Command Line, Keyboard Shortcuts, or the Mouse.',
'Each method is designed to enhance your productivity and ease of use within the application.',
'1. Command Line - The Power of Cmd/Ctrl + K:',
"Cmd/Ctrl + K: This is one of Huly's most powerful features. Use this command line shortcut to swiftly search for items or execute any action within the application. It's your go-to tool for quick navigation and task management.",
'2. Keyboard Shortcuts - For the Shortcut Enthusiast:',
'Discovering Shortcuts: If keyboard shortcuts are your preference, Huly has you covered. Access a comprehensive list of shortcuts by clicking on Help & Support located in the lower-left corner of the application. These shortcuts are designed to streamline your workflow and save you time.',
'3. Mouse Navigation - Contextual Menus and More:',
"Right-Click for Contextual Menus: Prefer using a mouse? Right-click on any issue to open contextual menus. These menus provide easy access to various actions and are also an excellent way to familiarize yourself with Huly's keyboard shortcuts.",
"Learning and Flexibility: Whether you are a fan of quick command-line actions, efficient keyboard shortcuts, or the traditional mouse-click approach, Huly adapts to your style. These navigation methods not only offer flexibility but also help you learn the application's functionality more deeply. Try them out and find the one that best suits your workflow!"
]
export const connectToGithub = [
"Huly's bi-directional integration with GitHub brings together the best of both platforms.",
'This integration means that activities on GitHub, including Issues, Pull Requests (PRs), Comments, and Change Requests, are instantly updated in your synchronized Huly project, and vice versa.',
'Key Features of Huly-GitHub Integration:',
'Bi-Directional Synchronization: Ensures real-time updates between Huly and GitHub, providing a cohesive project management experience.',
'Milestone-Based Board Management: Huly Milestones correspond to boards in GitHub Projects, maintaining a two-way synchronization for effective board management.',
'Flexible Repository Management: Manage individual repositories or entire GitHub organizations and handle multiple GitHub repositories within a single Huly Project.',
'Empowered by Huly Automation Capabilities:',
'Integration with Huly Automation: Synchronizing your GitHub projects with Huly unlocks additional automation features like Todos and Team Planning, streamlining your project management processes.',
'Efficient Workflows: Automations integrate tasks like assignments, status updates, and scheduling, making your workflow more efficient and reducing manual workload.',
'Freedom and Flexibility:',
'Non-restrictive Use: You have the freedom to stop using Huly at any time. If you decide to discontinue Huly, all your project information will remain intact in GitHub.',
"Data Continuity: There's no risk of losing your project data. Even after dropping Huly, your GitHub projects will retain all their information and history.",
'Setting Up Your Integration:',
'Create a New Project in Huly: Start by creating the project you wish to synchronize with GitHub.',
"Navigate to Integrations: In your Huly workspace, go to the 'Integrations' section.",
"Connect and Install: Choose 'Connect GitHub' and install the Huly app in your GitHub account or organization.",
'Repository Selection and Mapping: Select the GitHub repository you want to sync, and then map it to the corresponding project in Huly.',
"Leverage the power of Huly's advanced features with your GitHub projects and enjoy a more streamlined project management experience.",
"Remember, you're always in control and can choose to use Huly as per your project needs without any commitment."
]
export const proTip = [
'Issue Peek is one hundreds little nice Huly features.',
'Turn on/off with the space bar.',
'To scroll through issues, type J/K or move the mouse.'
]
export const customizeViewsAndDisplay = [
'Customize grouping and sort order of your list and choose what properties show up with Display Options:',
'Use Filters to narrow down objects by values of their fields:'
]

View File

@ -2,6 +2,7 @@ import { Browser, BrowserContext, Locator, Page, expect } from '@playwright/test
import { allure } from 'allure-playwright' import { allure } from 'allure-playwright'
import { faker } from '@faker-js/faker' import { faker } from '@faker-js/faker'
import { TestData } from './chat/types' import { TestData } from './chat/types'
import path from 'path'
export const PlatformURI = process.env.PLATFORM_URI as string export const PlatformURI = process.env.PLATFORM_URI as string
export const PlatformTransactor = process.env.PLATFORM_TRANSACTOR as string export const PlatformTransactor = process.env.PLATFORM_TRANSACTOR as string
@ -34,6 +35,7 @@ export const userName = faker.internet.userName()
export const firstName = faker.person.firstName() export const firstName = faker.person.firstName()
export const lastName = faker.person.lastName() export const lastName = faker.person.lastName()
export const channelName = faker.lorem.word() export const channelName = faker.lorem.word()
export const email = faker.internet.email()
function toHex (value: number, chars: number): string { function toHex (value: number, chars: number): string {
const result = value.toString(16) const result = value.toString(16)
@ -117,3 +119,41 @@ export async function checkIfUrlContains (page: Page, url: string): Promise<void
export async function waitForNetworIdle (page: Page, timeout = 2000): Promise<void> { export async function waitForNetworIdle (page: Page, timeout = 2000): Promise<void> {
await Promise.race([page.waitForLoadState('networkidle'), new Promise((resolve) => setTimeout(resolve, timeout))]) await Promise.race([page.waitForLoadState('networkidle'), new Promise((resolve) => setTimeout(resolve, timeout))])
} }
// Check for text in the page
export const checkTextChunksVisibility = async (page: Page, textChunks: string[]): Promise<void> => {
for (const textChunk of textChunks) {
await expect(page.locator(`text=${textChunk}`)).toBeVisible()
}
}
/**
* Resolves the file path for a given file name located in the same directory as the test.
*
* @param fileName - name of the file to be resolved
* @returns - resolved file path
*/
function resolveFilePath (fileName: string): string {
return path.resolve(__dirname, '.', 'files', fileName)
}
/**
* Uploads a single file using a file chooser in Playwright.
*
* @param page - Playwright Page object
* @param fileName - name of the file to be uploaded
* @param fileUploadTestId - test ID of the file input element (default: '@upload-file')
*/
export async function uploadFile (page: Page, fileName: string, fileUploadTestId = 'Attached photo'): Promise<void> {
const uploadFileElement = page.getByText(fileUploadTestId)
const [fileChooser] = await Promise.all([page.waitForEvent('filechooser'), uploadFileElement.click()])
// Resolve the file path using the 'resolveFilePath' function
const filePath = resolveFilePath(fileName)
await fileChooser.setFiles(filePath)
// Replace with a more reliable condition for determining when the upload is complete, if possible.
await page.waitForTimeout(2000)
}

View File

@ -0,0 +1,181 @@
import { SignUpData } from '../model/common-types'
import { IssuesDetailsPage } from '../model/tracker/issues-details-page'
import { IssuesPage } from '../model/tracker/issues-page'
import { LeftSideMenuPage } from '../model/left-side-menu-page'
import { LoginPage } from '../model/login-page'
import { SelectWorkspacePage } from '../model/select-workspace-page'
import { SignUpPage } from '../model/signup-page'
import * as text from '../text/issueOnboardingText'
import { test } from '@playwright/test'
import { generateId, checkTextChunksVisibility, uploadFile } from '../utils'
import { NotificationPage } from '../model/notification-page'
import { UserProfilePage } from '../model/profile/user-profile-page'
import { ApiEndpoint } from '../API/Api'
test.describe.skip('Workspace tests', () => {
let loginPage: LoginPage
let signUpPage: SignUpPage
let selectWorkspacePage: SelectWorkspacePage
let leftSideMenuPage: LeftSideMenuPage
let issuesPage: IssuesPage
let issuesDetailsPage: IssuesDetailsPage
let notificationPage: NotificationPage
let userProfilePage: UserProfilePage
let api: ApiEndpoint
test.beforeEach(async ({ page, request }) => {
loginPage = new LoginPage(page)
signUpPage = new SignUpPage(page)
selectWorkspacePage = new SelectWorkspacePage(page)
leftSideMenuPage = new LeftSideMenuPage(page)
issuesPage = new IssuesPage(page)
issuesDetailsPage = new IssuesDetailsPage(page)
notificationPage = new NotificationPage(page)
userProfilePage = new UserProfilePage(page)
api = new ApiEndpoint(request)
})
test('Create a workspace from onboarding', async ({ page }) => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.clickSignUp()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await leftSideMenuPage.clickTracker()
await issuesPage.checkIssuesCount('Hello and Welcome to Huly! 🌟', 1)
await issuesPage.checkIssuesCount('Todos and Time Blocking 🗓️', 1)
await issuesPage.checkIssuesCount('Navigating Huly: Three Efficient Ways', 1)
await issuesPage.checkIssuesCount('Connect GitHub with Huly (', 1)
await issuesPage.checkIssuesCount('✨ProTip: Mouse over this', 1)
await issuesPage.checkIssuesCount('Customize views with Display', 1)
await issuesPage.openIssueById('HI-1')
})
test('check the content of the onboarding tracker', async ({ page }) => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.clickSignUp()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await leftSideMenuPage.clickTracker()
await issuesPage.openIssueById('HI-1')
await checkTextChunksVisibility(page, text.helloAndWelcomeToHuly)
await issuesDetailsPage.clickCloseIssueButton()
await issuesPage.openIssueById('HI-2')
await checkTextChunksVisibility(page, text.toolsAndTimeBlocking)
await issuesDetailsPage.clickCloseIssueButton()
await issuesPage.openIssueById('HI-3')
await checkTextChunksVisibility(page, text.navigationHully)
await issuesDetailsPage.clickCloseIssueButton()
await issuesPage.openIssueById('HI-4')
await checkTextChunksVisibility(page, text.connectToGithub)
await issuesDetailsPage.clickCloseIssueButton()
await issuesPage.openIssueById('HI-5')
await checkTextChunksVisibility(page, text.proTip)
await issuesDetailsPage.clickCloseIssueButton()
await issuesPage.openIssueById('HI-6')
await checkTextChunksVisibility(page, text.customizeViewsAndDisplay)
})
test('check the content of the notification', async ({ page }) => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.clickSignUp()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await leftSideMenuPage.clickNotification()
await notificationPage.clickOnNotification('HI-1')
await checkTextChunksVisibility(page, text.helloAndWelcomeToHuly)
})
test('User is able to upload pictures', async ({ page }) => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await leftSideMenuPage.buttonTracker().click()
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await userProfilePage.clickAccountSettings()
await userProfilePage.openUserAvatarMenu()
await uploadFile(page, 'Testingo.png')
await userProfilePage.clickSavaAvatarButton()
})
test('User is able to change workspace', async ({ page }) => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
const newWorkspaceName2 = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await api.createWorkspaceWithLogin(newWorkspaceName2, newUser.email, '1234')
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await userProfilePage.clickSelectWorkspace()
await selectWorkspacePage.selectWorkspace(newWorkspaceName2)
await selectWorkspacePage.clickCreateWorkspaceLogo()
await selectWorkspacePage.checkIfWorkspaceExists(newWorkspaceName2)
})
test('User is able to change password', async () => {
const newUser: SignUpData = {
firstName: `FirstName-${generateId()}`,
lastName: `LastName-${generateId()}`,
email: `sanity-email+${generateId()}@gmail.com`,
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
const newWorkspaceName2 = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await userProfilePage.changePassword('1234', '4321')
await userProfilePage.clickOnSignOutButton()
await loginPage.login(newUser.email, '4321')
await selectWorkspacePage.selectWorkspace(newWorkspaceName2)
await selectWorkspacePage.clickCreateWorkspaceLogo()
await selectWorkspacePage.checkIfWorkspaceExists(newWorkspaceName2)
})
})

View File

@ -0,0 +1,167 @@
import { SignUpData } from '../model/common-types'
import { LoginPage } from '../model/login-page'
import { SelectWorkspacePage } from '../model/select-workspace-page'
import { SignUpPage } from '../model/signup-page'
import { test } from '@playwright/test'
import { generateId, uploadFile } from '../utils'
import { UserProfilePage } from '../model/profile/user-profile-page'
import { ButtonType, WorkspaceSettingsPage } from '../model/workspace/workspace-settings-page'
import { OwnersPage } from '../model/workspace/owner-pages'
import { faker } from '@faker-js/faker'
import { ClassesPage } from '../model/workspace/classes-pages'
test.describe('Workspace tests', () => {
let loginPage: LoginPage
let signUpPage: SignUpPage
let selectWorkspacePage: SelectWorkspacePage
let userProfilePage: UserProfilePage
let workspaceSettingsPage: WorkspaceSettingsPage
let ownersPage: OwnersPage
let newUser: SignUpData
let classesPage: ClassesPage
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page)
signUpPage = new SignUpPage(page)
selectWorkspacePage = new SelectWorkspacePage(page)
userProfilePage = new UserProfilePage(page)
workspaceSettingsPage = new WorkspaceSettingsPage(page)
ownersPage = new OwnersPage(page)
classesPage = new ClassesPage(page)
})
test('User the owner is showing inside the owner tab', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.Owners)
await ownersPage.checkIfOwnerExists(newUser.firstName)
})
test('User is able to set himself as an spaces admin', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.Spaces)
await ownersPage.addMember(newUser.firstName)
})
test('User is able to change workspace picture', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.Branding)
await ownersPage.clickOnWorkspaceLogo()
await uploadFile(page, 'cat3.jpeg')
await ownersPage.saveUploadedLogo()
await ownersPage.checkIfPictureIsUploaded()
})
test('User is able to create template', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
const newTemplateName = faker.word.words(2)
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.TextTemplate)
await ownersPage.createTemplateWithName(newTemplateName)
})
test('User is able to see all the classes', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.Classes)
await classesPage.checkIfClassesExists()
})
test('User is able to create Enum', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
const enumTitle = faker.word.words(2)
const enumName = faker.word.words(2)
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.Enums)
await ownersPage.createEnumWithName(enumTitle, enumName)
})
// Seems that there is currently a bug
test.skip('User is able to create Enums', async ({ page }) => {
newUser = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
const newWorkspaceName = `New Workspace Name - ${generateId(2)}`
const enumTitle = faker.word.words(2)
const enumName = faker.word.words(2)
await loginPage.goto()
await loginPage.linkSignUp().click()
await signUpPage.signUp(newUser)
await selectWorkspacePage.createWorkspace(newWorkspaceName)
await userProfilePage.openProfileMenu()
await userProfilePage.clickSettings()
await workspaceSettingsPage.selectWorkspaceSettingsTab(ButtonType.InviteSettings)
await ownersPage.createEnumWithName(enumTitle, enumName)
})
})