Skip to content

Commit

Permalink
Fix signup query (#1608)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
miguelnietoa committed Jan 26, 2022
1 parent cad77ad commit 73de0c2
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 16 deletions.
2 changes: 1 addition & 1 deletion components/team/MemberInvitationModal.tsx
Expand Up @@ -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}>
Expand Down
7 changes: 6 additions & 1 deletion components/team/MemberListItem.tsx
Expand Up @@ -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">
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
15 changes: 4 additions & 11 deletions pages/api/auth/signup.ts
Expand Up @@ -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 } }],
},
],
},
Expand Down
3 changes: 2 additions & 1 deletion pages/settings/teams/[id].tsx
Expand Up @@ -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>
Expand Down
13 changes: 13 additions & 0 deletions playwright.config.ts
@@ -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,
Expand Down
102 changes: 101 additions & 1 deletion playwright/auth/auth-index.test.ts
@@ -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");
2 changes: 1 addition & 1 deletion playwright/lib/globalSetup.ts
Expand Up @@ -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();
}

Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down

1 comment on commit 73de0c2

@vercel
Copy link

@vercel vercel bot commented on 73de0c2 Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.