mirror of https://github.com/nocodb/nocodb
Muhammed Mustafa
1 year ago
20 changed files with 516 additions and 62 deletions
@ -0,0 +1,131 @@
|
||||
import BasePage from '../../../Base'; |
||||
import { SidebarPage } from '..'; |
||||
import { expect } from '@playwright/test'; |
||||
|
||||
export class SidebarProjectNodeObject extends BasePage { |
||||
readonly sidebar: SidebarPage; |
||||
|
||||
constructor(parent: SidebarPage) { |
||||
super(parent.rootPage); |
||||
|
||||
this.sidebar = parent; |
||||
} |
||||
|
||||
get({ projectTitle }: { projectTitle: string }) { |
||||
return this.sidebar.get().getByTestId(`nc-sidebar-project-${projectTitle}`); |
||||
} |
||||
|
||||
async click({ projectTitle }: { projectTitle: string }) { |
||||
await this.get({ |
||||
projectTitle, |
||||
}).click(); |
||||
} |
||||
|
||||
async clickOptions({ projectTitle }: { projectTitle: string }) { |
||||
await this.get({ |
||||
projectTitle, |
||||
}) |
||||
.getByTestId(`nc-sidebar-context-menu`) |
||||
.click(); |
||||
} |
||||
|
||||
async verifyTableAddBtn({ projectTitle, visible }: { projectTitle: string; visible: boolean }) { |
||||
const addBtn = await this.get({ |
||||
projectTitle, |
||||
}).getByTestId('nc-sidebar-add-project-entity'); |
||||
|
||||
if (visible) { |
||||
await addBtn.hover({ |
||||
force: true, |
||||
}); |
||||
await expect(addBtn).toBeVisible(); |
||||
} else await expect(addBtn).toHaveCount(0); |
||||
} |
||||
|
||||
async verifyProjectOptions({ |
||||
projectTitle, |
||||
renameVisible, |
||||
starredVisible, |
||||
duplicateVisible, |
||||
relationsVisible, |
||||
restApisVisible, |
||||
importVisible, |
||||
settingsVisible, |
||||
deleteVisible, |
||||
copyProjectInfoVisible, |
||||
}: { |
||||
projectTitle: string; |
||||
renameVisible?: boolean; |
||||
starredVisible?: boolean; |
||||
duplicateVisible?: boolean; |
||||
relationsVisible?: boolean; |
||||
restApisVisible?: boolean; |
||||
importVisible?: boolean; |
||||
settingsVisible?: boolean; |
||||
deleteVisible?: boolean; |
||||
copyProjectInfoVisible?: boolean; |
||||
}) { |
||||
const renameLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-rename'); |
||||
|
||||
if (renameVisible) await renameLocator.isVisible(); |
||||
else await expect(renameLocator).toHaveCount(0); |
||||
|
||||
const starredLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-starred'); |
||||
|
||||
if (starredVisible) await expect(starredLocator).toBeVisible(); |
||||
else await expect(starredLocator).toHaveCount(0); |
||||
|
||||
const duplicateLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-duplicate'); |
||||
|
||||
if (duplicateVisible) await expect(duplicateLocator).toBeVisible(); |
||||
else await expect(duplicateLocator).toHaveCount(0); |
||||
|
||||
const relationsLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-relations'); |
||||
|
||||
if (relationsVisible) await expect(relationsLocator).toBeVisible(); |
||||
else await expect(relationsLocator).toHaveCount(0); |
||||
|
||||
const restApisLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-rest-apis'); |
||||
|
||||
if (restApisVisible) await expect(restApisLocator).toBeVisible(); |
||||
else await expect(restApisLocator).toHaveCount(0); |
||||
|
||||
const importLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-import'); |
||||
|
||||
if (importVisible) await expect(importLocator).toBeVisible(); |
||||
else await expect(importLocator).toHaveCount(0); |
||||
|
||||
const settingsLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-settings'); |
||||
|
||||
if (settingsVisible) await expect(settingsLocator).toBeVisible(); |
||||
else await expect(settingsLocator).toHaveCount(0); |
||||
|
||||
const deleteLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-delete'); |
||||
|
||||
if (deleteVisible) await expect(deleteLocator).toBeVisible(); |
||||
else await expect(deleteLocator).toHaveCount(0); |
||||
|
||||
const copyProjectInfoLocator = await this.rootPage |
||||
.getByTestId(`nc-sidebar-project-${projectTitle}-options`) |
||||
.getByTestId('nc-sidebar-project-copy-project-info'); |
||||
|
||||
if (copyProjectInfoVisible) await expect(copyProjectInfoLocator).toBeVisible(); |
||||
else await expect(copyProjectInfoLocator).toHaveCount(0); |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
import BasePage from '../../../Base'; |
||||
import { SidebarPage } from '..'; |
||||
import { expect } from '@playwright/test'; |
||||
|
||||
export class SidebarTableNodeObject extends BasePage { |
||||
readonly sidebar: SidebarPage; |
||||
|
||||
constructor(parent: SidebarPage) { |
||||
super(parent.rootPage); |
||||
|
||||
this.sidebar = parent; |
||||
} |
||||
|
||||
get({ tableTitle }: { tableTitle: string }) { |
||||
return this.sidebar.get().getByTestId(`tree-view-table-${tableTitle}`); |
||||
} |
||||
|
||||
async click({ tableTitle }: { tableTitle: string }) { |
||||
await this.get({ |
||||
tableTitle, |
||||
}).click(); |
||||
} |
||||
|
||||
async clickOptions({ tableTitle }: { tableTitle: string }) { |
||||
await this.get({ |
||||
tableTitle, |
||||
}) |
||||
.getByTestId(`nc-sidebar-table-context-menu`) |
||||
.click(); |
||||
} |
||||
|
||||
async verifyTableOptions({ |
||||
tableTitle, |
||||
isVisible, |
||||
renameVisible, |
||||
duplicateVisible, |
||||
deleteVisible, |
||||
}: { |
||||
tableTitle: string; |
||||
isVisible: boolean; |
||||
renameVisible?: boolean; |
||||
duplicateVisible?: boolean; |
||||
deleteVisible?: boolean; |
||||
}) { |
||||
const optionsLocator = await this.get({ |
||||
tableTitle, |
||||
}).getByTestId('nc-sidebar-table-context-menu'); |
||||
if (isVisible) await optionsLocator.isVisible(); |
||||
else { |
||||
await expect(optionsLocator).toHaveCount(0); |
||||
return; |
||||
} |
||||
|
||||
const renameLocator = await this.rootPage.getByTestId(`sidebar-table-rename-${tableTitle}`); |
||||
|
||||
if (renameVisible) await renameLocator.isVisible(); |
||||
else await expect(renameLocator).toHaveCount(0); |
||||
|
||||
const duplicateLocator = await this.rootPage.getByTestId(`sidebar-table-duplicate-${tableTitle}`); |
||||
|
||||
if (duplicateVisible) await expect(duplicateLocator).toBeVisible(); |
||||
else await expect(duplicateLocator).toHaveCount(0); |
||||
|
||||
const deleteLocator = await this.rootPage.getByTestId(`sidebar-table-delete-${tableTitle}`); |
||||
|
||||
if (deleteVisible) await expect(deleteLocator).toBeVisible(); |
||||
else await expect(deleteLocator).toHaveCount(0); |
||||
} |
||||
} |
@ -0,0 +1,204 @@
|
||||
import { Page, test } from '@playwright/test'; |
||||
import { DashboardPage } from '../../../pages/Dashboard'; |
||||
import setup, { unsetup } from '../../../setup'; |
||||
import { getDefaultPwd } from '../../../tests/utils/general'; |
||||
|
||||
import { Api } from 'nocodb-sdk'; |
||||
import { CollaborationPage } from '../../../pages/WorkspacePage/CollaborationPage'; |
||||
import { LoginPage } from '../../../pages/LoginPage'; |
||||
import { ProjectViewPage } from '../../../pages/Dashboard/ProjectView'; |
||||
import { AccountUsersPage } from '../../../pages/Account/Users'; |
||||
import { AccountPage } from '../../../pages/Account'; |
||||
import { isEE } from '../../../setup/db'; |
||||
|
||||
const roleDb = [ |
||||
{ email: 'pjt_creator@nocodb.com', role: 'Creator' }, |
||||
{ email: 'pjt_editor@nocodb.com', role: 'Editor' }, |
||||
{ email: 'pjt_commenter@nocodb.com', role: 'Commenter' }, |
||||
{ email: 'pjt_viewer@nocodb.com', role: 'Viewer' }, |
||||
]; |
||||
|
||||
test.describe('Project Collaboration', () => { |
||||
let dashboard: DashboardPage; |
||||
let accountsPage: AccountPage; |
||||
let collaborationPage: CollaborationPage; |
||||
let projectViewPage: ProjectViewPage; |
||||
let context: any; |
||||
let api: Api<any>; |
||||
|
||||
test.skip(() => isEE()); |
||||
|
||||
test.beforeEach(async ({ page }) => { |
||||
context = await setup({ page, isEmptyProject: false }); |
||||
dashboard = new DashboardPage(page, context.project); |
||||
accountsPage = new AccountPage(page); |
||||
projectViewPage = dashboard.projectView; |
||||
|
||||
api = new Api({ |
||||
baseURL: `http://localhost:8080/`, |
||||
headers: { |
||||
'xc-auth': context.token, |
||||
}, |
||||
}); |
||||
|
||||
for (let i = 0; i < roleDb.length; i++) { |
||||
try { |
||||
await api.auth.signup({ |
||||
email: roleDb[i].email, |
||||
password: getDefaultPwd(), |
||||
}); |
||||
} catch (e) { |
||||
// ignore error even if user already exists
|
||||
} |
||||
} |
||||
}); |
||||
|
||||
test.afterEach(async () => { |
||||
await unsetup(context); |
||||
}); |
||||
|
||||
const projectCollabVerify = async ( |
||||
page: Page, |
||||
user: { |
||||
email: string; |
||||
role: string; |
||||
} |
||||
) => { |
||||
await dashboard.leftSidebar.clickTeamAndSettings(); |
||||
|
||||
// add all users as WS viewers
|
||||
|
||||
await accountsPage.users.invite({ |
||||
email: user.email, |
||||
role: 'viewer', |
||||
}); |
||||
|
||||
await dashboard.rootPage.goBack(); |
||||
|
||||
await dashboard.treeView.openProject({ title: context.project.title, context }); |
||||
|
||||
// tab access validation
|
||||
await projectViewPage.verifyAccess('Owner'); |
||||
|
||||
await projectViewPage.tab_accessSettings.click(); |
||||
|
||||
// update roles
|
||||
|
||||
await projectViewPage.accessSettings.setRole(user.email, user.role); |
||||
|
||||
await dashboard.signOut(); |
||||
|
||||
const loginPage = new LoginPage(page); |
||||
await loginPage.signIn({ |
||||
email: user.email, |
||||
password: getDefaultPwd(), |
||||
withoutPrefix: true, |
||||
skipReload: true, |
||||
}); |
||||
|
||||
await dashboard.rootPage.waitForTimeout(500); |
||||
await dashboard.projectView.verifyAccess(user.role); |
||||
|
||||
await dashboard.treeView.openTable({ title: 'Country' }); |
||||
await dashboard.treeView.validateRoleAccess({ |
||||
role: user.role, |
||||
projectTitle: context.project.title, |
||||
tableTitle: 'Country', |
||||
context, |
||||
}); |
||||
await dashboard.viewSidebar.validateRoleAccess({ role: user.role }); |
||||
|
||||
await dashboard.grid.verifyRoleAccess({ role: user.role }); |
||||
|
||||
await dashboard.grid.openExpandedRow({ index: 0 }); |
||||
await dashboard.expandedForm.verifyRoleAccess({ role: user.role }); |
||||
|
||||
await dashboard.sidebar.projectNode.click({ |
||||
projectTitle: context.project.title, |
||||
}); |
||||
}; |
||||
|
||||
test('Project role access validation: Creator', async ({ page }) => { |
||||
await projectCollabVerify(page, roleDb[0]); |
||||
|
||||
const projectNode = dashboard.sidebar.projectNode; |
||||
await projectNode.verifyTableAddBtn({ projectTitle: context.project.title, visible: true }); |
||||
|
||||
await projectNode.clickOptions({ projectTitle: context.project.title }); |
||||
await projectNode.verifyProjectOptions({ |
||||
projectTitle: context.project.title, |
||||
deleteVisible: false, |
||||
duplicateVisible: true, |
||||
importVisible: true, |
||||
renameVisible: true, |
||||
restApisVisible: true, |
||||
settingsVisible: true, |
||||
starredVisible: false, |
||||
relationsVisible: true, |
||||
copyProjectInfoVisible: true, |
||||
}); |
||||
}); |
||||
|
||||
test('Project role access validation: Editor', async ({ page }) => { |
||||
await projectCollabVerify(page, roleDb[1]); |
||||
|
||||
const projectNode = dashboard.sidebar.projectNode; |
||||
await projectNode.verifyTableAddBtn({ projectTitle: context.project.title, visible: false }); |
||||
|
||||
await projectNode.clickOptions({ projectTitle: context.project.title }); |
||||
await projectNode.verifyProjectOptions({ |
||||
projectTitle: context.project.title, |
||||
deleteVisible: false, |
||||
duplicateVisible: false, |
||||
importVisible: false, |
||||
renameVisible: false, |
||||
restApisVisible: true, |
||||
settingsVisible: false, |
||||
starredVisible: false, |
||||
relationsVisible: true, |
||||
copyProjectInfoVisible: true, |
||||
}); |
||||
}); |
||||
|
||||
test('Project role access validation: Commentor', async ({ page }) => { |
||||
await projectCollabVerify(page, roleDb[2]); |
||||
|
||||
const projectNode = dashboard.sidebar.projectNode; |
||||
await projectNode.verifyTableAddBtn({ projectTitle: context.project.title, visible: false }); |
||||
|
||||
await projectNode.clickOptions({ projectTitle: context.project.title }); |
||||
await projectNode.verifyProjectOptions({ |
||||
projectTitle: context.project.title, |
||||
deleteVisible: false, |
||||
duplicateVisible: false, |
||||
importVisible: false, |
||||
renameVisible: false, |
||||
restApisVisible: true, |
||||
settingsVisible: false, |
||||
starredVisible: false, |
||||
relationsVisible: true, |
||||
copyProjectInfoVisible: true, |
||||
}); |
||||
}); |
||||
|
||||
test('Project role access validation: Viewer', async ({ page }) => { |
||||
await projectCollabVerify(page, roleDb[3]); |
||||
|
||||
const projectNode = dashboard.sidebar.projectNode; |
||||
await projectNode.verifyTableAddBtn({ projectTitle: context.project.title, visible: false }); |
||||
|
||||
await projectNode.clickOptions({ projectTitle: context.project.title }); |
||||
await projectNode.verifyProjectOptions({ |
||||
projectTitle: context.project.title, |
||||
deleteVisible: false, |
||||
duplicateVisible: false, |
||||
importVisible: false, |
||||
renameVisible: false, |
||||
restApisVisible: true, |
||||
settingsVisible: false, |
||||
starredVisible: false, |
||||
relationsVisible: true, |
||||
copyProjectInfoVisible: true, |
||||
}); |
||||
}); |
||||
}); |
Loading…
Reference in new issue