Refactor account settings and e2e tests
Renamed several components related to account settings and updated corresponding data-test selectors for more clarity. Adjusted e2e tests to reflect these changes and added tests for new functionalities, like changing password and deleting account. In addition, generator description in monorepo configuration was simplified. Minor changes were also made to e2e test utilities for better error handling.
This commit is contained in:
@@ -14,15 +14,27 @@ export class AccountPageObject {
|
|||||||
return this.auth.signUpFlow('/home/settings');
|
return this.auth.signUpFlow('/home/settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateProfileName(name: string) {
|
async updateName(name: string) {
|
||||||
await this.page.locator('[data-test="update-account-name-form"] input').fill(name);
|
await this.page.fill('[data-test="update-account-name-form"] input', name);
|
||||||
await this.page.locator('[data-test="update-account-name-form"] button').click();
|
await this.page.click('[data-test="update-account-name-form"] button');
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateProfileEmail(email: string) {
|
async updateEmail(email: string) {
|
||||||
await this.page.locator('[data-test="account-email-form-email-input"]').fill(email);
|
await this.page.fill('[data-test="account-email-form-email-input"]', email);
|
||||||
await this.page.locator('[data-test="account-email-form-repeat-email-input"]').fill(email);
|
await this.page.fill('[data-test="account-email-form-repeat-email-input"]', email);
|
||||||
await this.page.locator('[data-test="account-email-form"] button').click();
|
await this.page.click('[data-test="account-email-form"] button');
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePassword(password: string) {
|
||||||
|
await this.page.fill('[data-test="account-password-form-password-input"]', password);
|
||||||
|
await this.page.fill('[data-test="account-password-form-repeat-password-input"]', password);
|
||||||
|
await this.page.click('[data-test="account-password-form"] button');
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAccount() {
|
||||||
|
await this.page.click('[data-test="delete-account-button"]');
|
||||||
|
await this.page.fill('[data-test="delete-account-input-field"]', 'DELETE');
|
||||||
|
await this.page.click('[data-test="confirm-delete-account-button"]');
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileName() {
|
getProfileName() {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ test.describe('Account Settings', () => {
|
|||||||
account = new AccountPageObject(page);
|
account = new AccountPageObject(page);
|
||||||
|
|
||||||
await account.setup();
|
await account.setup();
|
||||||
})
|
});
|
||||||
|
|
||||||
test('user can update their profile name', async () => {
|
test('user can update their profile name', async () => {
|
||||||
const name = 'John Doe';
|
const name = 'John Doe';
|
||||||
|
|
||||||
await account.updateProfileName(name);
|
await account.updateName(name);
|
||||||
|
|
||||||
await page.waitForResponse((resp) => {
|
await page.waitForResponse((resp) => {
|
||||||
return resp.url().includes('accounts');
|
return resp.url().includes('accounts');
|
||||||
@@ -27,7 +27,7 @@ test.describe('Account Settings', () => {
|
|||||||
test('user can update their email', async () => {
|
test('user can update their email', async () => {
|
||||||
const email = account.auth.createRandomEmail();
|
const email = account.auth.createRandomEmail();
|
||||||
|
|
||||||
await account.updateProfileEmail(email);
|
await account.updateEmail(email);
|
||||||
|
|
||||||
const req = await page.waitForResponse((resp) => {
|
const req = await page.waitForResponse((resp) => {
|
||||||
return resp.url().includes('auth/v1/user');
|
return resp.url().includes('auth/v1/user');
|
||||||
@@ -35,4 +35,36 @@ test.describe('Account Settings', () => {
|
|||||||
|
|
||||||
expect(req.status()).toBe(200);
|
expect(req.status()).toBe(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('user can update their password', async () => {
|
||||||
|
const password = (Math.random() * 1000).toString();
|
||||||
|
|
||||||
|
await account.updatePassword(password);
|
||||||
|
|
||||||
|
await page.waitForResponse((resp) => {
|
||||||
|
return resp.url().includes('auth/v1/user');
|
||||||
|
});
|
||||||
|
|
||||||
|
await account.auth.signOut();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Account Deletion', () => {
|
||||||
|
let page: Page;
|
||||||
|
let account: AccountPageObject;
|
||||||
|
|
||||||
|
test.beforeAll(async ({ browser }) => {
|
||||||
|
page = await browser.newPage();
|
||||||
|
account = new AccountPageObject(page);
|
||||||
|
|
||||||
|
await account.setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('user can delete their own account', async () => {
|
||||||
|
await account.deleteAccount();
|
||||||
|
|
||||||
|
await page.waitForURL('http://localhost:3000');
|
||||||
|
|
||||||
|
expect(page.url()).toEqual('http://localhost:3000/');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -22,6 +22,11 @@ export class AuthPageObject {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async signOut() {
|
||||||
|
await this.page.click('[data-test="account-dropdown-trigger"]');
|
||||||
|
await this.page.click('[data-test="account-dropdown-sign-out"]');
|
||||||
|
}
|
||||||
|
|
||||||
async signIn(params: {
|
async signIn(params: {
|
||||||
email: string,
|
email: string,
|
||||||
password: string
|
password: string
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ test.describe('Auth flow', () => {
|
|||||||
|
|
||||||
await auth.visitConfirmEmailLink(email);
|
await auth.visitConfirmEmailLink(email);
|
||||||
|
|
||||||
|
await page.waitForURL('http://localhost:3000/home');
|
||||||
|
|
||||||
expect(page.url()).toContain('http://localhost:3000/home');
|
expect(page.url()).toContain('http://localhost:3000/home');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,9 +42,13 @@ test.describe('Auth flow', () => {
|
|||||||
password: 'password',
|
password: 'password',
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.waitForTimeout(500);
|
await page.waitForURL('http://localhost:3000/home');
|
||||||
|
|
||||||
expect(page.url()).toContain('/home');
|
expect(page.url()).toContain('/home');
|
||||||
|
|
||||||
|
await auth.signOut();
|
||||||
|
|
||||||
|
expect(page.url()).toContain('/');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ export class Mailbox {
|
|||||||
const url = `http://localhost:54324/api/v1/mailbox/${mailbox}`;
|
const url = `http://localhost:54324/api/v1/mailbox/${mailbox}`;
|
||||||
|
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch emails: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
const json = (await response.json()) as Array<{ id: string }>;
|
const json = (await response.json()) as Array<{ id: string }>;
|
||||||
|
|
||||||
if (!json || !json.length) {
|
if (!json || !json.length) {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function PersonalAccountDropdown({
|
|||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
aria-label="Open your profile menu"
|
aria-label="Open your profile menu"
|
||||||
data-test={'profile-dropdown-trigger'}
|
data-test={'account-dropdown-trigger'}
|
||||||
className={cn(
|
className={cn(
|
||||||
'animate-in fade-in group flex cursor-pointer items-center focus:outline-none',
|
'animate-in fade-in group flex cursor-pointer items-center focus:outline-none',
|
||||||
className ?? '',
|
className ?? '',
|
||||||
@@ -179,6 +179,7 @@ export function PersonalAccountDropdown({
|
|||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
|
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
|
data-test={'account-dropdown-sign-out'}
|
||||||
role={'button'}
|
role={'button'}
|
||||||
className={'cursor-pointer'}
|
className={'cursor-pointer'}
|
||||||
onClick={signOutRequested}
|
onClick={signOutRequested}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ function DeleteAccountForm() {
|
|||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
data-test={'delete-account-form'}
|
||||||
action={deletePersonalAccountAction}
|
action={deletePersonalAccountAction}
|
||||||
className={'flex flex-col space-y-4'}
|
className={'flex flex-col space-y-4'}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export const UpdatePasswordForm = ({
|
|||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
data-test={'update-password-form'}
|
data-test={'account-password-form'}
|
||||||
onSubmit={form.handleSubmit(updatePasswordCallback)}
|
onSubmit={form.handleSubmit(updatePasswordCallback)}
|
||||||
>
|
>
|
||||||
<div className={'flex flex-col space-y-4'}>
|
<div className={'flex flex-col space-y-4'}>
|
||||||
@@ -118,7 +118,7 @@ export const UpdatePasswordForm = ({
|
|||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
data-test={'new-password'}
|
data-test={'account-password-form-password-input'}
|
||||||
required
|
required
|
||||||
type={'password'}
|
type={'password'}
|
||||||
{...field}
|
{...field}
|
||||||
@@ -144,7 +144,7 @@ export const UpdatePasswordForm = ({
|
|||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
data-test={'repeat-password'}
|
data-test={'account-password-form-repeat-password-input'}
|
||||||
required
|
required
|
||||||
type={'password'}
|
type={'password'}
|
||||||
{...field}
|
{...field}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { PlopTypes } from "@turbo/gen";
|
|||||||
|
|
||||||
export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
||||||
plop.setGenerator("init", {
|
plop.setGenerator("init", {
|
||||||
description: "Generate a new package for the Acme Monorepo",
|
description: "Generate a new package for the Monorepo",
|
||||||
prompts: [
|
prompts: [
|
||||||
{
|
{
|
||||||
type: "input",
|
type: "input",
|
||||||
|
|||||||
Reference in New Issue
Block a user