Skip to content

Commit 48960d9

Browse files
committed
fix: nearly complete tests
might need to double check with more manual flows
1 parent 96952fb commit 48960d9

File tree

2 files changed

+135
-13
lines changed

2 files changed

+135
-13
lines changed

packages/auth-server/components/account-recovery/passkey-generation-flow/Step3ConfirmLater.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ const recoveryUrl = computedAsync(async () => {
4646
const queryParams = new URLSearchParams();
4747
4848
const credentialId = props.newPasskey.credentialId;
49-
const credentialPublicKey = uint8ArrayToHex(props.newPasskey.credentialPublicKey);
49+
// Serialize the public key as JSON since it's {x, y} format
50+
const credentialPublicKey = JSON.stringify(props.newPasskey.credentialPublicKey);
5051
5152
queryParams.set("credentialId", credentialId);
5253
queryParams.set("credentialPublicKey", credentialPublicKey);

packages/auth-server/tests/guardian.spec.ts

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ test("Guardian flow: propose and confirm guardian", async ({ page, context: _con
395395
await guardianPage.waitForTimeout(5000);
396396

397397
// Check for success message
398-
const successIndicator = guardianPage.getByText(/Guardian.*confirmed|Success|Confirmed/i);
398+
const successIndicator = guardianPage.getByText(/Guardian.*confirmed|Success|Confirmed/i).first();
399399
if (await successIndicator.isVisible({ timeout: 5000 })) {
400400
console.log("✅ Guardian confirmation success message visible");
401401
} else {
@@ -678,7 +678,7 @@ test("Guardian flow: propose guardian with paymaster", async ({ page }) => {
678678

679679
// Verify success
680680
await guardianPage.waitForTimeout(5000);
681-
const successIndicator = guardianPage.getByText(/Guardian.*confirmed|Success|Confirmed/i);
681+
const successIndicator = guardianPage.getByText(/Guardian.*confirmed|Success|Confirmed/i).first();
682682
if (await successIndicator.isVisible({ timeout: 5000 })) {
683683
console.log("✅ Guardian confirmation success message visible");
684684
} else {
@@ -844,20 +844,141 @@ test("Guardian flow: full recovery execution", async ({ page, context: baseConte
844844
await guardianPage.waitForTimeout(2000);
845845
}
846846

847-
// Check if confirmation text appeared
848-
const confirmingVisible = await guardianPage.getByText(/confirming/i).isVisible({ timeout: 2000 }).catch(() => false);
849-
if (!confirmingVisible) {
850-
const finalState = await stateElement.textContent().catch(() => "unknown");
851-
console.log("⚠️ 'Confirming' text not visible after waiting. Final state:", finalState);
852-
throw new Error(`Guardian confirmation did not show progress. Final state: ${finalState}`);
847+
// Check for successful completion
848+
const finalState = await stateElement.textContent().catch(() => "unknown");
849+
if (finalState !== "complete" && finalState !== "confirm_guardian_completed") {
850+
console.log("⚠️ Guardian confirmation did not complete. Final state:", finalState);
851+
throw new Error(`Guardian confirmation failed. Final state: ${finalState}`);
853852
}
854-
console.log("✅ Guardian confirmed successfully");
853+
console.log("✅ Guardian confirmed successfully. Final state:", finalState);
855854

856-
// NOTE: Recovery execution steps 5-10 would follow similar patterns
857-
// but are skipped until recovery UI pages are updated with proper test IDs
855+
// Step 5: Owner initiates recovery with new passkey
856+
console.log("\nStep 5: Owner initiating account recovery...");
858857

859-
console.log("\n=== Full Recovery Execution E2E Test Complete (Skipped) ===\n");
858+
// Create new recovery credential
859+
const recoveryContext = await baseContext.browser()!.newContext();
860+
const recoveryPage = await recoveryContext.newPage();
861+
862+
// Navigate directly to guardian recovery page
863+
await recoveryPage.goto("http://localhost:3002/recovery/guardian");
864+
await recoveryPage.waitForTimeout(2000);
865+
866+
// Enter owner account address - find the input inside the ZkInput component
867+
const accountInput = recoveryPage.locator("#address input");
868+
await expect(accountInput).toBeVisible({ timeout: 10000 });
869+
await accountInput.fill(ownerAddress);
870+
await recoveryPage.waitForTimeout(1000);
871+
872+
// Click Continue button
873+
const continueBtn = recoveryPage.getByRole("button", { name: /Continue/i });
874+
await expect(continueBtn).toBeEnabled({ timeout: 5000 });
875+
await continueBtn.click();
876+
await recoveryPage.waitForTimeout(2000);
877+
878+
// Set up WebAuthn mock for recovery passkey
879+
await setupWebAuthn(recoveryPage);
880+
881+
const createPasskeyBtn = recoveryPage.getByRole("button", { name: /Generate Passkey/i });
882+
await expect(createPasskeyBtn).toBeVisible({ timeout: 10000 });
883+
await createPasskeyBtn.click();
884+
await recoveryPage.waitForTimeout(3000);
885+
886+
// Click "Confirm Later" to see the recovery URL
887+
const confirmLaterBtn = recoveryPage.getByRole("button", { name: /Confirm Later/i });
888+
await expect(confirmLaterBtn).toBeVisible({ timeout: 10000 });
889+
await confirmLaterBtn.click();
890+
await recoveryPage.waitForTimeout(2000);
891+
892+
// Wait for the recovery URL link to be visible and extract it
893+
const recoveryLink = recoveryPage.locator("a[href*='confirm-recovery']");
894+
await expect(recoveryLink).toBeVisible({ timeout: 10000 });
895+
896+
const confirmRecoveryUrl = await recoveryLink.getAttribute("href");
897+
898+
console.log(`✅ Recovery initiated. Confirmation URL: ${confirmRecoveryUrl}`);
899+
900+
// Step 6: Guardian confirms the recovery
901+
console.log("\nStep 6: Guardian confirming recovery request...");
902+
903+
if (!confirmRecoveryUrl) {
904+
throw new Error("Failed to get recovery confirmation URL");
905+
}
906+
907+
// The URL is already a full URL, use it directly
908+
await guardianPage.goto(confirmRecoveryUrl);
909+
console.log("Navigated to recovery confirmation page");
910+
911+
// Wait for page to load
912+
await guardianPage.waitForLoadState("networkidle");
913+
await guardianPage.waitForTimeout(2000);
914+
915+
// Take a screenshot to see what's on the page
916+
await guardianPage.screenshot({ path: "test-results/recovery-page-debug.png" });
917+
918+
// Check what's actually on the page
919+
const bodyText = await guardianPage.locator("body").textContent();
920+
console.log(`Page content (first 1000 chars): ${bodyText?.substring(0, 1000)}`);
921+
922+
// Check if there's an error message first (before trying to find h1)
923+
const errorCard = guardianPage.locator("[title='Error']");
924+
const hasError = await errorCard.isVisible().catch(() => false);
925+
if (hasError) {
926+
const errorMsg = await guardianPage.locator("body").textContent();
927+
console.log(`❌ Error on recovery page: ${errorMsg?.substring(0, 500)}`);
928+
throw new Error(`Recovery page shows error. credentialPublicKey is empty in URL: ${confirmRecoveryUrl}`);
929+
}
930+
931+
// Now try to find h1
932+
const h1Element = guardianPage.locator("h1");
933+
const h1Visible = await h1Element.isVisible().catch(() => false);
934+
if (!h1Visible) {
935+
throw new Error(`No h1 found on page. This likely means the page failed to load due to missing credentialPublicKey in URL: ${confirmRecoveryUrl}`);
936+
}
937+
const pageTitle = await h1Element.textContent();
938+
console.log(`Recovery page title: ${pageTitle}`);
939+
940+
// Select guardian from dropdown (it's a native select element inside account-recovery-account-select)
941+
const guardianSelect = guardianPage.locator("select");
942+
await expect(guardianSelect).toBeVisible({ timeout: 10000 });
943+
await guardianSelect.selectOption(guardianAddress);
944+
await guardianPage.waitForTimeout(1000);
945+
946+
// Confirm the recovery
947+
const confirmRecoveryBtn = guardianPage.getByRole("button", { name: /Confirm Recovery/i });
948+
await expect(confirmRecoveryBtn).toBeVisible({ timeout: 10000 });
949+
await confirmRecoveryBtn.click();
950+
await guardianPage.waitForTimeout(5000);
951+
952+
// Verify recovery was initiated
953+
const recoveryCompletedMsg = guardianPage.getByText(/24hrs/i);
954+
const recoveryCompleted = await recoveryCompletedMsg.isVisible({ timeout: 10000 }).catch(() => false);
955+
956+
if (!recoveryCompleted) {
957+
// Take a screenshot for debugging
958+
await guardianPage.screenshot({ path: "test-results/recovery-confirmation-debug.png" });
959+
const bodyText = await guardianPage.locator("body").textContent();
960+
console.log("Page content:", bodyText?.substring(0, 500));
961+
throw new Error("Recovery confirmation failed - completion message not visible");
962+
}
963+
964+
console.log("✅ Guardian confirmed recovery successfully");
965+
966+
// Step 7: Verify recovery is pending (skip execution for now as it requires time travel)
967+
console.log("\nStep 7: Verifying recovery is in pending state...");
968+
console.log("Note: Full recovery execution requires EVM time manipulation");
969+
console.log("The recovery would need to wait 24 hours before it can be finalized");
970+
971+
console.log("\n=== Full Recovery E2E Flow Complete ===\n");
972+
console.log("Summary:");
973+
console.log(" ✅ Owner account created");
974+
console.log(" ✅ Guardian account created");
975+
console.log(" ✅ Guardian proposed by owner");
976+
console.log(" ✅ Guardian confirmed their role");
977+
console.log(" ✅ Owner initiated recovery with new passkey");
978+
console.log(" ✅ Guardian confirmed the recovery request");
979+
console.log(" ⏳ Recovery pending (24hr delay before finalization)");
860980

861981
// Cleanup
862982
await guardianContext.close();
983+
await recoveryContext.close();
863984
});

0 commit comments

Comments
 (0)