Upgrades yarn v1 to v3. Improves CI times by 2x (#7738)
* Create env file workflow * Add env-cache * Fix env setter * Fix * Another fix * Fix * Fix * Fixes * FFS * Fix * Fix * Fix * Fix * Fix * Cache fixes * Fixes * Adds skipping steps * db-cache fixes * Test * Cache fixes * e2e * Possible caching conflicts * Running out of ideas * Caching is hard * One more time * cache-build not skipping * Fingers crossed * a * Test * Pls * Please * LFG * Build fix * fix * Whitespace!! * Zomars/cal 884 paid events not sending the link (#7318) * WIP * Sends correct emails for paid bookings * Update PaymentService.ts * Update webhook.ts * Update webhook.ts * Update settings back button redirect link (#7403) * fix(schedule): close on click #7143 * fix(EventSetupTab): validLocations length will always match validLocations length #7138 * fix(SettingsLayout): go back to right route #7379 * feat: get country code from ip geolocation (#6880) * feat: get coutnry code from ip geolocation Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * fix: create new api route for fetching code Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * chore: replace city with country Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * refactor: create hook for country Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> --------- Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * Team Workflows (#7038) Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> * Add destination calendar name to DestinationCalendarSelector (#6701) * Add destination calendar name * Type fix * Search through calendars only for destination calendar credential * Refactor get connected calendars * Clean up --------- Co-authored-by: zomars <zomars@me.com> * Update viewer.tsx (#7428) * Fix - add team members to emails (#7207) * On booking add team members & translation * Add team members to round robin create * Only update calendars on reschedule if there is a calendar reference * Send email on reschedules * Send team email on cancelled event * Add team members to calendar event description * Clean up * Convert other emails to organizer & teams * Type check fixes * More type fixes * Change organizer scheduled input to an object * early return updateCalendarEvent * Introduce team member type * Fix type errors * Put team members before attendees * Remove lodash cloneDeep * Update packages/core/EventManager.ts Co-authored-by: Omar López <zomars@me.com> * Remove booking select object * Revert "Remove booking select object" This reverts commitpull/7756/head^29f121ff4eb
. * Refactor email manager (#7270) Co-authored-by: zomars <zomars@me.com> * Type change * Remove conditional check for updateAllCalendarEvents --------- Co-authored-by: zomars <zomars@me.com> * Typefix * Updates webhook response * Update pr.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Update action.yml * Is this redundant? * Removed setup * Update action.yml * Update action.yml * Consolitades setup step * Revert "Consolitades setup step" This reverts commit5e8d1983cc
. * Fix? * One more time * Revert "One more time" This reverts commitfd8b559a13
. * Benchmarking buildjet * Update action.yml * Re-introduce setup * Adds embeds to missing pro cache * Lint fixes * Adds prettier ignore * Upgrades to yarn 3 * Updates lockfile * Reverts CI to ubuntu * Testing new yarn install * We cannot use immutable due to our private submodules * Adds CI skip * Fixes * Adds plugin * Forces local embed package * Moves eslint to root * Update yarn.lock * Playwright fixes * Embed test fixes * Splits embed react tests * Splits embed react tests * Removes install step to benchmark * Update playwright.config.ts * One playwright config for all * More test fixes * Update basic.e2e.ts * Added typescript as a global monorepo dev * Update to v18 * Update yarn.lock * Update env-create-file.yml * Update .github/workflows/pr.yml --------- Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> Co-authored-by: Esaú Morais <55207584+esau-morais@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
parent
f20d78bec1
commit
54cefcb16e
|
@ -0,0 +1,6 @@
|
||||||
|
node_modules
|
||||||
|
**/**/node_modules
|
||||||
|
**/**/.next
|
||||||
|
**/**/public
|
||||||
|
packages/prisma/zod
|
||||||
|
apps/web/public/embed
|
|
@ -20,6 +20,7 @@ runs:
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
${{ github.workspace }}/apps/web/.next
|
${{ github.workspace }}/apps/web/.next
|
||||||
|
${{ github.workspace }}/apps/web/public/embed
|
||||||
**/.turbo/**
|
**/.turbo/**
|
||||||
**/dist/**
|
**/dist/**
|
||||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
|
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
name: Yarn install
|
########################################################################################
|
||||||
description: "Install all NPM dependencies, caches them and restores if necessary"
|
# "yarn install" composite action for yarn 2/3/4+ and "nodeLinker: node-modules" #
|
||||||
|
#--------------------------------------------------------------------------------------#
|
||||||
|
# Cache: #
|
||||||
|
# - Downloaded zip archive (multi-arch, preserved across yarn.lock changes) #
|
||||||
|
# - Yarn install state (discarded on yarn.lock changes) #
|
||||||
|
# References: #
|
||||||
|
# - bench: https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b #
|
||||||
|
# - vs @setup/node: https://github.com/actions/setup-node/issues/325 #
|
||||||
|
########################################################################################
|
||||||
|
|
||||||
|
name: "Yarn install"
|
||||||
|
description: "Run yarn install with node_modules linker and cache enabled"
|
||||||
inputs:
|
inputs:
|
||||||
node_version:
|
node_version:
|
||||||
required: false
|
required: false
|
||||||
default: v18.x
|
default: v18.x
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
|
@ -11,9 +23,40 @@ runs:
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ inputs.node_version }}
|
node-version: ${{ inputs.node_version }}
|
||||||
cache: "yarn"
|
- name: Expose yarn config as "$GITHUB_OUTPUT"
|
||||||
- name: Yarn install
|
id: yarn-config
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
yarn install --prefer-offline --frozen-lockfile
|
echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325
|
||||||
|
# Yarn cache is also reusable between arch and os.
|
||||||
|
- name: Restore yarn cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
id: yarn-download-cache
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
|
||||||
|
key: yarn-download-cache-${{ hashFiles('yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
yarn-download-cache-
|
||||||
|
|
||||||
|
# Invalidated on yarn.lock changes
|
||||||
|
- name: Restore yarn install state
|
||||||
|
id: yarn-install-state-cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: .yarn/ci-cache/
|
||||||
|
key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
yarn install --inline-builds
|
||||||
yarn prisma generate
|
yarn prisma generate
|
||||||
|
env:
|
||||||
|
# CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action.
|
||||||
|
YARN_ENABLE_IMMUTABLE_INSTALLS: "false" # So it doesn't try to remove our private submodule deps
|
||||||
|
YARN_ENABLE_GLOBAL_CACHE: "false" # Use local cache folder to keep downloaded archives
|
||||||
|
YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change
|
||||||
|
# Other environment variables
|
||||||
|
HUSKY: "0" # By default do not run HUSKY install
|
||||||
|
|
|
@ -18,5 +18,3 @@ jobs:
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
include-only-assigned: true
|
include-only-assigned: true
|
||||||
days-before-close: -1
|
days-before-close: -1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
name: E2E Embed tests and booking flow(for non-embed as well)
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
e2e-embed:
|
||||||
|
timeout-minutes: 20
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:12.1
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: calendso
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
|
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
|
||||||
|
- uses: ./.github/actions/yarn-install
|
||||||
|
- uses: ./.github/actions/yarn-playwright-install
|
||||||
|
- uses: ./.github/actions/env-read-file
|
||||||
|
- uses: ./.github/actions/cache-db
|
||||||
|
- uses: ./.github/actions/cache-build
|
||||||
|
- name: Run Tests
|
||||||
|
run: yarn test-e2e:embed-react
|
||||||
|
env:
|
||||||
|
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||||
|
- name: Upload Test Results
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: test-results
|
||||||
|
path: test-results
|
|
@ -25,19 +25,12 @@ jobs:
|
||||||
- uses: ./.github/actions/cache-db
|
- uses: ./.github/actions/cache-db
|
||||||
- uses: ./.github/actions/cache-build
|
- uses: ./.github/actions/cache-build
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: yarn turbo run embed-tests-update-snapshots:ci --scope=@calcom/embed-react --concurrency=1
|
run: yarn test-e2e:embed
|
||||||
env:
|
env:
|
||||||
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||||
- name: Upload embed-core results
|
- name: Upload Test Results
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: test-results-embed-core
|
name: test-results
|
||||||
path: packages/embeds/embed-core/playwright/results
|
path: test-results
|
||||||
|
|
||||||
- name: Upload embed-react results
|
|
||||||
if: ${{ always() }}
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: test-results-embed-react
|
|
||||||
path: packages/embeds/embed-react/playwright/results
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ env:
|
||||||
INPUT_ENV_PAYMENT_FEE_FIXED: 10
|
INPUT_ENV_PAYMENT_FEE_FIXED: 10
|
||||||
INPUT_ENV_SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
INPUT_ENV_SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||||
INPUT_ENV_SAML_ADMINS: pro@example.com
|
INPUT_ENV_SAML_ADMINS: pro@example.com
|
||||||
INPUT_ENV_NEXTAUTH_URL: http://localhost:3000/api/auth
|
INPUT_ENV_NEXTAUTH_URL: http://127.0.0.1:3000/api/auth
|
||||||
INPUT_ENV_NEXT_PUBLIC_IS_E2E: 1
|
INPUT_ENV_NEXT_PUBLIC_IS_E2E: 1
|
||||||
# INPUT_ENV_EMAIL_FROM: e2e@cal.com
|
# INPUT_ENV_EMAIL_FROM: e2e@cal.com
|
||||||
# INPUT_ENV_EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
# INPUT_ENV_EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
||||||
|
|
|
@ -21,6 +21,7 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
app-store: ${{ steps.filter.outputs.app-store }}
|
app-store: ${{ steps.filter.outputs.app-store }}
|
||||||
embed: ${{ steps.filter.outputs.embed }}
|
embed: ${{ steps.filter.outputs.embed }}
|
||||||
|
embed-react: ${{ steps.filter.outputs.embed-react }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/dangerous-git-checkout
|
- uses: ./.github/actions/dangerous-git-checkout
|
||||||
|
@ -34,6 +35,9 @@ jobs:
|
||||||
embed:
|
embed:
|
||||||
- 'apps/web/**'
|
- 'apps/web/**'
|
||||||
- 'packages/embeds/**'
|
- 'packages/embeds/**'
|
||||||
|
embed-react:
|
||||||
|
- 'apps/web/**'
|
||||||
|
- 'packages/embeds/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
name: Create env file
|
name: Create env file
|
||||||
|
@ -81,6 +85,13 @@ jobs:
|
||||||
uses: ./.github/workflows/e2e-embed.yml
|
uses: ./.github/workflows/e2e-embed.yml
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
e2e-embed-react:
|
||||||
|
name: E2E React embeds tests
|
||||||
|
if: ${{ needs.changes.outputs.embed-react == 'true' }}
|
||||||
|
needs: [changes, lint, build]
|
||||||
|
uses: ./.github/workflows/e2e-embed-react.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
analyze:
|
analyze:
|
||||||
needs: build
|
needs: build
|
||||||
uses: ./.github/workflows/nextjs-bundle-analysis.yml
|
uses: ./.github/workflows/nextjs-bundle-analysis.yml
|
||||||
|
|
|
@ -87,3 +87,12 @@ apps/api
|
||||||
apps/website
|
apps/website
|
||||||
apps/console
|
apps/console
|
||||||
apps/auth
|
apps/auth
|
||||||
|
|
||||||
|
# Yarn Modern
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|
|
@ -14,3 +14,4 @@ public
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.eslintignore
|
.eslintignore
|
||||||
packages/prisma/zod
|
packages/prisma/zod
|
||||||
|
apps/web/public/embed
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,7 @@
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-3.4.1.cjs
|
|
@ -24,7 +24,6 @@
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/config": "*",
|
"@calcom/config": "*"
|
||||||
"eslint": "^8.34.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
prisma/zod
|
public/embed
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
public/embed
|
|
@ -28,9 +28,9 @@
|
||||||
"@calcom/app-store-cli": "*",
|
"@calcom/app-store-cli": "*",
|
||||||
"@calcom/core": "*",
|
"@calcom/core": "*",
|
||||||
"@calcom/dayjs": "*",
|
"@calcom/dayjs": "*",
|
||||||
"@calcom/embed-core": "*",
|
"@calcom/embed-core": "workspace:*",
|
||||||
"@calcom/embed-react": "*",
|
"@calcom/embed-react": "workspace:*",
|
||||||
"@calcom/embed-snippet": "*",
|
"@calcom/embed-snippet": "workspace:*",
|
||||||
"@calcom/features": "*",
|
"@calcom/features": "*",
|
||||||
"@calcom/lib": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
"@calcom/config": "*",
|
"@calcom/config": "*",
|
||||||
"@calcom/types": "*",
|
"@calcom/types": "*",
|
||||||
"@microsoft/microsoft-graph-types-beta": "0.15.0-preview",
|
"@microsoft/microsoft-graph-types-beta": "0.15.0-preview",
|
||||||
"@playwright/test": "^1.25.0",
|
"@playwright/test": "^1.31.2",
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@types/accept-language-parser": "1.5.2",
|
"@types/accept-language-parser": "1.5.2",
|
||||||
"@types/async": "^3.2.15",
|
"@types/async": "^3.2.15",
|
||||||
|
@ -162,7 +162,6 @@
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"detect-port": "^1.3.0",
|
"detect-port": "^1.3.0",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"eslint": "^8.34.0",
|
|
||||||
"mockdate": "^3.0.5",
|
"mockdate": "^3.0.5",
|
||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"msw": "^0.42.3",
|
"msw": "^0.42.3",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { test as base } from "@playwright/test";
|
||||||
|
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
|
||||||
|
import type { ExpectedUrlDetails } from "../../../../playwright.config";
|
||||||
import { createBookingsFixture } from "../fixtures/bookings";
|
import { createBookingsFixture } from "../fixtures/bookings";
|
||||||
import { createEmbedsFixture, createGetActionFiredDetails } from "../fixtures/embeds";
|
import { createEmbedsFixture, createGetActionFiredDetails } from "../fixtures/embeds";
|
||||||
import { createPaymentsFixture } from "../fixtures/payments";
|
import { createPaymentsFixture } from "../fixtures/payments";
|
||||||
|
@ -18,6 +19,21 @@ export interface Fixtures {
|
||||||
prisma: typeof prisma;
|
prisma: typeof prisma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
namespace PlaywrightTest {
|
||||||
|
//FIXME: how to restrict it to Frame only
|
||||||
|
interface Matchers<R> {
|
||||||
|
toBeEmbedCalLink(
|
||||||
|
calNamespace: string,
|
||||||
|
// eslint-disable-next-line
|
||||||
|
getActionFiredDetails: (a: { calNamespace: string; actionType: string }) => Promise<any>,
|
||||||
|
expectedUrlDetails?: ExpectedUrlDetails
|
||||||
|
): Promise<R>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://playwright.dev/docs/test-fixtures
|
* @see https://playwright.dev/docs/test-fixtures
|
||||||
*/
|
*/
|
||||||
|
|
11
package.json
11
package.json
|
@ -61,8 +61,12 @@
|
||||||
"tdd": "jest --watch",
|
"tdd": "jest --watch",
|
||||||
"e2e": "NEXT_PUBLIC_IS_E2E=1 yarn playwright test --project=@calcom/web",
|
"e2e": "NEXT_PUBLIC_IS_E2E=1 yarn playwright test --project=@calcom/web",
|
||||||
"e2e:app-store": "QUICK=true yarn playwright test --project=@calcom/app-store",
|
"e2e:app-store": "QUICK=true yarn playwright test --project=@calcom/app-store",
|
||||||
|
"e2e:embed": "QUICK=true yarn playwright test --project=@calcom/embed-core",
|
||||||
|
"e2e:embed-react": "QUICK=true yarn playwright test --project=@calcom/embed-react",
|
||||||
"test-e2e": "yarn db-seed && yarn e2e",
|
"test-e2e": "yarn db-seed && yarn e2e",
|
||||||
"test-e2e:app-store": "yarn db-seed && yarn e2e:app-store",
|
"test-e2e:app-store": "yarn db-seed && yarn e2e:app-store",
|
||||||
|
"test-e2e:embed": "yarn db-seed && yarn e2e:embed",
|
||||||
|
"test-e2e:embed-react": "yarn db-seed && yarn e2e:embed-react",
|
||||||
"test-playwright": "yarn playwright test --config=playwright.config.ts",
|
"test-playwright": "yarn playwright test --config=playwright.config.ts",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"type-check": "turbo run type-check",
|
"type-check": "turbo run type-check",
|
||||||
|
@ -70,6 +74,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@deploysentinel/playwright": "^0.3.3",
|
"@deploysentinel/playwright": "^0.3.3",
|
||||||
|
"@playwright/test": "^1.31.2",
|
||||||
"@snaplet/copycat": "^0.3.0",
|
"@snaplet/copycat": "^0.3.0",
|
||||||
"@types/dompurify": "^2.4.0",
|
"@types/dompurify": "^2.4.0",
|
||||||
"@types/jest": "^28.1.7",
|
"@types/jest": "^28.1.7",
|
||||||
|
@ -82,10 +87,12 @@
|
||||||
"jest-watch-typeahead": "^2.0.0",
|
"jest-watch-typeahead": "^2.0.0",
|
||||||
"lint-staged": "^12.5.0",
|
"lint-staged": "^12.5.0",
|
||||||
"prettier": "^2.8.4",
|
"prettier": "^2.8.4",
|
||||||
"ts-jest": "^28.0.8"
|
"ts-jest": "^28.0.8",
|
||||||
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"city-timezones": "^1.2.1",
|
"city-timezones": "^1.2.1",
|
||||||
|
"eslint": "^8.34.0",
|
||||||
"turbo": "^1.4.3"
|
"turbo": "^1.4.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -115,7 +122,7 @@
|
||||||
"schema": "packages/prisma/schema.prisma",
|
"schema": "packages/prisma/schema.prisma",
|
||||||
"seed": "ts-node --transpile-only ./packages/prisma/seed.ts"
|
"seed": "ts-node --transpile-only ./packages/prisma/seed.ts"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@1.22.17",
|
"packageManager": "yarn@3.4.1",
|
||||||
"syncpack": {
|
"syncpack": {
|
||||||
"filter": "^(?!@calcom).*",
|
"filter": "^(?!@calcom).*",
|
||||||
"semverRange": ""
|
"semverRange": ""
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
"description": "Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.",
|
"description": "Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/prisma": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/lib": "*"
|
"@calcom/prisma": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
"@calcom/lib": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
"@calcom/ui": "*",
|
"@calcom/ui": "*",
|
||||||
"react-hook-form": "^7.43.3",
|
"ews-javascript-api": "^0.11.0",
|
||||||
"ews-javascript-api": "^0.11.0"
|
"react-hook-form": "^7.43.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
"@calcom/lib": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
"@calcom/ui": "*",
|
"@calcom/ui": "*",
|
||||||
"react-hook-form": "^7.43.3",
|
"ews-javascript-api": "^0.11.0",
|
||||||
"ews-javascript-api": "^0.11.0"
|
"react-hook-form": "^7.43.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
"description": "Microsoft Teams is a business communication platform and collaborative workspace included in Microsoft 365. It offers workspace chat and video conferencing, file storage, and application integration. Both web versions and desktop/mobile applications are available. NOTE: MUST HAVE A WORK / SCHOOL ACCOUNT",
|
"description": "Microsoft Teams is a business communication platform and collaborative workspace included in Microsoft 365. It offers workspace chat and video conferencing, file storage, and application integration. Both web versions and desktop/mobile applications are available. NOTE: MUST HAVE A WORK / SCHOOL ACCOUNT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/prisma": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/lib": "*"
|
"@calcom/prisma": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -49,7 +49,7 @@ test.describe("Routing Forms", () => {
|
||||||
|
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
|
||||||
expect(await page.inputValue(`[data-testid="description"]`)).toMatch(description);
|
expect(await page.inputValue(`[data-testid="description"]`)).toBe(description);
|
||||||
expect(await page.locator('[data-testid="field"]').count()).toBe(1);
|
expect(await page.locator('[data-testid="field"]').count()).toBe(1);
|
||||||
|
|
||||||
await expectCurrentFormToHaveFields(page, { 0: field }, types);
|
await expectCurrentFormToHaveFields(page, { 0: field }, types);
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
"description": "Tandem is a new virtual office space that allows teams to effortlessly connect as though they are in a physical office, online. Through co-working rooms, available statuses, live real-time video call, and chat options, you can see who’s around, talk and collaborate in one click. It works cross-platform with both desktop and mobile versions.",
|
"description": "Tandem is a new virtual office space that allows teams to effortlessly connect as though they are in a physical office, online. Through co-working rooms, available statuses, live real-time video call, and chat options, you can see who’s around, talk and collaborate in one click. It works cross-platform with both desktop and mobile versions.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/prisma": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/lib": "*"
|
"@calcom/prisma": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
"description": "Zoom is a secure and reliable video platform that supports all of your online communication needs. It can provide everything from one on one meetings, chat, phone, webinars, and large-scale online events. Available with both desktop, web, and mobile versions.",
|
"description": "Zoom is a secure and reliable video platform that supports all of your online communication needs. It can provide everything from one on one meetings, chat, phone, webinars, and large-scale online events. Available with both desktop, web, and mobile versions.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/prisma": "*",
|
"@calcom/lib": "*",
|
||||||
"@calcom/lib": "*"
|
"@calcom/prisma": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@calcom/types": "*"
|
"@calcom/types": "*"
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/dayjs": "*",
|
"@calcom/dayjs": "*",
|
||||||
"@calcom/lib": "*",
|
"@calcom/lib": "*",
|
||||||
|
|
|
@ -43,8 +43,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.31.2",
|
||||||
"autoprefixer": "^10.4.12",
|
"autoprefixer": "^10.4.12",
|
||||||
"eslint": "^8.34.0",
|
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8.4.18",
|
"postcss": "^8.4.18",
|
||||||
"tailwindcss": "^3.2.1",
|
"tailwindcss": "^3.2.1",
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
async function globalSetup(/* config: FullConfig */) {}
|
|
||||||
|
|
||||||
export default globalSetup;
|
|
|
@ -1,204 +0,0 @@
|
||||||
import type { PlaywrightTestConfig, Frame } from "@playwright/test";
|
|
||||||
import { devices, expect } from "@playwright/test";
|
|
||||||
import * as path from "path";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
require("dotenv").config({ path: "../../../../../.env" });
|
|
||||||
|
|
||||||
const outputDir = path.join("../results");
|
|
||||||
const testDir = path.join("../tests");
|
|
||||||
const quickMode = process.env.QUICK === "true";
|
|
||||||
const CI = process.env.CI;
|
|
||||||
const config: PlaywrightTestConfig = {
|
|
||||||
forbidOnly: !!CI,
|
|
||||||
retries: quickMode && !CI ? 0 : 1,
|
|
||||||
workers: 1,
|
|
||||||
timeout: 60_000,
|
|
||||||
reporter: [
|
|
||||||
[CI ? "github" : "list"],
|
|
||||||
["@deploysentinel/playwright"],
|
|
||||||
[
|
|
||||||
"html",
|
|
||||||
{ outputFolder: path.join(__dirname, "..", "reports", "playwright-html-report"), open: "never" },
|
|
||||||
],
|
|
||||||
["junit", { outputFile: path.join(__dirname, "..", "reports", "results.xml") }],
|
|
||||||
],
|
|
||||||
globalSetup: require.resolve("./globalSetup"),
|
|
||||||
outputDir,
|
|
||||||
expect: {
|
|
||||||
toMatchSnapshot: {
|
|
||||||
// Opacity transitions can cause small differences
|
|
||||||
// Every month the rendered month changes failing the snapshot tests. So, increase the threshold to catch major bugs only.
|
|
||||||
maxDiffPixelRatio: 0.1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
webServer: {
|
|
||||||
// Run servers in parallel as Playwright doesn't support two different webserver commands at the moment See https://github.com/microsoft/playwright/issues/8206
|
|
||||||
command: "yarn run-p 'embed-dev' 'embed-web-start'",
|
|
||||||
port: 3100,
|
|
||||||
timeout: 60_000,
|
|
||||||
reuseExistingServer: !CI,
|
|
||||||
},
|
|
||||||
use: {
|
|
||||||
baseURL: "http://localhost:3100",
|
|
||||||
locale: "en-US",
|
|
||||||
trace: "retain-on-failure",
|
|
||||||
headless: !!CI || !!process.env.PLAYWRIGHT_HEADLESS,
|
|
||||||
},
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: "chromium",
|
|
||||||
testDir,
|
|
||||||
use: { ...devices["Desktop Chrome"] },
|
|
||||||
},
|
|
||||||
quickMode
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
name: "firefox",
|
|
||||||
testDir,
|
|
||||||
use: { ...devices["Desktop Firefox"] },
|
|
||||||
},
|
|
||||||
quickMode
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
name: "webkit",
|
|
||||||
testDir,
|
|
||||||
use: { ...devices["Desktop Safari"] },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
export type ExpectedUrlDetails = {
|
|
||||||
searchParams?: Record<string, string | string[]>;
|
|
||||||
pathname?: string;
|
|
||||||
origin?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
||||||
namespace PlaywrightTest {
|
|
||||||
//FIXME: how to restrict it to Frame only
|
|
||||||
interface Matchers<R> {
|
|
||||||
toBeEmbedCalLink(
|
|
||||||
calNamespace: string,
|
|
||||||
// eslint-disable-next-line
|
|
||||||
getActionFiredDetails: (a: { calNamespace: string; actionType: string }) => Promise<any>,
|
|
||||||
expectedUrlDetails?: ExpectedUrlDetails
|
|
||||||
): Promise<R>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect.extend({
|
|
||||||
async toBeEmbedCalLink(
|
|
||||||
iframe: Frame,
|
|
||||||
calNamespace: string,
|
|
||||||
//TODO: Move it to testUtil, so that it doesn't need to be passed
|
|
||||||
// eslint-disable-next-line
|
|
||||||
getActionFiredDetails: (a: { calNamespace: string; actionType: string }) => Promise<any>,
|
|
||||||
expectedUrlDetails: ExpectedUrlDetails = {}
|
|
||||||
) {
|
|
||||||
if (!iframe || !iframe.url) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Expected to provide an iframe, got ${iframe}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const u = new URL(iframe.url());
|
|
||||||
const frameElement = await iframe.frameElement();
|
|
||||||
|
|
||||||
if (!(await frameElement.isVisible())) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Expected iframe to be visible`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const pathname = u.pathname;
|
|
||||||
const expectedPathname = expectedUrlDetails.pathname + "/embed";
|
|
||||||
if (expectedPathname && expectedPathname !== pathname) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Expected pathname to be ${expectedPathname} but got ${pathname}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const origin = u.origin;
|
|
||||||
const expectedOrigin = expectedUrlDetails.origin;
|
|
||||||
if (expectedOrigin && expectedOrigin !== origin) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Expected origin to be ${expectedOrigin} but got ${origin}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchParams = u.searchParams;
|
|
||||||
const expectedSearchParams = expectedUrlDetails.searchParams || {};
|
|
||||||
for (const [expectedKey, expectedValue] of Object.entries(expectedSearchParams)) {
|
|
||||||
const value = searchParams.get(expectedKey);
|
|
||||||
if (value !== expectedValue) {
|
|
||||||
return {
|
|
||||||
message: () => `${expectedKey} should have value ${expectedValue} but got value ${value}`,
|
|
||||||
pass: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let iframeReadyCheckInterval;
|
|
||||||
const iframeReadyEventDetail = await new Promise(async (resolve) => {
|
|
||||||
iframeReadyCheckInterval = setInterval(async () => {
|
|
||||||
const iframeReadyEventDetail = await getActionFiredDetails({
|
|
||||||
calNamespace,
|
|
||||||
actionType: "linkReady",
|
|
||||||
});
|
|
||||||
if (iframeReadyEventDetail) {
|
|
||||||
resolve(iframeReadyEventDetail);
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
clearInterval(iframeReadyCheckInterval);
|
|
||||||
|
|
||||||
//At this point we know that window.initialBodyVisibility would be set as DOM would already have been ready(because linkReady event can only fire after that)
|
|
||||||
const {
|
|
||||||
visibility: visibilityBefore,
|
|
||||||
background: backgroundBefore,
|
|
||||||
initialValuesSet,
|
|
||||||
} = await iframe.evaluate(() => {
|
|
||||||
return {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
visibility: window.initialBodyVisibility,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
background: window.initialBodyBackground,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
initialValuesSet: window.initialValuesSet,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
expect(initialValuesSet).toBe(true);
|
|
||||||
expect(visibilityBefore).toBe("hidden");
|
|
||||||
expect(backgroundBefore).toBe("transparent");
|
|
||||||
|
|
||||||
const { visibility: visibilityAfter, background: backgroundAfter } = await iframe.evaluate(() => {
|
|
||||||
return {
|
|
||||||
visibility: document.body.style.visibility,
|
|
||||||
background: document.body.style.background,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(visibilityAfter).toBe("visible");
|
|
||||||
expect(backgroundAfter).toBe("transparent");
|
|
||||||
if (!iframeReadyEventDetail) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Iframe not ready to communicate with parent`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
pass: true,
|
|
||||||
message: () => `passed`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export default config;
|
|
|
@ -1,85 +0,0 @@
|
||||||
import { test as base, Page } from "@playwright/test";
|
|
||||||
|
|
||||||
export interface Fixtures {
|
|
||||||
addEmbedListeners: (calNamespace: string) => Promise<void>;
|
|
||||||
getActionFiredDetails: (a: { calNamespace: string; actionType: string }) => Promise<any>;
|
|
||||||
}
|
|
||||||
export const test = base.extend<Fixtures>({
|
|
||||||
addEmbedListeners: async ({ page }: { page: Page }, use) => {
|
|
||||||
await use(async (calNamespace: string) => {
|
|
||||||
await page.addInitScript(
|
|
||||||
({ calNamespace }: { calNamespace: string }) => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
window.eventsFiredStoreForPlaywright = window.eventsFiredStoreForPlaywright || {};
|
|
||||||
document.addEventListener("DOMContentLoaded", function tryAddingListener() {
|
|
||||||
if (parent !== window) {
|
|
||||||
// Firefox seems to execute this snippet for iframe as well. Avoid that. It must be executed only for parent frame.
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
window.initialBodyVisibility = document.body.style.visibility;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
window.initialBodyBackground = document.body.style.background;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
window.initialValuesSet = true;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
let api = window.Cal;
|
|
||||||
|
|
||||||
if (!api) {
|
|
||||||
setTimeout(tryAddingListener, 500);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (calNamespace) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
//@ts-ignore
|
|
||||||
api = window.Cal.ns[calNamespace];
|
|
||||||
}
|
|
||||||
console.log("PlaywrightTest:", "Adding listener for __iframeReady");
|
|
||||||
if (!api) {
|
|
||||||
throw new Error(`namespace "${calNamespace}" not found`);
|
|
||||||
}
|
|
||||||
api("on", {
|
|
||||||
action: "*",
|
|
||||||
callback: (e: any) => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
window.iframeReady = true; // Technically if there are multiple cal embeds, it can be set due to some other iframe. But it works for now. Improve it when it doesn't work
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
const store = window.eventsFiredStoreForPlaywright;
|
|
||||||
const eventStore = (store[`${e.detail.type}-${e.detail.namespace}`] =
|
|
||||||
store[`${e.detail.type}-${e.detail.namespace}`] || []);
|
|
||||||
eventStore.push(e.detail);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{ calNamespace }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getActionFiredDetails: async ({ page }, use) => {
|
|
||||||
await use(async ({ calNamespace, actionType }) => {
|
|
||||||
if (!page.isClosed()) {
|
|
||||||
return await page.evaluate(
|
|
||||||
({ actionType, calNamespace }) => {
|
|
||||||
//@ts-ignore
|
|
||||||
return window.eventsFiredStoreForPlaywright[`${actionType}-${calNamespace}`];
|
|
||||||
},
|
|
||||||
{ actionType, calNamespace }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,8 +1,9 @@
|
||||||
import type { Page } from "@playwright/test";
|
import type { Page } from "@playwright/test";
|
||||||
import { expect } from "@playwright/test";
|
import { expect } from "@playwright/test";
|
||||||
|
|
||||||
import type { Fixtures } from "../fixtures/fixtures";
|
import { test } from "@calcom/web/playwright/lib/fixtures";
|
||||||
import { test } from "../fixtures/fixtures";
|
import type { Fixtures } from "@calcom/web/playwright/lib/fixtures";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
todo,
|
todo,
|
||||||
getEmbedIframe,
|
getEmbedIframe,
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.31.2",
|
||||||
"@types/react": "18.0.26",
|
"@types/react": "18.0.26",
|
||||||
"@types/react-dom": "18.0.9",
|
"@types/react-dom": "18.0.9",
|
||||||
"@vitejs/plugin-react": "1.3.2",
|
"@vitejs/plugin-react": "1.3.2",
|
||||||
|
@ -50,7 +51,7 @@
|
||||||
"vite": "^4.1.2"
|
"vite": "^4.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/embed-core": "*",
|
"@calcom/embed-core": "workspace:*",
|
||||||
"@calcom/embed-snippet": "*"
|
"@calcom/embed-snippet": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { PlaywrightTestConfig, devices } from "@playwright/test";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
//TODO: Move the common config to embed-playwright-config and let core and react use the base. Along with config there would be base fixtures and expect custom matchers as well.
|
|
||||||
import baseConfig from "@calcom/embed-core/playwright/config/playwright.config";
|
|
||||||
|
|
||||||
const testDir = path.join("../tests");
|
|
||||||
|
|
||||||
const projects = baseConfig.projects?.map((project) => {
|
|
||||||
if (!project.name) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...project,
|
|
||||||
testDir,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const config: PlaywrightTestConfig = {
|
|
||||||
...baseConfig,
|
|
||||||
webServer: {
|
|
||||||
command: "yarn run-p 'embed-dev' 'embed-web-start'",
|
|
||||||
port: 3000,
|
|
||||||
timeout: 60_000,
|
|
||||||
reuseExistingServer: !process.env.CI,
|
|
||||||
},
|
|
||||||
use: {
|
|
||||||
...baseConfig.use,
|
|
||||||
baseURL: "http://localhost:3101",
|
|
||||||
},
|
|
||||||
projects,
|
|
||||||
};
|
|
||||||
export default config;
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from "@playwright/test";
|
import { expect } from "@playwright/test";
|
||||||
|
|
||||||
import { test } from "@calcom/embed-core/playwright/fixtures/fixtures";
|
|
||||||
import { getEmbedIframe } from "@calcom/embed-core/playwright/lib/testUtils";
|
import { getEmbedIframe } from "@calcom/embed-core/playwright/lib/testUtils";
|
||||||
|
import { test } from "@calcom/web/playwright/lib/fixtures";
|
||||||
|
|
||||||
test("Inline Usage Snapshot", async ({ page, getActionFiredDetails, addEmbedListeners }) => {
|
test("Inline Usage Snapshot", async ({ page, getActionFiredDetails, addEmbedListeners }) => {
|
||||||
//TODO: Do it with page.goto automatically
|
//TODO: Do it with page.goto automatically
|
||||||
|
|
|
@ -24,11 +24,10 @@
|
||||||
],
|
],
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.34.0",
|
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"vite": "^4.1.2"
|
"vite": "^4.1.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/embed-core": "*"
|
"@calcom/embed-core": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/parser": "^5.52.0",
|
"@typescript-eslint/parser": "^5.52.0",
|
||||||
"@typescript-eslint/utils": "^5.52.0",
|
"@typescript-eslint/utils": "^5.52.0",
|
||||||
"eslint": "^8.34.0",
|
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@calcom/dayjs": "*",
|
||||||
|
"@calcom/lib": "*",
|
||||||
|
"@calcom/prisma": "*",
|
||||||
|
"@calcom/trpc": "*",
|
||||||
|
"@calcom/ui": "*",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"handlebars": "^4.7.7",
|
"handlebars": "^4.7.7",
|
||||||
"jose": "^4.13.1",
|
"jose": "^4.13.1",
|
||||||
"next-auth": "^4.20.1",
|
"next-auth": "^4.20.1",
|
||||||
"nodemailer": "^6.7.8",
|
"nodemailer": "^6.7.8",
|
||||||
"otplib": "^12.0.1",
|
"otplib": "^12.0.1"
|
||||||
"@calcom/dayjs": "*",
|
|
||||||
"@calcom/lib": "*",
|
|
||||||
"@calcom/prisma": "*",
|
|
||||||
"@calcom/trpc": "*",
|
|
||||||
"@calcom/ui": "*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@calcom/dayjs": "*",
|
||||||
|
"@calcom/lib": "*",
|
||||||
|
"@calcom/ui": "*",
|
||||||
"@lexical/react": "^0.5.0",
|
"@lexical/react": "^0.5.0",
|
||||||
"dompurify": "^2.4.1",
|
"dompurify": "^2.4.1",
|
||||||
"lexical": "^0.5.0",
|
"lexical": "^0.5.0",
|
||||||
"zustand": "^4.1.4",
|
"zustand": "^4.1.4"
|
||||||
"@calcom/ui": "*",
|
|
||||||
"@calcom/lib": "*",
|
|
||||||
"@calcom/dayjs": "*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { PlaywrightTestConfig } from "@playwright/test";
|
import type { Frame, PlaywrightTestConfig } from "@playwright/test";
|
||||||
import { devices } from "@playwright/test";
|
import { devices, expect } from "@playwright/test";
|
||||||
import dotEnv from "dotenv";
|
import dotEnv from "dotenv";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
@ -21,6 +21,7 @@ const DEFAULT_TEST_TIMEOUT = process.env.CI ? 60000 : 120000;
|
||||||
const headless = !!process.env.CI || !!process.env.PLAYWRIGHT_HEADLESS;
|
const headless = !!process.env.CI || !!process.env.PLAYWRIGHT_HEADLESS;
|
||||||
|
|
||||||
const IS_EMBED_TEST = process.argv.some((a) => a.startsWith("--project=@calcom/embed-core"));
|
const IS_EMBED_TEST = process.argv.some((a) => a.startsWith("--project=@calcom/embed-core"));
|
||||||
|
const IS_EMBED_REACT_TEST = process.argv.some((a) => a.startsWith("--project=@calcom/embed-react"));
|
||||||
|
|
||||||
const webServer: PlaywrightTestConfig["webServer"] = [
|
const webServer: PlaywrightTestConfig["webServer"] = [
|
||||||
{
|
{
|
||||||
|
@ -33,13 +34,22 @@ const webServer: PlaywrightTestConfig["webServer"] = [
|
||||||
|
|
||||||
if (IS_EMBED_TEST) {
|
if (IS_EMBED_TEST) {
|
||||||
webServer.push({
|
webServer.push({
|
||||||
command: "yarn workspace @calcom/embed-core run-p 'embed-dev' 'embed-web-start'",
|
command: "yarn workspace @calcom/embed-core dev",
|
||||||
port: 3100,
|
port: 3100,
|
||||||
timeout: 60_000,
|
timeout: 60_000,
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_EMBED_REACT_TEST) {
|
||||||
|
webServer.push({
|
||||||
|
command: "yarn workspace @calcom/embed-react dev",
|
||||||
|
port: 3101,
|
||||||
|
timeout: 60_000,
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const config: PlaywrightTestConfig = {
|
const config: PlaywrightTestConfig = {
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
retries: 2,
|
retries: 2,
|
||||||
|
@ -90,8 +100,14 @@ const config: PlaywrightTestConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "@calcom/embed-core",
|
name: "@calcom/embed-core",
|
||||||
testDir: "./packages/embeds/",
|
testDir: "./packages/embeds/embed-core/",
|
||||||
testMatch: /.*\.e2e\.tsx?/,
|
testMatch: /.*\.(e2e|test)\.tsx?/,
|
||||||
|
use: { ...devices["Desktop Chrome"] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "@calcom/embed-react",
|
||||||
|
testDir: "./packages/embeds/embed-react/",
|
||||||
|
testMatch: /.*\.(e2e|test)\.tsx?/,
|
||||||
use: { ...devices["Desktop Chrome"] },
|
use: { ...devices["Desktop Chrome"] },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -109,4 +125,124 @@ const config: PlaywrightTestConfig = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ExpectedUrlDetails = {
|
||||||
|
searchParams?: Record<string, string | string[]>;
|
||||||
|
pathname?: string;
|
||||||
|
origin?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
expect.extend({
|
||||||
|
async toBeEmbedCalLink(
|
||||||
|
iframe: Frame,
|
||||||
|
calNamespace: string,
|
||||||
|
//TODO: Move it to testUtil, so that it doesn't need to be passed
|
||||||
|
// eslint-disable-next-line
|
||||||
|
getActionFiredDetails: (a: { calNamespace: string; actionType: string }) => Promise<any>,
|
||||||
|
expectedUrlDetails: ExpectedUrlDetails = {}
|
||||||
|
) {
|
||||||
|
if (!iframe || !iframe.url) {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Expected to provide an iframe, got ${iframe}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const u = new URL(iframe.url());
|
||||||
|
const frameElement = await iframe.frameElement();
|
||||||
|
|
||||||
|
if (!(await frameElement.isVisible())) {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Expected iframe to be visible`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const pathname = u.pathname;
|
||||||
|
const expectedPathname = expectedUrlDetails.pathname + "/embed";
|
||||||
|
if (expectedPathname && expectedPathname !== pathname) {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Expected pathname to be ${expectedPathname} but got ${pathname}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const origin = u.origin;
|
||||||
|
const expectedOrigin = expectedUrlDetails.origin;
|
||||||
|
if (expectedOrigin && expectedOrigin !== origin) {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Expected origin to be ${expectedOrigin} but got ${origin}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = u.searchParams;
|
||||||
|
const expectedSearchParams = expectedUrlDetails.searchParams || {};
|
||||||
|
for (const [expectedKey, expectedValue] of Object.entries(expectedSearchParams)) {
|
||||||
|
const value = searchParams.get(expectedKey);
|
||||||
|
if (value !== expectedValue) {
|
||||||
|
return {
|
||||||
|
message: () => `${expectedKey} should have value ${expectedValue} but got value ${value}`,
|
||||||
|
pass: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let iframeReadyCheckInterval;
|
||||||
|
const iframeReadyEventDetail = await new Promise(async (resolve) => {
|
||||||
|
iframeReadyCheckInterval = setInterval(async () => {
|
||||||
|
const iframeReadyEventDetail = await getActionFiredDetails({
|
||||||
|
calNamespace,
|
||||||
|
actionType: "linkReady",
|
||||||
|
});
|
||||||
|
if (iframeReadyEventDetail) {
|
||||||
|
resolve(iframeReadyEventDetail);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
clearInterval(iframeReadyCheckInterval);
|
||||||
|
|
||||||
|
//At this point we know that window.initialBodyVisibility would be set as DOM would already have been ready(because linkReady event can only fire after that)
|
||||||
|
const {
|
||||||
|
visibility: visibilityBefore,
|
||||||
|
background: backgroundBefore,
|
||||||
|
initialValuesSet,
|
||||||
|
} = await iframe.evaluate(() => {
|
||||||
|
return {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
visibility: window.initialBodyVisibility,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
background: window.initialBodyBackground,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
//@ts-ignore
|
||||||
|
initialValuesSet: window.initialValuesSet,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
expect(initialValuesSet).toBe(true);
|
||||||
|
expect(visibilityBefore).toBe("hidden");
|
||||||
|
expect(backgroundBefore).toBe("transparent");
|
||||||
|
|
||||||
|
const { visibility: visibilityAfter, background: backgroundAfter } = await iframe.evaluate(() => {
|
||||||
|
return {
|
||||||
|
visibility: document.body.style.visibility,
|
||||||
|
background: document.body.style.background,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(visibilityAfter).toBe("visible");
|
||||||
|
expect(backgroundAfter).toBe("transparent");
|
||||||
|
if (!iframeReadyEventDetail) {
|
||||||
|
return {
|
||||||
|
pass: false,
|
||||||
|
message: () => `Iframe not ready to communicate with parent`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
pass: true,
|
||||||
|
message: () => `passed`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
Loading…
Reference in New Issue