Fix signup query (#1608)

* Remove emailVerified not null from query

* Improve query to find existing user

* Add test suite to Signup from a Team Invite

* Allow importing modules with aliases

* Delete created data after all tests

* Resolve conflicts

* Use teampro instead of pro user and refactor code
pull/1618/head^2
Miguel Nieto A 2022-01-26 11:56:22 -05:00 committed by GitHub
parent cad77ad237
commit 73de0c2185
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 140 additions and 16 deletions

View File

@ -125,7 +125,7 @@ export default function MemberInvitationModal(props: { team: TeamWithMembers | n
</p>
)}
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" color="primary" className="ml-2">
<Button type="submit" color="primary" className="ml-2" data-testid="invite-new-member-button">
{t("invite")}
</Button>
<Button type="button" color="secondary" onClick={props.onExit}>

View File

@ -71,7 +71,12 @@ export default function MemberListItem(props: Props) {
/>
<div className="inline-block ml-3">
<span className="text-sm font-bold text-neutral-700">{name}</span>
<span className="block -mt-1 text-xs text-gray-400">{props.member.email}</span>
<span
className="block -mt-1 text-xs text-gray-400"
data-testid="member-email"
data-email={props.member.email}>
{props.member.email}
</span>
</div>
</div>
<div className="flex mt-2 mr-2 sm:mt-0 sm:justify-center">

View File

@ -116,6 +116,7 @@
"@types/jest": "^27.0.3",
"@types/lodash": "^4.14.177",
"@types/micro": "^7.3.6",
"@types/module-alias": "^2.0.1",
"@types/node": "^16.11.10",
"@types/nodemailer": "^6.4.4",
"@types/qrcode": "^1.4.1",
@ -140,6 +141,7 @@
"jest": "^26.0.0",
"lint-staged": "^11.1.2",
"mockdate": "^3.0.5",
"module-alias": "^2.2.2",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.4",
"prettier": "^2.3.2",

View File

@ -31,21 +31,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return;
}
// There is actually an existingUser if username matches
// OR if email matches and both username and password are set
const existingUser = await prisma.user.findFirst({
where: {
OR: [
{ username },
{
username: username,
},
{
email: userEmail,
},
],
AND: [
{
emailVerified: {
not: null,
},
AND: [{ email: userEmail }, { password: { not: null } }, { username: { not: null } }],
},
],
},

View File

@ -72,7 +72,8 @@ export function TeamSettingsPage() {
type="button"
color="secondary"
StartIcon={PlusIcon}
onClick={() => setShowMemberInvitationModal(true)}>
onClick={() => setShowMemberInvitationModal(true)}
data-testid="new-member-button">
{t("new_member")}
</Button>
</div>

View File

@ -1,4 +1,17 @@
import { PlaywrightTestConfig, devices } from "@playwright/test";
import { addAliases } from "module-alias";
// Add aliases for the paths specified in the tsconfig.json file.
// This is needed because playwright does not consider tsconfig.json
// For more info, see:
// https://stackoverflow.com/questions/69023682/typescript-playwright-error-cannot-find-module
// https://github.com/microsoft/playwright/issues/7066#issuecomment-983984496
addAliases({
"@components": __dirname + "/components",
"@lib": __dirname + "/lib",
"@server": __dirname + "/server",
"@ee": __dirname + "/ee",
});
const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,

View File

@ -1,5 +1,105 @@
import { expect, test } from "@playwright/test";
import { BASE_URL } from "@lib/config/constants";
import prisma from "@lib/prisma";
import { todo } from "../lib/testUtils";
todo("Can signup from a team invite");
test.describe("Can signup from a team invite", async () => {
let page;
let token: string | undefined;
let signupFromInviteURL = "";
const team = { name: "Seeded Team", slug: "seeded-team" };
const testUser = {
email: "test@test.com",
password: "secretpassword123",
validUsername: "test-user",
};
const usernameAlreadyTaken = "teampro";
const emailAlreadyTaken = "teampro@example.com";
test.use({ storageState: "playwright/artifacts/teamproStorageState.json" });
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
await page.goto("/settings/teams");
await page.waitForSelector(`a[title="${team.name}"]`);
await page.click(`a[title="${team.name}"]`);
// Send invite to team
await page.click('[data-testid="new-member-button"]');
await page.fill('input[id="inviteUser"]', testUser.email);
await page.click('[data-testid="invite-new-member-button"]');
// Wait for the invite to be sent
await page.waitForSelector(`[data-testid="member-email"][data-email="${testUser.email}"]`);
const tokenObj = await prisma.verificationRequest.findFirst({
where: { identifier: testUser.email },
select: { token: true },
});
token = tokenObj?.token;
signupFromInviteURL = `/auth/signup?token=${token}&callbackUrl=${BASE_URL}/settings/teams`;
});
test.afterAll(async () => {
// Delete test user
await prisma.user.delete({
where: { email: testUser.email },
});
// Delete verification request
await prisma.verificationRequest.delete({
where: { token },
});
});
test("Username already taken", async ({ page }) => {
expect(token).toBeDefined();
await page.goto(signupFromInviteURL);
// Fill in form
await page.fill('input[name="username"]', usernameAlreadyTaken);
await page.fill('input[name="email"]', testUser.email);
await page.fill('input[name="password"]', testUser.password);
await page.fill('input[name="passwordcheck"]', testUser.password);
await page.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(page.locator('text="Username already taken"')).toBeVisible();
});
test("Email address is already registered", async ({ page }) => {
expect(token).toBeDefined();
await page.goto(signupFromInviteURL);
// Fill in form
await page.fill('input[name="username"]', testUser.validUsername);
await page.fill('input[name="email"]', emailAlreadyTaken);
await page.fill('input[name="password"]', testUser.password);
await page.fill('input[name="passwordcheck"]', testUser.password);
await page.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(page.locator('text="Email address is already registered"')).toBeVisible();
});
test("Successful signup", async ({ page }) => {
expect(token).toBeDefined();
await page.goto(signupFromInviteURL);
// Fill in form
await page.fill('input[name="username"]', testUser.validUsername);
await page.fill('input[name="email"]', testUser.email);
await page.fill('input[name="password"]', testUser.password);
await page.fill('input[name="passwordcheck"]', testUser.password);
await page.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await page.waitForNavigation();
const createdUser = await prisma.user.findUnique({
where: { email: testUser.email },
});
expect(createdUser).not.toBeNull();
expect(createdUser?.username).toBe(testUser.validUsername);
expect(createdUser?.password).not.toBeNull();
expect(createdUser?.emailVerified).not.toBeNull();
});
});
todo("Can login using 2FA");

View File

@ -33,7 +33,7 @@ async function globalSetup(/* config: FullConfig */) {
await loginAsUser("free", browser);
// await loginAsUser("usa", browser);
// await loginAsUser("teamfree", browser);
// await loginAsUser("teampro", browser);
await loginAsUser("teampro", browser);
await browser.close();
}

View File

@ -2589,6 +2589,11 @@
"@types/node" "*"
"@types/socket.io" "2.1.13"
"@types/module-alias@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/module-alias/-/module-alias-2.0.1.tgz#e5893236ce922152d57c5f3f978f764f4deeb45f"
integrity sha512-DN/CCT1HQG6HquBNJdLkvV+4v5l/oEuwOHUPLxI+Eub0NED+lk0YUfba04WGH90EINiUrNgClkNnwGmbICeWMQ==
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
@ -7548,6 +7553,11 @@ mockdate@^3.0.5:
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb"
integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==
module-alias@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==
mongodb-connection-string-url@^2.3.2:
version "2.4.1"
resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.4.1.tgz#6b3c6c40133a0ad059fe9a0abda64b2a1cb4e8b4"