Files
myeasycms-v2/apps/e2e/tests/team-accounts/team-accounts.po.ts
2026-03-11 14:47:47 +08:00

284 lines
7.6 KiB
TypeScript

import { Page, expect } from '@playwright/test';
import { AuthPageObject } from '../authentication/auth.po';
import { OtpPo } from '../utils/otp.po';
export class TeamAccountsPageObject {
private readonly page: Page;
public auth: AuthPageObject;
public otp: OtpPo;
constructor(page: Page) {
this.page = page;
this.auth = new AuthPageObject(page);
this.otp = new OtpPo(page);
}
async setup(params = this.createTeamName()) {
const auth = new AuthPageObject(this.page);
const email = auth.createRandomEmail();
await auth.bootstrapUser({
email,
name: 'Test User',
});
await auth.loginAsUser({ email });
await this.createTeam(params);
return {
email: email,
teamName: params.teamName,
slug: params.slug,
};
}
getTeamFromSelector(teamName: string) {
return this.page.locator(`[data-test="account-selector-team"]`, {
hasText: teamName,
});
}
getTeams() {
return this.page.locator('[data-test="account-selector-team"]');
}
goToSettings() {
return expect(async () => {
await this.page
.locator('a', {
hasText: 'Settings',
})
.click();
await this.page.waitForURL('**/home/*/settings');
}).toPass();
}
goToMembers() {
return expect(async () => {
await this.page
.locator('a', {
hasText: 'Members',
})
.click();
await this.page.waitForURL('**/home/*/members');
}).toPass();
}
goToBilling() {
return expect(async () => {
await this.page
.locator('a', {
hasText: 'Billing',
})
.click();
return await this.page.waitForURL('**/home/*/billing');
}).toPass();
}
openAccountsSelector() {
return expect(async () => {
await this.page.click('[data-test="account-selector-trigger"]');
return expect(
this.page.locator('[data-test="account-selector-content"]'),
).toBeVisible();
}).toPass();
}
async tryCreateTeam(teamName: string, slug?: string) {
const nameInput = this.page.locator(
'[data-test="create-team-form"] [data-test="team-name-input"]',
);
await nameInput.fill('');
await nameInput.fill(teamName);
// If slug is provided (for non-Latin names), fill the slug field
if (slug) {
const slugInput = this.page.locator(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
);
await expect(slugInput).toBeVisible();
await slugInput.fill(slug);
}
return this.page.click('[data-test="create-team-form"] button:last-child');
}
async createTeam({ teamName, slug } = this.createTeamName()) {
await this.openAccountsSelector();
await this.page.click('[data-test="create-team-account-trigger"]');
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-name-input"]',
teamName,
);
// Slug field is only shown for non-Latin names, so we don't fill it for Latin names
// The database trigger will auto-generate the slug from the name
const click = this.page.click(
'[data-test="create-team-form"] button:last-child',
);
const response = this.page.waitForURL(`/home/${slug}`);
await Promise.all([click, response]);
// Verify user landed on the team page
await expect(this.page).toHaveURL(`/home/${slug}`);
// Verify the team was created and appears in the selector
await this.openAccountsSelector();
await expect(this.getTeamFromSelector(teamName)).toBeVisible();
// Close the selector
await this.page.keyboard.press('Escape');
}
async createTeamWithNonLatinName(teamName: string, slug: string) {
await this.openAccountsSelector();
await this.page.click('[data-test="create-team-account-trigger"]');
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-name-input"]',
teamName,
);
// Wait for slug field to appear (triggered by non-Latin name)
await expect(this.getSlugField()).toBeVisible();
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
slug,
);
const click = this.page.click(
'[data-test="create-team-form"] button:last-child',
);
const response = this.page.waitForURL(`/home/${slug}`);
await Promise.all([click, response]);
// Verify user landed on the team page
await expect(this.page).toHaveURL(`/home/${slug}`);
// Verify the team was created and appears in the selector
await this.openAccountsSelector();
await expect(this.getTeamFromSelector(teamName)).toBeVisible();
// Close the selector
await this.page.keyboard.press('Escape');
}
getSlugField() {
return this.page.locator(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
);
}
async updateTeamName(name: string) {
await expect(async () => {
await this.page.fill(
'[data-test="update-team-account-name-form"] input',
name,
);
await Promise.all([
this.page.click('[data-test="update-team-account-name-form"] button'),
this.page.waitForResponse((response) => {
return (
response.url().includes('settings') &&
response.request().method() === 'POST'
);
}),
]);
}).toPass();
}
async deleteAccount(email: string) {
await expect(async () => {
await this.page.click('[data-test="delete-team-trigger"]');
await this.otp.completeOtpVerification(email);
const click = this.page.click(
'[data-test="delete-team-form-confirm-button"]',
);
const response = this.page.waitForURL('**/home');
return Promise.all([click, response]);
}).toPass();
}
async updateMemberRole(memberEmail: string, newRole: string) {
await expect(async () => {
// Find the member row and click the actions button
const memberRow = this.page.getByRole('row', { name: memberEmail });
await memberRow.getByRole('button').click();
// Click the update role option in the dropdown menu
await this.page.getByText('Update Role').click();
// Select the new role
await this.page.click('[data-test="role-selector-trigger"]');
await this.page.click(`[data-test="role-option-${newRole}"]`);
// Wait for the update to complete and page to reload
const response = this.page.waitForResponse((response) => {
return (
response.url().includes('members') &&
response.request().method() === 'POST'
);
});
return Promise.all([
this.page.click('[data-test="confirm-update-member-role"]'),
response,
]);
}).toPass();
}
async transferOwnership(memberEmail: string, ownerEmail: string) {
await expect(async () => {
// Find the member row and click the actions button
const memberRow = this.page.getByRole('row', { name: memberEmail });
await memberRow.getByRole('button').click();
// Click the transfer ownership option in the dropdown menu
await this.page.getByText('Transfer Ownership').click();
// Complete OTP verification
await this.otp.completeOtpVerification(ownerEmail);
// Wait for the transfer to complete and page to reload
const response = this.page.waitForResponse('**/members');
return Promise.all([
this.page.click('[data-test="confirm-transfer-ownership-button"]'),
response,
]);
}).toPass();
}
createTeamName() {
const random = (Math.random() * 100000000).toFixed(0);
const teamName = `Team-Name-${random}`;
const slug = `team-name-${random}`;
return { teamName, slug };
}
}