Validate special chars when creating a team (#209)

* Add validation for team account names

- Prevent creating teams with reserved names like 'billing' and 'settings'
- Add regex validation to block team names with special characters
- Update localization for new error messages
- Extend E2E tests to cover various invalid team name scenarios

* Enhance team account name validation and slug generation

- Add comprehensive tests for account slug generation in Supabase
- Improve team name validation schema to handle special characters
- Add form validation message display in update team account name form
- Refine slug generation to handle various edge cases like special characters, non-ASCII text, and mixed case
This commit is contained in:
Giancarlo Buomprisco
2025-03-11 09:58:21 +07:00
committed by GitHub
parent b265f596da
commit bd723dccce
6 changed files with 205 additions and 13 deletions

View File

@@ -16,7 +16,7 @@ export class TeamAccountsPageObject {
async setup(params = this.createTeamName()) {
const { email } = await this.auth.signUpFlow('/home');
await this.createTeam(params);
return { email, teamName: params.teamName, slug: params.slug };
@@ -78,6 +78,16 @@ export class TeamAccountsPageObject {
}).toPass();
}
async tryCreateTeam(teamName: string) {
await this.page.locator('[data-test="create-team-form"] input').fill('');
await this.page.waitForTimeout(200);
await this.page.locator('[data-test="create-team-form"] input').fill(teamName);
return this.page.click(
'[data-test="create-team-form"] button:last-child',
);
}
async createTeam({ teamName, slug } = this.createTeamName()) {
await this.openAccountsSelector();
@@ -132,20 +142,20 @@ export class TeamAccountsPageObject {
// 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}"]`);
// Click the confirm button
const click = this.page.click('[data-test="confirm-update-member-role"]');
// Wait for the update to complete and page to reload
const response = this.page.waitForURL('**/home/*/members');
return Promise.all([click, response]);
}).toPass();
}
@@ -155,19 +165,21 @@ export class TeamAccountsPageObject {
// 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);
// Click the confirm button
const click = this.page.click('[data-test="confirm-transfer-ownership-button"]');
const click = this.page.click(
'[data-test="confirm-transfer-ownership-button"]',
);
// Wait for the transfer to complete and page to reload
const response = this.page.waitForURL('**/home/*/members');
return Promise.all([click, response]);
}).toPass();
}

View File

@@ -96,6 +96,99 @@ test.describe('Team Accounts', () => {
await expect(teamAccounts.getTeamFromSelector(teamName)).toBeVisible();
});
test('cannot create a Team account using reserved names', async ({
page,
}) => {
const teamAccounts = new TeamAccountsPageObject(page);
await teamAccounts.setup();
await teamAccounts.openAccountsSelector();
await page.click('[data-test="create-team-account-trigger"]');
await teamAccounts.tryCreateTeam('billing');
await expect(
page.getByText('This name is reserved. Please choose a different one.'),
).toBeVisible();
await teamAccounts.tryCreateTeam('settings');
await expect(
page.getByText('This name is reserved. Please choose a different one.'),
).toBeVisible();
function expectError() {
return expect(
page.getByText(
'This name cannot contain special characters. Please choose a different one.',
),
).toBeVisible();
}
await teamAccounts.tryCreateTeam('Test-Name#');
await expectError();
await teamAccounts.tryCreateTeam('Test,Name');
await expectError();
await teamAccounts.tryCreateTeam('Test Name/')
await expectError();
await teamAccounts.tryCreateTeam('Test Name\\')
await expectError();
await teamAccounts.tryCreateTeam('Test Name:')
await expectError();
await teamAccounts.tryCreateTeam('Test Name;')
await expectError();
await teamAccounts.tryCreateTeam('Test Name=');
await expectError();
await teamAccounts.tryCreateTeam('Test Name>');
await expectError();
await teamAccounts.tryCreateTeam('Test Name<');
await expectError();
await teamAccounts.tryCreateTeam('Test Name?');
await expectError();
await teamAccounts.tryCreateTeam('Test Name@');
await expectError();
await teamAccounts.tryCreateTeam('Test Name^');
await expectError();
await teamAccounts.tryCreateTeam('Test Name&');
await expectError();
await teamAccounts.tryCreateTeam('Test Name*');
await expectError();
await teamAccounts.tryCreateTeam('Test Name(');
await expectError();
await teamAccounts.tryCreateTeam('Test Name)');
await expectError();
await teamAccounts.tryCreateTeam('Test Name+');
await expectError();
await teamAccounts.tryCreateTeam('Test Name%');
await expectError();
await teamAccounts.tryCreateTeam('Test Name$');
await expectError();
await teamAccounts.tryCreateTeam('Test Name[');
await expectError();
await teamAccounts.tryCreateTeam('Test Name]');
await expectError();
});
});
test.describe('Team Account Deletion', () => {