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
This commit is contained in:
Joe Au-Yeung 2023-12-20 14:28:24 -05:00 committed by GitHub
parent b384e4a9d8
commit 4faad64978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 135 additions and 60 deletions

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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 }) => {

View File

@ -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

View File

@ -415,7 +415,7 @@ const loadUsers = async (eventType: NewBookingEventType, dynamicUserList: string
}
};
async function ensureAvailableUsers(
export async function ensureAvailableUsers(
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>> & {
users: IsFixedAwareUser[];
},

View File

@ -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;
}

View File

@ -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(
{

View File

@ -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",