Skip to content

Commit da6bd0b

Browse files
authored
Fix the flow to upgrade an upgraded legacy identity (#3406)
* Fix upgrade again flow * Remove unused variable * E2E test upgrade identity again * Inline function
1 parent 6fde217 commit da6bd0b

File tree

3 files changed

+81
-9
lines changed

3 files changed

+81
-9
lines changed

src/frontend/src/lib/components/wizards/migration/views/AlreadyMigrated.svelte

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
UpgradeIdentityEvents,
99
} from "$lib/utils/analytics/upgradeIdentityFunnel";
1010
11-
let { onUpgradeAgain }: { onUpgradeAgain: () => void } = $props();
11+
let {
12+
onUpgradeAgain,
13+
}: { onUpgradeAgain: (attachElement?: HTMLElement) => void } = $props();
14+
15+
let attachElement = $state<HTMLElement>();
1216
1317
onMount(() => {
1418
upgradeIdentityFunnel.trigger(UpgradeIdentityEvents.AlreadyMigratedScreen);
1519
});
1620
</script>
1721

18-
<div class="flex flex-1 flex-col">
22+
<div class="flex flex-1 flex-col" bind:this={attachElement}>
1923
<div class="mb-8 flex flex-col">
2024
<div class="text-text-primary flex h-32 items-center justify-center py-5">
2125
<MigrationIllustration />
@@ -48,7 +52,11 @@
4852
>
4953
Help & FAQ
5054
</Button>
51-
<Button onclick={onUpgradeAgain} variant="tertiary" size="lg">
55+
<Button
56+
onclick={() => onUpgradeAgain(attachElement)}
57+
variant="tertiary"
58+
size="lg"
59+
>
5260
Upgrade again
5361
</Button>
5462
</div>

src/frontend/src/lib/flows/migrationFlow.svelte.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export class MigrationFlow {
4444
view = $state<"enterNumber" | "enterName" | "alreadyMigrated">("enterNumber");
4545
identityNumber: UserNumber | undefined;
4646
#webAuthFlows: { flows: WebAuthnFlow[]; currentIndex: number } | undefined;
47-
#attachElement?: HTMLElement;
4847
#devices: Omit<DeviceData, "alias">[] = [];
4948

5049
constructor() {
@@ -56,7 +55,6 @@ export class MigrationFlow {
5655
attachElement?: HTMLElement,
5756
): Promise<void> => {
5857
this.identityNumber = identityNumber;
59-
this.#attachElement = attachElement;
6058
this.#devices = await this.#lookupAuthenticators(identityNumber);
6159
const alreadyMigrated = this.#devices.some(isNewOriginDevice);
6260
if (alreadyMigrated) {
@@ -71,17 +69,17 @@ export class MigrationFlow {
7169
});
7270
};
7371

74-
upgradeAgain = () => {
75-
if (isNullish(this.identityNumber) || isNullish(this.#attachElement)) {
72+
upgradeAgain = (attachElement?: HTMLElement) => {
73+
if (isNullish(this.identityNumber)) {
7674
// This shouldn't happen because `authenticateWithIdentityNumber` is called, before.
77-
// The identityNumber and attachElement are set in authenticateWithIdentityNumber from "enterNumber" view.
75+
// The identityNumber is set in authenticateWithIdentityNumber from "enterNumber" view.
7876
this.view = "enterNumber";
7977
return;
8078
}
8179
return this.#authenticate({
8280
identityNumber: this.identityNumber,
8381
devices: this.#devices,
84-
attachElement: this.#attachElement,
82+
attachElement,
8583
});
8684
};
8785

src/frontend/tests/e2e-playwright/dashboard/migration.spec.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from "../utils";
1111

1212
const TEST_USER_NAME = "Test User";
13+
const TEST_USER_NAME_2 = "Test User 2";
1314

1415
const createLegacyIdentity = async (page: Page) => {
1516
await page.getByRole("button", { name: "Create Internet Identity" }).click();
@@ -115,4 +116,69 @@ test.describe("Migration", () => {
115116
}),
116117
).toBeVisible();
117118
});
119+
120+
test("User can go through the upgrade flow again", async ({ page }) => {
121+
// Step 1: Create a legacy identity
122+
await page.goto(LEGACY_II_URL);
123+
124+
await addVirtualAuthenticator(page);
125+
const identityNumber = await createLegacyIdentity(page);
126+
127+
// Step 2: Navigate to the new II_URL to start the migration
128+
await page.goto(II_URL);
129+
await page.getByRole("link", { name: "Manage Identity" }).click();
130+
131+
// Step 3: Perform the first migration
132+
const auth = dummyAuth();
133+
await upgradeLegacyIdentity(page, identityNumber, auth);
134+
135+
// Step 4: Verify the migration was successful
136+
await page.waitForURL(II_URL + "/manage");
137+
await expect(
138+
page.getByRole("heading", {
139+
name: new RegExp(`Welcome, ${TEST_USER_NAME}!`),
140+
}),
141+
).toBeVisible();
142+
143+
// Step 5: Sign out
144+
await signOut(page);
145+
146+
// Step 6: Navigate back to upgrade flow with the same identity number
147+
await page.goto(II_URL);
148+
const auth2 = dummyAuth();
149+
150+
await page.getByRole("link", { name: "Manage Identity" }).click();
151+
await page.getByRole("button", { name: "Use another identity" }).click();
152+
await page.getByRole("button", { name: "Upgrade" }).click();
153+
await page
154+
.getByPlaceholder("Internet Identity number")
155+
.fill(identityNumber);
156+
await page.getByRole("button", { name: "Continue" }).click();
157+
158+
// Step 7: Verify "Identity already upgraded" screen appears
159+
await expect(
160+
page.getByRole("heading", { name: "Identity already upgraded" }),
161+
).toBeVisible();
162+
await expect(
163+
page.getByText(
164+
"This identity has already been upgraded to the new experience",
165+
),
166+
).toBeVisible();
167+
168+
// Step 8: Click "Upgrade again" button
169+
await page.getByRole("button", { name: "Upgrade again" }).click();
170+
171+
// Step 9: Complete the upgrade flow again with a different name
172+
await page.getByLabel("Identity name").fill(TEST_USER_NAME_2);
173+
auth2(page);
174+
await page.getByRole("button", { name: "Create Passkey" }).click();
175+
176+
// Step 10: Verify the second upgrade was successful
177+
await page.waitForURL(II_URL + "/manage");
178+
await expect(
179+
page.getByRole("heading", {
180+
name: new RegExp(`Welcome, ${TEST_USER_NAME_2}!`),
181+
}),
182+
).toBeVisible();
183+
});
118184
});

0 commit comments

Comments
 (0)