From 4faad64978a2b4782fcb84df28f3fb2fd46d6f64 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:28:24 -0500 Subject: [PATCH] test: Seed GCal test credentials (#12596) * Seed GCal test credentials * Set yml .env to secrets * Switch to vars * Add error messages * Set error message * Error messages * Change .env to secrets * Run db-seed even with cache * Add with DATABASE_URL * Set DB URL * Set DB URL * Inputs DB URL * Move database URL to with block * Create env under yarn db-studio * Fix typo * WIP * WIP * WIP * WIP * WIP * Add credential console log * Hit cache * Add logs * Remove echo * Run on ubuntu latest * Don't cache db * Uncache * WIP * WIP * Change back to buildjet * Seed GCal keys in test * Test uses GCal keys * Parse keys * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * Clean up * Type fix * Clean up * Clean up --- .env.example | 2 + .github/actions/cache-db/action.yml | 7 +- .github/workflows/e2e-app-store.yml | 10 ++ .github/workflows/production-build.yml | 4 + .../tests/google-calendar.e2e.ts | 96 +++++++++++-------- .../googlecalendar/tests/testUtils.ts | 12 ++- .../features/bookings/lib/handleNewBooking.ts | 2 +- packages/prisma/seed-utils.ts | 21 ++++ packages/prisma/seed.ts | 39 +++++--- turbo.json | 2 + 10 files changed, 135 insertions(+), 60 deletions(-) diff --git a/.env.example b/.env.example index 204be5fe9d..799046ac34 100644 --- a/.env.example +++ b/.env.example @@ -272,6 +272,8 @@ E2E_TEST_APPLE_CALENDAR_PASSWORD="" E2E_TEST_CALCOM_QA_EMAIL="qa@example.com" # Replace with your own password E2E_TEST_CALCOM_QA_PASSWORD="password" +E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS= +E2E_TEST_CALCOM_GCAL_KEYS= # - APP CREDENTIAL SYNC *********************************************************************************** # Used for self-hosters that are implementing Cal.com into their applications that already have certain integrations diff --git a/.github/actions/cache-db/action.yml b/.github/actions/cache-db/action.yml index f69fd9513a..9d2c1ce28d 100644 --- a/.github/actions/cache-db/action.yml +++ b/.github/actions/cache-db/action.yml @@ -17,10 +17,15 @@ runs: cache-name: cache-db key-1: ${{ hashFiles('packages/prisma/schema.prisma', 'packages/prisma/migrations/**/**.sql', 'packages/prisma/*.ts') }} key-2: ${{ github.event.pull_request.number || github.ref }} + DATABASE_URL: ${{ inputs.DATABASE_URL }} + E2E_TEST_CALCOM_QA_EMAIL: ${{ inputs.E2E_TEST_CALCOM_QA_EMAIL }} + E2E_TEST_CALCOM_QA_PASSWORD: ${{ inputs.E2E_TEST_CALCOM_QA_PASSWORD }} + E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ inputs.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }} with: path: ${{ inputs.path }} key: ${{ runner.os }}-${{ env.cache-name }}-${{ inputs.path }}-${{ env.key-1 }}-${{ env.key-2 }} - - run: yarn db-seed + DATABASE_URL: ${{ inputs.DATABASE_URL }} + - run: echo ${{ env.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }} && yarn db-seed if: steps.cache-db.outputs.cache-hit != 'true' shell: bash - name: Postgres Dump Backup diff --git a/.github/workflows/e2e-app-store.yml b/.github/workflows/e2e-app-store.yml index 471b0357e3..dcba9d40c9 100644 --- a/.github/workflows/e2e-app-store.yml +++ b/.github/workflows/e2e-app-store.yml @@ -33,6 +33,12 @@ jobs: - uses: ./.github/actions/yarn-install - uses: ./.github/actions/yarn-playwright-install - uses: ./.github/actions/cache-db + env: + DATABASE_URL: ${{ secrets.CI_DATABASE_URL }} + E2E_TEST_CALCOM_QA_EMAIL: ${{ secrets.E2E_TEST_CALCOM_QA_EMAIL }} + E2E_TEST_CALCOM_QA_PASSWORD: ${{ secrets.E2E_TEST_CALCOM_QA_PASSWORD }} + E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ secrets.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }} + E2E_TEST_CALCOM_GCAL_KEYS: ${{ secrets.E2E_TEST_CALCOM_GCAL_KEYS }} - uses: ./.github/actions/cache-build - name: Run Tests run: yarn e2e:app-store --shard=${{ matrix.shard }}/${{ strategy.job-total }} @@ -43,6 +49,10 @@ jobs: DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }} E2E_TEST_APPLE_CALENDAR_EMAIL: ${{ secrets.E2E_TEST_APPLE_CALENDAR_EMAIL }} E2E_TEST_APPLE_CALENDAR_PASSWORD: ${{ secrets.E2E_TEST_APPLE_CALENDAR_PASSWORD }} + E2E_TEST_CALCOM_QA_EMAIL: ${{ secrets.E2E_TEST_CALCOM_QA_EMAIL }} + E2E_TEST_CALCOM_QA_PASSWORD: ${{ secrets.E2E_TEST_CALCOM_QA_PASSWORD }} + E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ secrets.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }} + E2E_TEST_CALCOM_GCAL_KEYS: ${{ secrets.E2E_TEST_CALCOM_GCAL_KEYS }} E2E_TEST_MAILHOG_ENABLED: ${{ vars.E2E_TEST_MAILHOG_ENABLED }} GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }} GOOGLE_LOGIN_ENABLED: ${{ vars.CI_GOOGLE_LOGIN_ENABLED }} diff --git a/.github/workflows/production-build.yml b/.github/workflows/production-build.yml index 3ea85d6141..4cbddfc0a5 100644 --- a/.github/workflows/production-build.yml +++ b/.github/workflows/production-build.yml @@ -9,6 +9,10 @@ env: DATABASE_URL: ${{ secrets.CI_DATABASE_URL }} E2E_TEST_APPLE_CALENDAR_EMAIL: ${{ secrets.E2E_TEST_APPLE_CALENDAR_EMAIL }} E2E_TEST_APPLE_CALENDAR_PASSWORD: ${{ secrets.E2E_TEST_APPLE_CALENDAR_PASSWORD }} + E2E_TEST_CALCOM_QA_EMAIL: ${{ secrets.E2E_TEST_CALCOM_QA_EMAIL }} + E2E_TEST_CALCOM_QA_PASSWORD: ${{ secrets.E2E_TEST_CALCOM_QA_PASSWORD }} + E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS: ${{ secrets.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS }} + E2E_TEST_CALCOM_GCAL_KEYS: ${{ secrets.E2E_TEST_CALCOM_GCAL_KEYS }} GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }} GOOGLE_LOGIN_ENABLED: ${{ vars.CI_GOOGLE_LOGIN_ENABLED }} NEXTAUTH_SECRET: ${{ secrets.CI_NEXTAUTH_SECRET }} diff --git a/packages/app-store/googlecalendar/tests/google-calendar.e2e.ts b/packages/app-store/googlecalendar/tests/google-calendar.e2e.ts index 226b7a61cd..788cb6ede6 100644 --- a/packages/app-store/googlecalendar/tests/google-calendar.e2e.ts +++ b/packages/app-store/googlecalendar/tests/google-calendar.e2e.ts @@ -4,7 +4,7 @@ import type { Page } from "@playwright/test"; import dayjs from "@calcom/dayjs"; import { APP_CREDENTIAL_SHARING_ENABLED } from "@calcom/lib/constants"; import prisma from "@calcom/prisma"; -import type { Prisma } from "@calcom/prisma/client"; +import type { CredentialPayload } from "@calcom/types/Credential"; import { test } from "@calcom/web/playwright/lib/fixtures"; import { selectSecondAvailableTimeSlotNextMonth } from "@calcom/web/playwright/lib/testUtils"; @@ -15,12 +15,30 @@ import { createBookingAndFetchGCalEvent, deleteBookingAndEvent, assertValueExist test.describe("Google Calendar", async () => { test.describe("Test using the primary calendar", async () => { let qaUsername: string; - let qaGCalCredential: Prisma.CredentialGetPayload<{ select: { id: true } }>; + let qaGCalCredential: CredentialPayload; test.beforeAll(async () => { let runIntegrationTest = false; + const errorMessage = "Could not run test"; test.skip(!!APP_CREDENTIAL_SHARING_ENABLED, "Credential sharing enabled"); + if (process.env.E2E_TEST_CALCOM_GCAL_KEYS) { + const gCalKeys = JSON.parse(process.env.E2E_TEST_CALCOM_GCAL_KEYS); + await prisma.app.update({ + where: { + slug: "google-calendar", + }, + data: { + keys: gCalKeys, + }, + }); + } else { + test.skip(!process.env.E2E_TEST_CALCOM_GCAL_KEYS, "GCal keys not found"); + } + + test.skip(!process.env.E2E_TEST_CALCOM_QA_EMAIL, "QA email not found"); + test.skip(!process.env.E2E_TEST_CALCOM_QA_PASSWORD, "QA password not found"); + if (process.env.E2E_TEST_CALCOM_QA_EMAIL && process.env.E2E_TEST_CALCOM_QA_PASSWORD) { qaGCalCredential = await prisma.credential.findFirstOrThrow({ where: { @@ -29,63 +47,59 @@ test.describe("Google Calendar", async () => { }, type: metadata.type, }, - select: { - id: true, + include: { + user: { + select: { + email: true, + }, + }, }, }); + test.skip(!qaGCalCredential, "Google QA credential not found"); const qaUserQuery = await prisma.user.findFirstOrThrow({ where: { email: process.env.E2E_TEST_CALCOM_QA_EMAIL, }, select: { + id: true, username: true, }, }); + test.skip(!qaUserQuery, "QA user not found"); + assertValueExists(qaUserQuery.username, "qaUsername"); qaUsername = qaUserQuery.username; + test.skip(!qaUsername, "QA username not found"); + + const googleCalendarService = new GoogleCalendarService(qaGCalCredential); + + const calendars = await googleCalendarService.listCalendars(); + + const primaryCalendarName = calendars.find((calendar) => calendar.primary)?.name; + assertValueExists(primaryCalendarName, "primaryCalendarName"); + + await prisma.destinationCalendar.upsert({ + where: { + userId: qaUserQuery.id, + externalId: primaryCalendarName, + eventTypeId: undefined, + }, + update: {}, + create: { + integration: "google_calendar", + userId: qaUserQuery.id, + externalId: primaryCalendarName, + credentialId: qaGCalCredential.id, + }, + }); + if (qaGCalCredential && qaUsername) runIntegrationTest = true; } - test.skip(!runIntegrationTest, "QA user not found"); - }); - - test.beforeEach(async ({ page, users }) => { - assertValueExists(process.env.E2E_TEST_CALCOM_QA_EMAIL, "qaEmail"); - - const qaUserStore = await users.set(process.env.E2E_TEST_CALCOM_QA_EMAIL); - - await qaUserStore.apiLogin(process.env.E2E_TEST_CALCOM_QA_PASSWORD); - - // Need to refresh keys from DB - const refreshedCredential = await prisma.credential.findFirst({ - where: { - id: qaGCalCredential?.id, - }, - include: { - user: { - select: { - email: true, - }, - }, - }, - }); - assertValueExists(refreshedCredential, "refreshedCredential"); - - const googleCalendarService = new GoogleCalendarService(refreshedCredential); - - const calendars = await googleCalendarService.listCalendars(); - - const primaryCalendarName = calendars.find((calendar) => calendar.primary)?.name; - assertValueExists(primaryCalendarName, "primaryCalendarName"); - - await page.goto("/apps/installed/calendar"); - - await page.waitForSelector('[title*="Create events on"]'); - await page.locator('[title*="Create events on"]').locator("svg").click(); - await page.locator("#react-select-2-option-0-0").getByText(primaryCalendarName).click(); + test.skip(!runIntegrationTest, errorMessage); }); test("On new booking, event should be created on GCal", async ({ page }) => { diff --git a/packages/app-store/googlecalendar/tests/testUtils.ts b/packages/app-store/googlecalendar/tests/testUtils.ts index 5d4920d2b1..c7960fd3bd 100644 --- a/packages/app-store/googlecalendar/tests/testUtils.ts +++ b/packages/app-store/googlecalendar/tests/testUtils.ts @@ -3,7 +3,7 @@ import { expect } from "@playwright/test"; import prisma from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; -import { bookFirstEvent } from "@calcom/web/playwright/lib/testUtils"; +import { bookTimeSlot, selectSecondAvailableTimeSlotNextMonth } from "@calcom/web/playwright/lib/testUtils"; import metadata from "../_metadata"; import GoogleCalendarService from "../lib/CalendarService"; @@ -20,8 +20,13 @@ export const createBookingAndFetchGCalEvent = async ( qaGCalCredential: Prisma.CredentialGetPayload<{ select: { id: true } }> | null, qaUsername: string ) => { - await page.goto(`/${qaUsername}`); - await bookFirstEvent(page); + await page.goto(`/${qaUsername}/15min`); + await selectSecondAvailableTimeSlotNextMonth(page); + await bookTimeSlot(page); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + await page.waitForNavigation({ state: "networkidle" }); + await page.locator("[data-testid=success-page]"); const bookingUrl = await page.url(); const bookingUid = bookingUrl.match(/booking\/([^\/?]+)/); @@ -64,6 +69,7 @@ export const createBookingAndFetchGCalEvent = async ( }), ]); assertValueExists(gCalReference, "gCalReference"); + assertValueExists(booking, "booking"); // Need to refresh keys from DB diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index c7d341e883..2ec81f8a5c 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -415,7 +415,7 @@ const loadUsers = async (eventType: NewBookingEventType, dynamicUserList: string } }; -async function ensureAvailableUsers( +export async function ensureAvailableUsers( eventType: Awaited> & { users: IsFixedAwareUser[]; }, diff --git a/packages/prisma/seed-utils.ts b/packages/prisma/seed-utils.ts index fbcb07c3a8..7a69530ac1 100644 --- a/packages/prisma/seed-utils.ts +++ b/packages/prisma/seed-utils.ts @@ -10,6 +10,7 @@ import prisma from "."; export async function createUserAndEventType({ user, eventTypes = [], + credentials, }: { user: { email: string; @@ -27,6 +28,11 @@ export async function createUserAndEventType({ _numBookings?: number; } >; + credentials?: ({ + type: string; + key: Prisma.JsonObject; + appId: string; + } | null)[]; }) { const userData = { ...user, @@ -144,5 +150,20 @@ export async function createUserAndEventType({ } } console.log("👤 User with it's event-types and bookings created", theUser.email); + + if (credentials) { + for (const credential of credentials) { + if (credential) { + await prisma.credential.create({ + data: { + ...credential, + userId: theUser.id, + }, + }); + + console.log(`🔑 ${credential.type} credentials created for ${theUser.email}`); + } + } + } return theUser; } diff --git a/packages/prisma/seed.ts b/packages/prisma/seed.ts index 78c6861372..e311117ed8 100644 --- a/packages/prisma/seed.ts +++ b/packages/prisma/seed.ts @@ -455,21 +455,32 @@ async function main() { }, }); - await createUserAndEventType({ - user: { - email: process.env.E2E_TEST_CALCOM_QA_EMAIL || "qa@example.com", - password: process.env.E2E_TEST_CALCOM_QA_PASSWORD || "qa", - username: "qa", - name: "QA Example", - }, - eventTypes: [ - { - title: "15min", - slug: "15min", - length: 15, + if (!!(process.env.E2E_TEST_CALCOM_QA_EMAIL && process.env.E2E_TEST_CALCOM_QA_PASSWORD)) { + await createUserAndEventType({ + user: { + email: process.env.E2E_TEST_CALCOM_QA_EMAIL || "qa@example.com", + password: process.env.E2E_TEST_CALCOM_QA_PASSWORD || "qa", + username: "qa", + name: "QA Example", }, - ], - }); + eventTypes: [ + { + title: "15min", + slug: "15min", + length: 15, + }, + ], + credentials: [ + !!process.env.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS + ? { + type: "google_calendar", + key: JSON.parse(process.env.E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS) as Prisma.JsonObject, + appId: "google-calendar", + } + : null, + ], + }); + } await createTeamAndAddUsers( { diff --git a/turbo.json b/turbo.json index 250cca10cf..0443281b82 100644 --- a/turbo.json +++ b/turbo.json @@ -239,6 +239,8 @@ "E2E_TEST_APPLE_CALENDAR_PASSWORD", "E2E_TEST_CALCOM_QA_EMAIL", "E2E_TEST_CALCOM_QA_PASSWORD", + "E2E_TEST_CALCOM_QA_GCAL_CREDENTIALS", + "E2E_TEST_CALCOM_GCAL_KEYS", "E2E_TEST_MAILHOG_ENABLED", "E2E_TEST_OIDC_CLIENT_ID", "E2E_TEST_OIDC_CLIENT_SECRET",