mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-20 20:48:11 -05:00
Compare commits
2 Commits
testing-cl
...
abhimanyuy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bea287957d | ||
|
|
84d7b05cd2 |
@@ -44,7 +44,7 @@ export const SettingsForm = ({
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="email" />
|
||||
<Input {...field} type="email" data-testid="settings-email" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -62,6 +62,7 @@ export const SettingsForm = ({
|
||||
{...field}
|
||||
type="password"
|
||||
placeholder="************"
|
||||
data-testid="settings-password"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -80,6 +81,7 @@ export const SettingsForm = ({
|
||||
{...field}
|
||||
type="password"
|
||||
placeholder="************"
|
||||
data-testid="settings-confirm-password"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -117,6 +119,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-agent-run"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -141,6 +144,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-block-execution-failed"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -164,6 +168,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-continuous-agent-error"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -193,6 +198,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-zero-balance"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -216,6 +222,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-low-balance"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -243,6 +250,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-daily-summary"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -264,6 +272,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-weekly-summary"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -285,6 +294,7 @@ export const SettingsForm = ({
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
data-testid="settings-notify-on-monthly-summary"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
@@ -300,6 +310,7 @@ export const SettingsForm = ({
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
disabled={form.formState.isSubmitting}
|
||||
data-testid="settings-cancel"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
182
autogpt_platform/frontend/src/tests/pages/settings.page.ts
Normal file
182
autogpt_platform/frontend/src/tests/pages/settings.page.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { expect, Locator, Page } from "@playwright/test";
|
||||
import { BasePage } from "./base.page";
|
||||
import { getSelectors } from "../utils/selectors";
|
||||
|
||||
export async function getSwitchState(toggle: Locator): Promise<boolean> {
|
||||
const ariaChecked = await toggle.getAttribute("aria-checked");
|
||||
if (ariaChecked === "true") return true;
|
||||
if (ariaChecked === "false") return false;
|
||||
|
||||
const dataState = await toggle.getAttribute("data-state");
|
||||
if (dataState === "checked") return true;
|
||||
if (dataState === "unchecked") return false;
|
||||
|
||||
const dataChecked = await toggle.getAttribute("data-checked");
|
||||
return dataChecked !== null;
|
||||
}
|
||||
|
||||
type ToggleId =
|
||||
| "settings-notify-on-agent-run"
|
||||
| "settings-notify-on-block-execution-failed"
|
||||
| "settings-notify-on-continuous-agent-error"
|
||||
| "settings-notify-on-zero-balance"
|
||||
| "settings-notify-on-low-balance"
|
||||
| "settings-notify-on-daily-summary"
|
||||
| "settings-notify-on-weekly-summary"
|
||||
| "settings-notify-on-monthly-summary";
|
||||
|
||||
export const TOGGLE_IDS: ReadonlyArray<ToggleId> = [
|
||||
"settings-notify-on-agent-run",
|
||||
"settings-notify-on-block-execution-failed",
|
||||
"settings-notify-on-continuous-agent-error",
|
||||
"settings-notify-on-zero-balance",
|
||||
"settings-notify-on-low-balance",
|
||||
"settings-notify-on-daily-summary",
|
||||
"settings-notify-on-weekly-summary",
|
||||
"settings-notify-on-monthly-summary",
|
||||
];
|
||||
|
||||
export class SettingsPage extends BasePage {
|
||||
static readonly path = "/profile/settings";
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page);
|
||||
}
|
||||
|
||||
async goto(): Promise<void> {
|
||||
await this.page.goto(SettingsPage.path);
|
||||
await this.isLoaded();
|
||||
}
|
||||
|
||||
async isLoaded(): Promise<boolean> {
|
||||
try {
|
||||
await this.page.waitForLoadState("domcontentloaded");
|
||||
const header = this.page.getByRole("heading", { name: "My account" });
|
||||
const email = this.getEmailInput();
|
||||
|
||||
await Promise.all([
|
||||
header.waitFor({ state: "visible" }),
|
||||
email.waitFor({ state: "visible" }),
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getEmailInput(): Locator {
|
||||
return this.page.getByTestId("settings-email");
|
||||
}
|
||||
getPasswordInput(): Locator {
|
||||
return this.page.getByTestId("settings-password");
|
||||
}
|
||||
getConfirmPasswordInput(): Locator {
|
||||
return this.page.getByTestId("settings-confirm-password");
|
||||
}
|
||||
getToggle(id: ToggleId): Locator {
|
||||
return this.page.getByTestId(id);
|
||||
}
|
||||
getCancelButton(): Locator {
|
||||
return this.page.getByTestId("settings-cancel");
|
||||
}
|
||||
getSaveButton(): Locator {
|
||||
return this.page.getByRole("button", { name: /Save changes|Saving\.\.\./ });
|
||||
}
|
||||
|
||||
async setEmail(value: string): Promise<void> {
|
||||
const input = this.getEmailInput();
|
||||
await input.waitFor({ state: "visible" });
|
||||
await input.fill(value);
|
||||
await expect(input).toHaveValue(value);
|
||||
}
|
||||
|
||||
async setPassword(value: string): Promise<void> {
|
||||
const input = this.getPasswordInput();
|
||||
await input.waitFor({ state: "visible" });
|
||||
await input.fill(value);
|
||||
await expect(input).toHaveValue(value);
|
||||
}
|
||||
|
||||
async setConfirmPassword(value: string): Promise<void> {
|
||||
const input = this.getConfirmPasswordInput();
|
||||
await input.waitFor({ state: "visible" });
|
||||
await input.fill(value);
|
||||
await expect(input).toHaveValue(value);
|
||||
}
|
||||
|
||||
private async getSwitchState(toggle: Locator): Promise<boolean> {
|
||||
const ariaChecked = await toggle.getAttribute("aria-checked");
|
||||
if (ariaChecked === "true") return true;
|
||||
if (ariaChecked === "false") return false;
|
||||
|
||||
const dataState = await toggle.getAttribute("data-state");
|
||||
if (dataState === "checked") return true;
|
||||
if (dataState === "unchecked") return false;
|
||||
|
||||
const dataChecked = await toggle.getAttribute("data-checked");
|
||||
return dataChecked !== null;
|
||||
}
|
||||
|
||||
private async setSwitchState(toggle: Locator, desired: boolean): Promise<void> {
|
||||
await toggle.waitFor({ state: "visible" });
|
||||
const current = await this.getSwitchState(toggle);
|
||||
if (current !== desired) {
|
||||
await toggle.click();
|
||||
await expect
|
||||
.poll(async () => this.getSwitchState(toggle))
|
||||
.toBe(desired);
|
||||
}
|
||||
}
|
||||
|
||||
async toggle(id: ToggleId): Promise<void> {
|
||||
await this.getToggle(id).click();
|
||||
}
|
||||
|
||||
async enable(id: ToggleId): Promise<void> {
|
||||
await this.setSwitchState(this.getToggle(id), true);
|
||||
}
|
||||
|
||||
async disable(id: ToggleId): Promise<void> {
|
||||
await this.setSwitchState(this.getToggle(id), false);
|
||||
}
|
||||
|
||||
async cancelChanges(): Promise<void> {
|
||||
const btn = this.getCancelButton();
|
||||
await btn.waitFor({ state: "visible" });
|
||||
await btn.click();
|
||||
await this.getEmailInput().waitFor({ state: "visible" });
|
||||
}
|
||||
|
||||
async saveChanges(): Promise<void> {
|
||||
const btn = this.getSaveButton();
|
||||
await btn.waitFor({ state: "visible" });
|
||||
await btn.click();
|
||||
await this.waitForSaveComplete();
|
||||
}
|
||||
|
||||
async waitForSaveComplete(): Promise<void> {
|
||||
const { getText } = getSelectors(this.page);
|
||||
const toast = getText("Successfully updated settings");
|
||||
|
||||
await Promise.race([
|
||||
toast.waitFor({ state: "visible" }),
|
||||
expect(this.getSaveButton()).toHaveText("Save changes"),
|
||||
]);
|
||||
}
|
||||
|
||||
async getEmailValue(): Promise<string> {
|
||||
return this.getEmailInput().inputValue();
|
||||
}
|
||||
|
||||
async expectValidationError(text: string | RegExp): Promise<void> {
|
||||
const { getText } = getSelectors(this.page);
|
||||
await expect(getText(text)).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
export async function navigateToSettings(page: Page): Promise<SettingsPage> {
|
||||
const settings = new SettingsPage(page);
|
||||
await settings.goto();
|
||||
return settings;
|
||||
}
|
||||
91
autogpt_platform/frontend/src/tests/settings.spec.ts
Normal file
91
autogpt_platform/frontend/src/tests/settings.spec.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
import { LoginPage } from "./pages/login.page";
|
||||
import { TEST_CREDENTIALS } from "./credentials";
|
||||
import { hasFieldValue, hasUrl } from "./utils/assertion";
|
||||
import { navigateToSettings, getSwitchState, TOGGLE_IDS } from "./pages/settings.page";
|
||||
|
||||
test.describe("Settings", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/login");
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.login(TEST_CREDENTIALS.email, TEST_CREDENTIALS.password);
|
||||
await hasUrl(page, "/marketplace");
|
||||
});
|
||||
|
||||
test("settings page redirects to login when not authenticated", async ({ browser }) => {
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto("/profile/settings");
|
||||
await hasUrl(page, /\/login/);
|
||||
await context.close();
|
||||
});
|
||||
|
||||
test("user can successfully update settings", async ({ page }) => {
|
||||
const settings = await navigateToSettings(page);
|
||||
|
||||
for (const id of TOGGLE_IDS) {
|
||||
const state = await getSwitchState(settings.getToggle(id));
|
||||
expect.soft(state, `Initial state of ${id}`).toBe(true);
|
||||
}
|
||||
|
||||
// Turn all ON, change email/password, save
|
||||
for (const id of TOGGLE_IDS) {
|
||||
await settings.disable(id);
|
||||
}
|
||||
const tempEmail = `temp+e2e@example.com`;
|
||||
await settings.setEmail(tempEmail);
|
||||
await settings.setPassword("temporarypassword123");
|
||||
await settings.setConfirmPassword("temporarypassword123");
|
||||
await settings.saveChanges();
|
||||
|
||||
// Reload and verify change email/password and OFF persisted
|
||||
await settings.goto();
|
||||
for (const id of TOGGLE_IDS) {
|
||||
const state = await getSwitchState(settings.getToggle(id));
|
||||
expect.soft(state, `Persisted OFF state of ${id}`).toBe(false);
|
||||
}
|
||||
await hasFieldValue(settings.getEmailInput(), tempEmail);
|
||||
await hasFieldValue(settings.getPasswordInput(), "temporarypassword123");
|
||||
|
||||
// Restore original test email and password
|
||||
await settings.setEmail(TEST_CREDENTIALS.email);
|
||||
await settings.setPassword(TEST_CREDENTIALS.password);
|
||||
await settings.setConfirmPassword(TEST_CREDENTIALS.password);
|
||||
for (const id of TOGGLE_IDS) {
|
||||
await settings.enable(id);
|
||||
}
|
||||
await settings.saveChanges();
|
||||
|
||||
// Reload and verify change email/password and ON persisted
|
||||
await settings.goto();
|
||||
for (const id of TOGGLE_IDS) {
|
||||
const state = await getSwitchState(settings.getToggle(id));
|
||||
expect.soft(state, `Persisted ON state of ${id}`).toBe(true);
|
||||
}
|
||||
await hasFieldValue(settings.getEmailInput(), TEST_CREDENTIALS.email);
|
||||
await hasFieldValue(settings.getPasswordInput(), TEST_CREDENTIALS.password);
|
||||
});
|
||||
|
||||
test("user can cancel changes", async ({ page }) => {
|
||||
const settings = await navigateToSettings(page);
|
||||
|
||||
const initialEmail = await settings.getEmailValue();
|
||||
await settings.setEmail("settings+cancel@example.com");
|
||||
|
||||
await settings.cancelChanges();
|
||||
await hasFieldValue(settings.getEmailInput(), initialEmail);
|
||||
});
|
||||
|
||||
test("settings form shows validation errors for invalid inputs", async ({ page }) => {
|
||||
const settings = await navigateToSettings(page);
|
||||
|
||||
await settings.setEmail("invalid-email");
|
||||
await settings.setPassword("short");
|
||||
await settings.setConfirmPassword("short");
|
||||
|
||||
await settings.saveChanges();
|
||||
|
||||
await settings.expectValidationError("Invalid email");
|
||||
await settings.expectValidationError("String must contain at least 12 character(s)");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user