diff --git a/playwright.config.ts b/playwright.config.ts index fdff474..c54c5b6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -16,7 +16,7 @@ const config: PlaywrightTestConfig = { expect: { timeout: 3000 }, - // timeout: 10000, + timeout: 10000, testDir: 'tests', use: { locale: 'en-US', diff --git a/prisma/constants.ts b/prisma/constants.ts index 5ce46fe..517fb6e 100644 --- a/prisma/constants.ts +++ b/prisma/constants.ts @@ -1,8 +1,3 @@ -export const PHONES = [ - '+12015550121', - '+12015550122', - '+12015550123', - '+12015550124', - '+12015550125', - '+12015550126' -]; +export const USERS_WITH_NOTHING = [1, 2, 7]; +export const USERS_WITH_EMPTY_HOUSEHOLD = [3, 4]; +export const USERS_WITH_ACTIVE_SESSION = [2, 4, 6, 7]; \ No newline at end of file diff --git a/prisma/seed.ts b/prisma/seed.ts index 23d8467..92c935c 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,16 +1,20 @@ import { PrismaClient } from '@prisma/client'; +import { USERS_WITH_ACTIVE_SESSION, USERS_WITH_EMPTY_HOUSEHOLD, USERS_WITH_NOTHING } from './constants'; import SeedUtils from './utils'; const prisma = new PrismaClient(); async function main() { const utils = new SeedUtils(new Date(), prisma); + + await utils.deleteAllHouseholds(); + await Promise.all([ utils.deleteAllFriendRequests(), utils.createExpiredLink(1), - ...[1, 2].map((userInd) => utils.createUserWithNothing(userInd)), - ...[3, 4].map((userInd) => utils.createUserWithEmptyHousehold(userInd)), - ...[2, 4, 6].map((userInd) => utils.createActiveSession(userInd)), + ...USERS_WITH_NOTHING.map((userInd) => utils.createUserWithNothing(userInd)), + ...USERS_WITH_EMPTY_HOUSEHOLD.map((userInd) => utils.createUserWithEmptyHousehold(userInd)), + ...USERS_WITH_ACTIVE_SESSION.map((userInd) => utils.createActiveSession(userInd)), utils.createUserWithEmptyHousehold(5), utils.createUserWithKid(6), ]); diff --git a/prisma/utils.ts b/prisma/utils.ts index ce62c55..a5c6d99 100644 --- a/prisma/utils.ts +++ b/prisma/utils.ts @@ -9,7 +9,8 @@ export default class SeedUtils { '+12015550123', '+12015550124', '+12015550125', - '+12015550126' + '+12015550126', + '+12015550127' ]; constructor(now: Date, prisma: PrismaClient) { @@ -100,6 +101,96 @@ export default class SeedUtils { .catch(() => console.log('No friend request table to delete')); } + async deleteAllHouseholds() { + await this.#prisma.householdChild + .deleteMany() + .catch(() => console.log('No household child table to delete')); + await this.#prisma.household + .deleteMany() + .catch(() => console.log('No household table to delete')); + } + + async deleteUserAndHousehold(phone: string) { + const user = await this.#prisma.user.findUnique({ + where: { phone } + }); + if (!user || !user.householdId) return; + const { householdId } = user; + // delete all kids + const deleteKids = this.#prisma.householdChild.deleteMany({ + where: { + householdId + } + }); + + // delete household invites this household has issued + const deleteHouseholdInvites = this.#prisma.joinHouseholdRequest.deleteMany({ + where: { + householdId + } + }); + + // delete friend reqs this household has issued + const deleteFriendReqs1 = this.#prisma.friendRequest.deleteMany({ + where: { + fromHouseholdId: householdId + } + }); + + // delete all friends with this household + const deleteFriends1 = this.#prisma.householdConnection.deleteMany({ + where: { + householdId + } + }); + const deleteFriends2 = this.#prisma.householdConnection.deleteMany({ + where: { + friendHouseholdId: householdId + } + }); + + const householdUsers = await this.#prisma.user.findMany({ + where: { + householdId + }, + select: { + phone: true + } + }); + + const householdPhones = householdUsers.map((x) => x.phone); + + // delete friend reqs this household has received + const deleteFriendReqs2 = this.#prisma.friendRequest.deleteMany({ + where: { + targetPhone: { in: householdPhones } + } + }); + + // delete all adults + const deleteAdults = this.#prisma.user.deleteMany({ + where: { + householdId + } + }); + + // finally, delete the household + const deleteHousehold = this.#prisma.household.delete({ + where: { id: householdId } + }); + + await this.#prisma.$transaction([ + deleteKids, + deleteHouseholdInvites, + deleteFriendReqs1, + deleteFriendReqs2, + deleteFriends1, + deleteFriends2, + deleteAdults, + deleteHousehold + ]); + } + async createExpiredLink(userInd: number) { const expiredLink = { token: '3e99472f1003794c', diff --git a/src/lib/components/Dashboard/ScheduleTable.svelte b/src/lib/components/Dashboard/ScheduleTable.svelte index c596e81..46a73e4 100644 --- a/src/lib/components/Dashboard/ScheduleTable.svelte +++ b/src/lib/components/Dashboard/ScheduleTable.svelte @@ -66,9 +66,7 @@ .flex { display: flex; } - .border-right { - border-right: 1px solid #dddddd; - } + table { border-collapse: collapse; border: 1px solid #dddddd; diff --git a/src/routes/household/+page.svelte b/src/routes/household/+page.svelte index 78c08dc..c348891 100644 --- a/src/routes/household/+page.svelte +++ b/src/routes/household/+page.svelte @@ -411,7 +411,7 @@ {/if}

Kids

{#each kids as kid, ind} -
+

{kid.firstName} {kid.lastName ?? ''}

Pronouns: {PRONOUNS[kid.pronouns]}

Age: {isNaN(kid.age) ? 'N/A' : kid.age}

@@ -421,26 +421,34 @@ {/each}
- - - - - - - - - - - + + + + + + +
diff --git a/tests/db.spec.ts b/tests/db.spec.ts index 89a65f2..e78a1c9 100644 --- a/tests/db.spec.ts +++ b/tests/db.spec.ts @@ -1,14 +1,31 @@ -import { test, expect } from '@playwright/test'; -import { run } from '../prisma/seed'; +import { expect, test } from '@playwright/test'; +import { PrismaClient } from '@prisma/client'; +import SeedUtils from '../prisma/utils'; -// const url = 'http://localhost:5173/profile'; const host = 'http://localhost:5173'; +const prisma = new PrismaClient(); +test.beforeAll(async () => { + const utils = new SeedUtils(new Date(), prisma); -test.beforeEach(async () => { - await run(); + await Promise.all([ + utils.deleteUserAndHousehold('+12015550003'), + utils.deleteUserAndHousehold('+12015550004'), + utils.deleteAllFriendRequests() + ]); + + await Promise.all([ + ...[3, 4].map((userInd) => utils.createUserWithEmptyHousehold(userInd)), + ...[4].map((userInd) => utils.createActiveSession(userInd)) + ]); + + await Promise.all([ + utils.createFriendRequest(4, 3), + utils.createHouseholdConnection(3, 5), + utils.createHouseholdInvite(5, 2) + ]); }); -test("User can't save profile without session cookie", async ({ page, context }) => { +test.only("User can't save profile without session cookie", async ({ page, context }) => { const res = await context.request.fetch(host + '/db', { method: 'post', headers: { @@ -35,124 +52,158 @@ that info is derived from the session cookie - User 6 fails to delete another user */ -test("User 4 fails to accept friend request on User 3's behalf", async ({ page, context }) => { - await context.addCookies([ - { - name: 'session', - value: 'user4session', - url: host - } - ]); - const res = await context.request.fetch(host + '/db', { - method: 'post', - headers: { - 'Content-Type': 'application/json' - }, - data: { - type: 'acceptFriendReq', - friendReqId: 3 - } +test.describe.only('Household Invites', () => { + test.beforeAll(async () => { + const utils = new SeedUtils(new Date(), prisma); + + await Promise.all([ + utils.deleteUserAndHousehold('+12015550001'), + utils.deleteUserAndHousehold('+12015550002') + ]); + + await Promise.all([ + ...[1].map((userInd) => utils.createUserWithNothing(userInd)), + ...[2].map((userInd) => utils.createUserWithEmptyHousehold(userInd)), + ...[1, 2].map((userInd) => utils.createActiveSession(userInd)) + ]); }); - const { message } = await res.json(); - expect(message).toEqual('No friend request with that id issued to you'); - expect(res.status()).toEqual(401); - await page.close(); -}); -test("User 4 fails to decline friend request on User 3's behalf", async ({ page, context }) => { - await context.addCookies([ - { - name: 'session', - value: 'user4session', - url: host - } - ]); - const res = await context.request.fetch(host + '/db', { - method: 'post', - headers: { - 'Content-Type': 'application/json' - }, - data: { - type: 'rejectFriendReq', - reqId: 3 - } + test("User 1 fails to accept household invite on User 2's behalf", async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user1session', + url: host + } + ]); + const res = await context.request.fetch(host + '/db', { + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data: { + type: 'acceptHouseholdInvite', + id: 2 + } + }); + const { message } = await res.json(); + expect(message).toEqual("You can't accept a household invite that wasn't issued to you"); + expect(res.status()).toEqual(401); + await page.close(); }); - const { message } = await res.json(); - expect(message).toEqual("Can't delete friend request not issued to you"); - expect(res.status()).toEqual(401); - await page.close(); -}); -test("User 4 fails to delete friend on User 3's behalf", async ({ page, context }) => { - await context.addCookies([ - { - name: 'session', - value: 'user4session', - url: host - } - ]); - const res = await context.request.fetch(host + '/db', { - method: 'post', - headers: { - 'Content-Type': 'application/json' - }, - data: { - type: 'deleteFriend', - connectionId: 3 - } + test("User 1 fails to decline household invite on User 2's behalf", async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user1session', + url: host + } + ]); + const res = await context.request.fetch(host + '/db', { + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data: { + type: 'rejectHouseholdInvite', + id: 2 + } + }); + const { message } = await res.json(); + expect(message).toEqual("You can't delete a household invite that wasn't issued to you"); + expect(res.status()).toEqual(401); + await page.close(); }); - const { message } = await res.json(); - expect(message).toEqual("You can't delete a household connection that you're not a part of"); - expect(res.status()).toEqual(401); - await page.close(); }); -test("User 4 fails to accept household invite on User 2's behalf", async ({ page, context }) => { - await context.addCookies([ - { - name: 'session', - value: 'user4session', - url: host - } - ]); - const res = await context.request.fetch(host + '/db', { - method: 'post', - headers: { - 'Content-Type': 'application/json' - }, - data: { - type: 'acceptHouseholdInvite', - id: 2 - } +test.describe.only('Friend Requests', () => { + test.beforeAll(async () => { + const utils = new SeedUtils(new Date(), prisma); + + await Promise.all([ + utils.deleteUserAndHousehold('+12015550003'), + utils.deleteUserAndHousehold('+12015550004') + ]); + + await Promise.all([ + ...[3, 4].map((userInd) => utils.createUserWithEmptyHousehold(userInd)), + ...[4].map((userInd) => utils.createActiveSession(userInd)) + ]); + + await Promise.all([utils.createFriendRequest(4, 3)]); }); - const { message } = await res.json(); - expect(message).toEqual("You can't accept a household invite that wasn't issued to you"); - expect(res.status()).toEqual(401); - await page.close(); -}); -test("User 4 fails to decline household invite on User 2's behalf", async ({ page, context }) => { - await context.addCookies([ - { - name: 'session', - value: 'user4session', - url: host - } - ]); - const res = await context.request.fetch(host + '/db', { - method: 'post', - headers: { - 'Content-Type': 'application/json' - }, - data: { - type: 'rejectHouseholdInvite', - id: 2 - } + test("User 4 fails to accept friend request on User 3's behalf", async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user4session', + url: host + } + ]); + const res = await context.request.fetch(host + '/db', { + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data: { + type: 'acceptFriendReq', + friendReqId: 3 + } + }); + const { message } = await res.json(); + expect(message).toEqual('No friend request with that id issued to you'); + expect(res.status()).toEqual(401); + await page.close(); }); - const { message } = await res.json(); - expect(message).toEqual("You can't delete a household invite that wasn't issued to you"); - expect(res.status()).toEqual(401); - await page.close(); -}); + test("User 4 fails to decline friend request on User 3's behalf", async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user4session', + url: host + } + ]); + const res = await context.request.fetch(host + '/db', { + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data: { + type: 'rejectFriendReq', + reqId: 3 + } + }); + const { message } = await res.json(); + expect(message).toEqual("Can't delete friend request not issued to you"); + expect(res.status()).toEqual(401); + await page.close(); + }); + + test("User 4 fails to delete friend on User 3's behalf", async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user4session', + url: host + } + ]); + const res = await context.request.fetch(host + '/db', { + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data: { + type: 'deleteFriend', + connectionId: 3 + } + }); + const { message } = await res.json(); + expect(message).toEqual("You can't delete a household connection that you're not a part of"); + expect(res.status()).toEqual(401); + await page.close(); + }); +}); // TODO: Can't create household for someone who's already in a household diff --git a/tests/household.spec.ts b/tests/household.spec.ts new file mode 100644 index 0000000..14a5f68 --- /dev/null +++ b/tests/household.spec.ts @@ -0,0 +1,30 @@ +import { expect, test } from '@playwright/test'; +import { run } from '../prisma/seed'; + +const host = 'http://localhost:5173'; + +test.beforeAll(async () => { + await run(); +}); + +test('User can create new kid', async ({ page, context }) => { + await context.addCookies([ + { + name: 'session', + value: 'user7session', + url: host + } + ]); + await page.goto(host); + await page.waitForURL(`${host}/household`); + await page.waitForTimeout(2000) + expect(await page.locator('.kid-card').count()).toBe(0) + + await page.locator('input[name="first-name"]').fill('FIRST_NAME') + await page.locator('input[name="last-name"]').fill('LAST_NAME') + await page.locator('select[name="pronouns"]').selectOption('SHE_HER_HERS'); + + await page.getByText('Save Child').click(); + await page.locator('.kid-card').first().waitFor(); + expect(await page.locator('.kid-card').count()).toBe(1) +});