Added Teamspace tests, UI fixes (#6326)

This commit is contained in:
Alexander Platov 2024-08-13 09:55:05 +07:00 committed by GitHub
parent 27b04fba7a
commit e591e073a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 180 additions and 45 deletions

View File

@ -601,7 +601,8 @@ export function createModel (builder: Builder): void {
{
id: 'properties',
label: setting.string.Properties,
component: setting.component.SpaceTypePropertiesSectionEditor
component: setting.component.SpaceTypePropertiesSectionEditor,
withoutContainer: true
},
{
id: 'roles',

View File

@ -569,7 +569,8 @@ export function createModel (builder: Builder): void {
{
id: 'properties',
label: setting.string.Properties,
component: setting.component.SpaceTypePropertiesSectionEditor
component: setting.component.SpaceTypePropertiesSectionEditor,
withoutContainer: true
},
{
id: 'roles',

View File

@ -408,7 +408,7 @@
<Label label={core.string.AutoJoin} />
<span><Label label={core.string.AutoJoinDescr} /></span>
</div>
<Toggle bind:on={autoJoin} />
<Toggle id={'teamspace-autoJoin'} bind:on={autoJoin} />
</div>
{#each roles as role}

View File

@ -37,12 +37,14 @@
IconMoreV,
AnySvelteComponent,
navigate,
getCurrentResolvedLocation
getCurrentResolvedLocation,
IconWithEmoji
} from '@hcengineering/ui'
import { createQuery, getClient } from '@hcengineering/presentation'
import { showMenu } from '@hcengineering/view-resources'
import setting, { SpaceTypeEditor } from '@hcengineering/setting'
import { Asset, getResource } from '@hcengineering/platform'
import view from '@hcengineering/view'
import SpaceTypeEditorComponent from './editor/SpaceTypeEditor.svelte'
import { clearSettingsStore } from '../../store'
@ -59,6 +61,7 @@
let selectedSubObjectId: Ref<Doc> | undefined
let subItemName: string | undefined
let subItemIcon: Asset | undefined
let subItemIconColor: number | undefined
onDestroy(resolvedLocationStore.subscribe(handleLocationChanged))
@ -109,7 +112,7 @@
subEditor = undefined
}
let bcItems: Array<{ title: string, icon?: Asset }> = []
let bcItems: Array<{ title: string, icon?: Asset | AnySvelteComponent, iconProps?: any }> = []
$: {
bcItems = []
@ -117,7 +120,11 @@
bcItems.push({ title: type.name, icon: descriptor?.icon })
if (selectedSubObjectId) {
bcItems.push({ title: subItemName ?? selectedSubObjectId, icon: subItemIcon })
bcItems.push({
title: subItemName ?? selectedSubObjectId,
icon: subItemIcon === view.ids.IconWithEmoji ? IconWithEmoji : subItemIcon,
iconProps: { icon: subItemIconColor }
})
}
}
}
@ -193,6 +200,7 @@
this={subEditor}
bind:name={subItemName}
bind:icon={subItemIcon}
bind:color={subItemIconColor}
readonly={!canEdit}
spaceType={type}
{descriptor}

View File

@ -103,6 +103,3 @@
{/if}
</div>
{/if}
<style lang="scss">
</style>

View File

@ -41,6 +41,7 @@
export let objectId: Ref<TaskType>
export let name: string | undefined
export let icon: Asset | undefined
export let color: number | undefined
export let readonly: boolean = true
const client = getClient()
@ -59,6 +60,7 @@
$: taskType = taskTypes.find((tt) => tt._id === objectId)
$: name = taskType?.name
$: icon = taskType?.icon
$: color = taskType?.color
$: descriptor = client.getModel().findAllSync(task.class.TaskTypeDescriptor, { _id: taskType?.descriptor })
$: states = (taskType?.statuses.map((p) => $statusStore.byId.get(p)).filter((p) => p !== undefined) as Status[]) ?? []

View File

@ -1,4 +1,3 @@
import { faker } from '@faker-js/faker'
import { expect, test } from '@playwright/test'
import { ApiEndpoint } from '../API/Api'
import { ChannelPage } from '../model/channel-page'
@ -8,7 +7,7 @@ import { LeftSideMenuPage } from '../model/left-side-menu-page'
import { LoginPage } from '../model/login-page'
import { SelectWorkspacePage } from '../model/select-workspace-page'
import { SignInJoinPage } from '../model/signin-page'
import { PlatformURI, generateTestData } from '../utils'
import { PlatformURI, generateTestData, getInviteLink, generateUser, createAccount } from '../utils'
test.describe('channel tests', () => {
let leftSideMenuPage: LeftSideMenuPage
@ -21,12 +20,7 @@ test.describe('channel tests', () => {
test.beforeEach(async ({ page, request }) => {
data = generateTestData()
newUser2 = {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
newUser2 = generateUser()
leftSideMenuPage = new LeftSideMenuPage(page)
chunterPage = new ChunterPage(page)
@ -415,13 +409,9 @@ test.describe('channel tests', () => {
await page2.close()
})
test('Checking backlinks in the Chat', async ({ browser, page }) => {
await api.createAccount(newUser2.email, newUser2.password, newUser2.firstName, newUser2.lastName)
await leftSideMenuPage.openProfileMenu()
await leftSideMenuPage.inviteToWorkspace()
await leftSideMenuPage.getInviteLink()
const linkText = await page.locator('.antiPopup .link').textContent()
await leftSideMenuPage.clickOnCloseInvite()
test('Checking backlinks in the Chat', async ({ browser, page, request }) => {
await createAccount(request, newUser2)
const linkText = await getInviteLink(page)
const page2 = await browser.newPage()
const leftSideMenuPageSecond = new LeftSideMenuPage(page2)
const channelPageSecond = new ChannelPage(page2)

View File

@ -1,8 +1,20 @@
import { test } from '@playwright/test'
import { generateId, PlatformSetting, PlatformURI } from '../utils'
import {
generateId,
PlatformSetting,
PlatformURI,
generateUser,
createAccount,
getInviteLink,
createAccountAndWorkspace,
generateTestData
} from '../utils'
import { NewTeamspace } from '../model/documents/types'
import { LeftSideMenuPage } from '../model/left-side-menu-page'
import { DocumentsPage } from '../model/documents/documents-page'
import { SignUpData } from '../model/common-types'
import { SignInJoinPage } from '../model/signin-page'
import { TestData } from '../chat/types'
test.use({
storageState: PlatformSetting
@ -64,4 +76,59 @@ test.describe('Teamspace tests', () => {
await documentsPage.moreActionTeamspace(updateEditTeamspace.title, 'Edit teamspace')
await documentsPage.checkTeamspace(updateEditTeamspace)
})
test('Auto-join teamspace', async ({ page, request, browser }) => {
const testData: TestData = generateTestData()
await createAccountAndWorkspace(page, request, testData)
const newUser2: SignUpData = generateUser()
await createAccount(request, newUser2)
const autojoinTeamspace: NewTeamspace = {
title: `Auto-join Teamspace-${generateId()}`,
description: 'Auto-join Teamspace description',
private: false,
autoJoin: true
}
await leftSideMenuPage.clickDocuments()
await documentsPage.checkTeamspaceNotExist(autojoinTeamspace.title)
await documentsPage.createNewTeamspace(autojoinTeamspace)
const linkText = await getInviteLink(page)
const page2 = await browser.newPage()
await page2.goto(linkText ?? '')
const joinPage: SignInJoinPage = new SignInJoinPage(page2)
await joinPage.join(newUser2)
const documentsSecondPage: DocumentsPage = new DocumentsPage(page2)
await documentsSecondPage.clickDocumentsApp()
await documentsSecondPage.checkTeamspaceExist(autojoinTeamspace.title)
await page2.close()
})
test('Join teamspace', async ({ page, request, browser }) => {
const testData: TestData = generateTestData()
await createAccountAndWorkspace(page, request, testData)
const newUser2: SignUpData = generateUser()
await createAccount(request, newUser2)
const joinTeamspace: NewTeamspace = {
title: `Join Teamspace-${generateId()}`,
description: 'Join Teamspace description'
}
await leftSideMenuPage.clickDocuments()
await documentsPage.checkTeamspaceNotExist(joinTeamspace.title)
await documentsPage.createNewTeamspace(joinTeamspace)
const linkText = await getInviteLink(page)
const page2 = await browser.newPage()
await page2.goto(linkText ?? '')
const joinPage: SignInJoinPage = new SignInJoinPage(page2)
await joinPage.join(newUser2)
const documentsSecondPage: DocumentsPage = new DocumentsPage(page2)
await documentsSecondPage.clickDocumentsApp()
await documentsSecondPage.checkTeamspaceNotExist(joinTeamspace.title)
await documentsSecondPage.clickTeamspaces()
await documentsSecondPage.joinTeamspace(joinTeamspace.title)
await documentsSecondPage.checkTeamspaceExist(joinTeamspace.title)
await page2.close()
})
})

View File

@ -23,8 +23,18 @@ export class DocumentsPage extends CommonPage {
readonly buttonDocument = (name: string): Locator =>
this.page.locator('button.hulyNavItem-container > span[class*="label"]', { hasText: name })
readonly buttonDocumentsApp = (): Locator => this.page.locator('button[id$="document:string:DocumentApplication"]')
readonly divTeamspacesParent = (): Locator =>
this.page.locator('div#navGroup-tree-teamspaces').locator('xpath=../button[1]')
this.page.locator('button.hulyNavGroup-header', { hasText: 'Teamspaces' })
readonly buttonTeamspaces = (): Locator =>
this.page.locator('button.hulyNavItem-container', { hasText: 'Teamspaces' })
readonly rowTeamspace = (hasText: string): Locator =>
this.page.locator('div.hulyComponent td ', { hasText }).locator('xpath=..')
readonly buttonJoinTeamspace = (hasText: string): Locator =>
this.page.locator('div.hulyComponent td ', { hasText }).locator('xpath=..').locator('button[type="submit"]')
readonly buttonCreateTeamspace = (): Locator => this.page.locator('button#tree-teamspaces')
readonly formNewTeamspace = (): Locator => this.page.locator('form[id="document:string:NewTeamspace"]')
@ -36,6 +46,7 @@ export class DocumentsPage extends CommonPage {
this.formNewTeamspace().locator('div[id="teamspace-description"] input')
readonly inputModalNewTeamspacePrivate = (): Locator => this.formNewTeamspace().locator('[id="teamspace-private"]')
readonly inputModalNewTeamspaceAutoJoin = (): Locator => this.formNewTeamspace().locator('[id="teamspace-autoJoin"]')
readonly buttonModalNewTeamspaceCreate = (): Locator => this.formNewTeamspace().locator('button[type="submit"]')
readonly buttonModalEditTeamspaceTitle = (): Locator =>
this.formEditTeamspace().locator('div[id="teamspace-title"] input')
@ -56,12 +67,15 @@ export class DocumentsPage extends CommonPage {
await this.divTeamspacesParent().hover()
await this.buttonCreateTeamspace().click()
await this.inputModalNewTeamspaceTitle().fill(data.title)
if (data.description != null) {
if (data?.description !== undefined) {
await this.inputModalNewTeamspaceDescription().fill(data.description)
}
if (data.private != null) {
if (data.private === true) {
await this.inputModalNewTeamspacePrivate().click()
}
if (data.autoJoin === true) {
await this.inputModalNewTeamspaceAutoJoin().click()
}
await this.buttonModalNewTeamspaceCreate().click()
}
@ -149,4 +163,17 @@ export class DocumentsPage extends CommonPage {
async fillMoveDocumentForm (newSpace: string): Promise<void> {
await this.popupMoveDocument.moveToSpace(newSpace)
}
async clickDocumentsApp (): Promise<void> {
await this.buttonDocumentsApp().click()
}
async clickTeamspaces (): Promise<void> {
await this.buttonTeamspaces().click()
}
async joinTeamspace (name: string): Promise<void> {
await expect(this.rowTeamspace(name)).toBeVisible()
await this.buttonJoinTeamspace(name).click()
}
}

View File

@ -2,6 +2,7 @@ export interface NewTeamspace {
title: string
description?: string
private?: boolean
autoJoin?: boolean
}
export interface NewDocument {

View File

@ -21,6 +21,9 @@ export class LoginPage {
recoveryLogin = (): Locator => this.page.getByRole('link', { name: 'Log In' })
recoverySignUp = (): Locator => this.page.getByRole('link', { name: 'Sign Up' })
profileButton = (): Locator => this.page.locator('#profile-button')
popupItemButton = (hasText: string): Locator => this.page.locator('div.popup button[class*="menu"]', { hasText })
// ACTIONS
async goto (): Promise<void> {
await (await this.page.goto(`${PlatformURI}/login/login`))?.finished()
@ -50,8 +53,20 @@ export class LoginPage {
await this.buttonLogin().click()
}
async openProfileMenu (): Promise<void> {
await this.profileButton().click()
}
// ASSERTS
async checkingNeedReLogin (): Promise<void> {
if (await this.profileButton().isVisible()) {
await this.openProfileMenu()
await this.popupItemButton('Sign out').click()
await this.loginWithPassword().waitFor({ state: 'visible', timeout: 15000 })
}
}
async checkIfErrorMessageIsShown (): Promise<void> {
await expect(this.invalidPasswordMessage()).toContainText('Invalid password')
}

View File

@ -41,13 +41,6 @@ export class TemplatePage extends CommonTrackerPage {
saveTemplateButton = (): Locator => this.page.locator('text=Save template')
editTemplateButton = (): Locator => this.page.locator('text=Edit template')
newSpaceTypeButton = (): Locator => this.page.locator('#new-space-type')
spaceTypeButton = (name: string, category?: string): Locator =>
this.page.locator('div#navGroup-spaceTypes button.hulyTaskNavLink-container', {
hasText: category !== undefined ? `${name} ${category}` : name
})
addTaskTypeButton = (): Locator =>
this.page.locator('div.hulyTableAttr-header', { hasText: 'Task types' }).locator('button[data-id="btnAdd"]')
async createNewTemplate (data: NewIssue): Promise<void> {
await this.buttonNewTemplate().click()
@ -124,15 +117,6 @@ export class TemplatePage extends CommonTrackerPage {
await this.newSpaceTypeButton().click()
}
async selectSpaceType (name: string, category?: string): Promise<void> {
await this.spaceTypeButton(name, category).click()
}
async addTaskType (): Promise<void> {
console.log('[!!!] ', await this.page.locator('div.hulyTableAttr-header', { hasText: 'Task types' }).isVisible())
await this.addTaskTypeButton().click()
}
async createTemplate (templateName: string, templateContent: string): Promise<void> {
await this.createTemplateButton().click()
await this.newTemplateInput().fill(templateName)

View File

@ -1,8 +1,13 @@
import { Browser, BrowserContext, Locator, Page, expect } from '@playwright/test'
import { Browser, BrowserContext, Locator, Page, expect, APIRequestContext } from '@playwright/test'
import { allure } from 'allure-playwright'
import { faker } from '@faker-js/faker'
import { TestData } from './chat/types'
import path from 'path'
import { LeftSideMenuPage } from './model/left-side-menu-page'
import { SignUpData } from './model/common-types'
import { ApiEndpoint } from './API/Api'
import { SelectWorkspacePage } from './model/select-workspace-page'
import { LoginPage } from './model/login-page'
export const PlatformURI = process.env.PLATFORM_URI as string
export const PlatformTransactor = process.env.PLATFORM_TRANSACTOR as string
@ -167,3 +172,40 @@ export async function uploadFile (page: Page, fileName: string, fileUploadTestId
// Replace with a more reliable condition for determining when the upload is complete, if possible.
await page.waitForTimeout(2000)
}
export async function getInviteLink (page: Page): Promise<string | null> {
const leftSideMenuPage = new LeftSideMenuPage(page)
await leftSideMenuPage.openProfileMenu()
await leftSideMenuPage.inviteToWorkspace()
await leftSideMenuPage.getInviteLink()
const linkText = await page.locator('.antiPopup .link').textContent()
expect(linkText).not.toBeNull()
await leftSideMenuPage.clickOnCloseInvite()
return linkText
}
export function generateUser (): SignUpData {
return {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
password: '1234'
}
}
export async function createAccount (request: APIRequestContext, data: SignUpData): Promise<void> {
const api: ApiEndpoint = new ApiEndpoint(request)
await api.createAccount(data.email, data.password, data.firstName, data.lastName)
}
export async function createAccountAndWorkspace (page: Page, request: APIRequestContext, data: TestData): Promise<void> {
const api: ApiEndpoint = new ApiEndpoint(request)
await api.createAccount(data.userName, '1234', data.firstName, data.lastName)
await api.createWorkspaceWithLogin(data.workspaceName, data.userName, '1234')
const loginPage: LoginPage = new LoginPage(page)
await loginPage.checkingNeedReLogin()
await (await page.goto(`${PlatformURI}`))?.finished()
await loginPage.login(data.userName, '1234')
const swp = new SelectWorkspacePage(page)
await swp.selectWorkspace(data.workspaceName)
}