Fix ConfirmationButton usage in pricing page and e2e tests

- Update pricing page to use ConfirmationButton API correctly (isConfirming, onConfirm, onCancel, onActionClick)
- Fix e2e tests to set up response listeners before navigation
- Fix validation error selector to use .first() for multiple matches
- All 9 e2e tests now passing
This commit is contained in:
counterweight 2025-12-26 21:07:56 +01:00
parent 1874c3a057
commit 1ef5ebe493
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
2 changed files with 64 additions and 38 deletions

View file

@ -49,6 +49,7 @@ export default function AdminPricingPage() {
const [errors, setErrors] = useState<ValidationErrors>({});
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const [isConfirming, setIsConfirming] = useState(false);
const fetchConfig = useCallback(async () => {
setError(null);
@ -180,12 +181,16 @@ export default function AdminPricingPage() {
},
});
const handleSave = () => {
if (!formData) return;
const handleConfirmSave = () => {
if (!formData) {
setIsConfirming(false);
return;
}
const validationErrors = validateForm(formData);
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
setIsConfirming(false);
return;
}
@ -199,6 +204,7 @@ export default function AdminPricingPage() {
eur_min_sell: formData.eur_min_sell,
eur_max_sell: formData.eur_max_sell,
});
setIsConfirming(false);
};
if (isLoading || !formData) {
@ -385,16 +391,19 @@ export default function AdminPricingPage() {
<div style={formStyles.actions}>
<ConfirmationButton
onClick={handleSave}
disabled={hasErrors || isSaving}
confirmMessage={t("pricing.confirmSave")}
style={{
isConfirming={isConfirming}
onConfirm={handleConfirmSave}
onCancel={() => setIsConfirming(false)}
onActionClick={() => setIsConfirming(true)}
actionLabel={isSaving ? tCommon("saving") : t("pricing.save")}
confirmLabel={tCommon("confirm")}
cancelLabel={tCommon("cancel")}
isLoading={isSaving}
actionButtonStyle={{
...buttonStyles.primary,
...(hasErrors || isSaving ? buttonStyles.disabled : {}),
}}
>
{isSaving ? tCommon("saving") : t("pricing.save")}
</ConfirmationButton>
/>
</div>
</form>
</div>

View file

@ -24,16 +24,18 @@ test.describe("Admin Pricing Page - Admin Access", () => {
await expect(pricingLink).toBeVisible();
// Test page access and structure
// Set up response listener before navigation
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await page.goto("/admin/pricing");
await expect(page).toHaveURL("/admin/pricing");
// Wait for API call to complete and form to render
await page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible({
timeout: 10000,
});
await responsePromise;
// Wait for form inputs to be visible (indicates form has loaded)
await expect(page.locator('input[type="number"]').first()).toBeVisible({ timeout: 10000 });
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible();
await expect(page.getByText("Configure premium pricing and trade amount limits")).toBeVisible();
// Check all form fields are present (using text + input selector since labels aren't associated)
@ -52,12 +54,14 @@ test.describe("Admin Pricing Page - Admin Access", () => {
});
test("can view current pricing configuration", async ({ page }) => {
// Set up response listener before navigation
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await page.goto("/admin/pricing");
// Wait for API call to complete and form to render
await page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await responsePromise;
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible({
timeout: 10000,
});
@ -77,12 +81,14 @@ test.describe("Admin Pricing Page - Admin Access", () => {
});
test("can update pricing configuration", async ({ page }) => {
// Set up response listener before navigation
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await page.goto("/admin/pricing");
// Wait for API call to complete and form to render
await page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await responsePromise;
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible({
timeout: 10000,
});
@ -98,6 +104,13 @@ test.describe("Admin Pricing Page - Admin Access", () => {
await premiumBuyInput.clear();
await premiumBuyInput.fill(newBuyValue);
// Wait a bit for any validation to clear
await page.waitForTimeout(200);
// Verify save button is enabled before clicking
const saveButton = page.getByRole("button", { name: /Save Changes/i });
await expect(saveButton).toBeEnabled({ timeout: 5000 });
// Set up response listener before clicking save
const putPromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "PUT"
@ -106,12 +119,12 @@ test.describe("Admin Pricing Page - Admin Access", () => {
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
// Click save button (with confirmation)
await page.getByRole("button", { name: /Save Changes/i }).click();
// Click save button (enters confirmation mode)
await saveButton.click();
// Confirm the save action
await expect(page.getByText(/Are you sure/i)).toBeVisible();
await page.getByRole("button", { name: /confirm|yes|ok/i }).click();
// Confirm the save action (button text changes to "Confirm")
await expect(page.getByRole("button", { name: /Confirm/i })).toBeVisible({ timeout: 5000 });
await page.getByRole("button", { name: /Confirm/i }).click();
// Wait for API calls to complete
await putPromise;
@ -127,12 +140,14 @@ test.describe("Admin Pricing Page - Admin Access", () => {
});
test("validation prevents invalid values", async ({ page }) => {
// Set up response listener before navigation
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await page.goto("/admin/pricing");
// Wait for API call to complete and form to render
await page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await responsePromise;
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible({
timeout: 10000,
});
@ -146,8 +161,8 @@ test.describe("Admin Pricing Page - Admin Access", () => {
// Try to save
await page.getByRole("button", { name: /Save Changes/i }).click();
await expect(page.getByText(/confirm|yes|ok/i)).toBeVisible();
await page.getByRole("button", { name: /confirm|yes|ok/i }).click();
await expect(page.getByRole("button", { name: /Confirm/i })).toBeVisible({ timeout: 2000 });
await page.getByRole("button", { name: /Confirm/i }).click();
// Should show validation error
await expect(page.getByText(/must be between.*-100.*100/i)).toBeVisible({ timeout: 2000 });
@ -167,22 +182,24 @@ test.describe("Admin Pricing Page - Admin Access", () => {
// Try to save
await page.getByRole("button", { name: /Save Changes/i }).click();
await expect(page.getByText(/confirm|yes|ok/i)).toBeVisible();
await page.getByRole("button", { name: /confirm|yes|ok/i }).click();
await expect(page.getByRole("button", { name: /Confirm/i })).toBeVisible({ timeout: 2000 });
await page.getByRole("button", { name: /Confirm/i }).click();
// Should show validation error
await expect(page.getByText(/minimum must be less than maximum/i)).toBeVisible({
// Should show validation error (there are two - one for min, one for max)
await expect(page.getByText(/minimum must be less than maximum/i).first()).toBeVisible({
timeout: 2000,
});
});
test("form fields update correctly when values change", async ({ page }) => {
// Set up response listener before navigation
const responsePromise = page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await page.goto("/admin/pricing");
// Wait for API call to complete and form to render
await page.waitForResponse(
(resp) => resp.url().includes("/api/admin/pricing") && resp.request().method() === "GET"
);
await responsePromise;
await expect(page.getByRole("heading", { name: "Pricing Configuration" })).toBeVisible({
timeout: 10000,
});