Skip to content

Commit d133a6b

Browse files
Add init test for e2e flow with passwordless and webauthn
1 parent 5976cbc commit d133a6b

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* Copyright (c) 2022, SuperTokens.com
3+
* All rights reserved.
4+
*/
5+
6+
import fetch from "isomorphic-fetch";
7+
import { TEST_SERVER_BASE_URL, TEST_CLIENT_BASE_URL } from "../constants";
8+
import {
9+
backendBeforeEach,
10+
setupBrowser,
11+
screenshotOnFailure,
12+
clearBrowserCookiesWithoutAffectingConsole,
13+
toggleSignInSignUp,
14+
getTestEmail,
15+
waitForSTElement,
16+
submitForm,
17+
setEnabledRecipes,
18+
setInputValues,
19+
setAccountLinkingConfig,
20+
getPasswordlessDevice,
21+
clickOnWebAuthnButton,
22+
} from "../helpers";
23+
import assert from "assert";
24+
25+
/*
26+
* Test case:
27+
* 1. The app has account linking disabled
28+
* 2. A user signs up using a non-webauthn factor (e.g.: passwordless)
29+
* 3. The user now tries signing up with webauthn using the same email
30+
* -> this should work and create an entirely separate user with an unverified email address
31+
*/
32+
describe("SuperTokens WebAuthn Account Linking", function () {
33+
let browser;
34+
let page;
35+
let consoleLogs = [];
36+
let userId1;
37+
let userId2;
38+
const email = getTestEmail();
39+
40+
before(async function () {
41+
await backendBeforeEach();
42+
43+
await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
44+
method: "POST",
45+
}).catch(console.error);
46+
47+
await setEnabledRecipes([
48+
"webauthn",
49+
"emailpassword",
50+
"passwordless",
51+
"session",
52+
"dashboard",
53+
"userroles",
54+
"multifactorauth",
55+
]);
56+
57+
browser = await setupBrowser();
58+
page = await browser.newPage();
59+
page.on("console", (consoleObj) => {
60+
const log = consoleObj.text();
61+
if (log.startsWith("ST_LOGS")) {
62+
consoleLogs.push(log);
63+
}
64+
});
65+
});
66+
67+
after(async function () {
68+
await browser.close();
69+
await fetch(`${TEST_SERVER_BASE_URL}/after`, {
70+
method: "POST",
71+
}).catch(console.error);
72+
73+
await fetch(`${TEST_SERVER_BASE_URL}/stopst`, {
74+
method: "POST",
75+
}).catch(console.error);
76+
});
77+
78+
afterEach(function () {
79+
return screenshotOnFailure(this, browser);
80+
});
81+
82+
beforeEach(async function () {
83+
consoleLogs = [];
84+
consoleLogs = await clearBrowserCookiesWithoutAffectingConsole(page, consoleLogs);
85+
await toggleSignInSignUp(page);
86+
});
87+
88+
it("Should create separate users when signing up with same email using different auth methods (account linking disabled)", async function () {
89+
// Disable account linking
90+
await setAccountLinkingConfig(false, false);
91+
const email = await getTestEmail();
92+
93+
await Promise.all([
94+
page.goto(`${TEST_CLIENT_BASE_URL}/auth?authRecipe=passwordless`),
95+
page.waitForNavigation({ waitUntil: "networkidle0" }),
96+
]);
97+
98+
// Signup using the email
99+
await setInputValues(page, [{ name: "email", value: email }]);
100+
await submitForm(page);
101+
102+
await waitForSTElement(page, "[data-supertokens~=input][name=userInputCode]");
103+
104+
const loginAttemptInfo = JSON.parse(
105+
await page.evaluate(() => localStorage.getItem("supertokens-passwordless-loginAttemptInfo"))
106+
);
107+
const device = await getPasswordlessDevice(loginAttemptInfo);
108+
await setInputValues(page, [{ name: "userInputCode", value: device.codes[0].userInputCode }]);
109+
await submitForm(page);
110+
await page.waitForTimeout(2000);
111+
112+
// We want to parse the text inside the session-context-userId div
113+
const userId = await page.evaluate(() => document.querySelector(".session-context-userId").textContent);
114+
console.log(userId);
115+
assert.strictEqual(userId, "undefined");
116+
117+
userId1 = userId;
118+
119+
// Extract userId from console logs
120+
const userIdLog = consoleLogs.find((log) => log.includes("ST_LOGS SESSION"));
121+
userId1 = userIdLog.split("ST_LOGS SESSION")[1].trim();
122+
123+
// Find the div with classname logoutButton and click it using normal
124+
// puppeteer selector
125+
const logoutButton = await page.waitForSelector("div.logoutButton");
126+
await logoutButton.click();
127+
await new Promise((res) => setTimeout(res, 1000));
128+
129+
await tryWebauthnSignUp(page, email);
130+
131+
// We should be in the confirmation page now.
132+
await submitForm(page);
133+
134+
await page.waitForTimeout(5000);
135+
136+
// Wait for successful registration and login
137+
await page.waitForNavigation({ waitUntil: "networkidle0" });
138+
139+
// Extract second userId from console logs
140+
const userIdLog2 = consoleLogs.find((log) => log.includes("ST_LOGS SESSION"));
141+
userId2 = userIdLog2.split("ST_LOGS SESSION")[1].trim();
142+
143+
// Verify that two different users were created
144+
assert.notStrictEqual(
145+
userId1,
146+
userId2,
147+
"Different auth methods with same email should create separate users when account linking is disabled"
148+
);
149+
150+
// Verify that the second user has an unverified email
151+
// This would require checking the API or console logs for email verification status
152+
const emailVerificationLog = consoleLogs.find((log) => log.includes("isEmailVerified"));
153+
assert(emailVerificationLog.includes("false"), "The WebAuthn user should have an unverified email");
154+
});
155+
});

0 commit comments

Comments
 (0)