refactor: apply biome formatting to several packages (#27439)
* refactor: apply biome formatting to Phase 1 packages Packages formatted: - packages/app-store-cli - packages/config - packages/dayjs - packages/debugging - packages/embeds/embed-react - packages/embeds/embed-snippet - packages/kysely - packages/platform/constants - packages/platform/utils - packages/testing - packages/tsconfig Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: restore non-null assertions in embed-snippet to fix type error Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: remove ESM import from CommonJS config file Biome incorrectly added 'import process from node:process' to a CommonJS file that uses require(). This breaks Jest which expects CommonJS syntax. The process global is already available in Node.js without explicit import. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: exclude packages/embeds from Phase 1 formatting Per user request, reverting all biome formatting changes in packages/embeds to handle separately. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: restore const enum for BookingLocations Biome changed 'const enum' to 'enum' which is a semantic change. Reverting to keep the PR purely formatting-only. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c652c61e0c
commit
357c2882ad
50 files changed
+349
-452
No files matched your search
@@ -1,6 +1,5 @@
|
||||
import React, { FC } from "react";
|
||||
import { SupportedCommands } from "src/types";
|
||||
|
||||
import type { FC } from "react";
|
||||
import type { SupportedCommands } from "src/types";
|
||||
import Create from "./commandViews/Create";
|
||||
import CreateTemplate from "./commandViews/Create";
|
||||
import Delete from "./commandViews/Delete";
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import chokidar from "chokidar";
|
||||
import fs from "node:fs"
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { debounce } from "lodash";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import path from "node:path"
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
import type { AppMeta } from "@calcom/types/App";
|
||||
import { AppMetaSchema } from "@calcom/types/AppMetaSchema";
|
||||
|
||||
import chokidar from "chokidar";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { debounce } from "lodash";
|
||||
import { APP_STORE_PATH } from "./constants";
|
||||
import { getAppName } from "./utils/getAppName";
|
||||
|
||||
@@ -37,8 +37,7 @@ const formatOutput = (source: string) => source;
|
||||
const getVariableName = (appName: string) => appName.replace(/[-./]/g, "_");
|
||||
|
||||
// INFO: Handle stripe separately as it's an old app with different dirName than slug/appId
|
||||
const getAppId = (app: { name: string }) =>
|
||||
app.name === "stripepayment" ? "stripe" : app.name;
|
||||
const getAppId = (app: { name: string }) => (app.name === "stripepayment" ? "stripe" : app.name);
|
||||
|
||||
type App = Partial<AppMeta> & {
|
||||
name: string;
|
||||
@@ -79,21 +78,10 @@ function generateFiles() {
|
||||
}
|
||||
});
|
||||
|
||||
function forEachAppDir(
|
||||
callback: (arg: App) => void,
|
||||
filter: (arg: App) => boolean = () => true
|
||||
) {
|
||||
function forEachAppDir(callback: (arg: App) => void, filter: (arg: App) => boolean = () => true) {
|
||||
for (let i = 0; i < appDirs.length; i++) {
|
||||
const configPath = path.join(
|
||||
APP_STORE_PATH,
|
||||
appDirs[i].path,
|
||||
"config.json"
|
||||
);
|
||||
const metadataPath = path.join(
|
||||
APP_STORE_PATH,
|
||||
appDirs[i].path,
|
||||
"_metadata.ts"
|
||||
);
|
||||
const configPath = path.join(APP_STORE_PATH, appDirs[i].path, "config.json");
|
||||
const metadataPath = path.join(APP_STORE_PATH, appDirs[i].path, "_metadata.ts");
|
||||
let app: AppMetaSchema;
|
||||
|
||||
if (fs.existsSync(configPath)) {
|
||||
@@ -102,16 +90,8 @@ function generateFiles() {
|
||||
const parsedConfig = JSON.parse(rawConfig);
|
||||
app = AppMetaSchema.parse(parsedConfig);
|
||||
} catch (error) {
|
||||
const prefix = `Config error in ${path.join(
|
||||
APP_STORE_PATH,
|
||||
appDirs[i].path,
|
||||
"config.json"
|
||||
)}`;
|
||||
throw new Error(
|
||||
`${prefix}: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`
|
||||
);
|
||||
const prefix = `Config error in ${path.join(APP_STORE_PATH, appDirs[i].path, "config.json")}`;
|
||||
throw new Error(`${prefix}: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
} else if (fs.existsSync(metadataPath)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
@@ -156,7 +136,7 @@ function generateFiles() {
|
||||
{
|
||||
fileToBeImported: string;
|
||||
importName: string;
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -180,18 +160,12 @@ function generateFiles() {
|
||||
const getLocalImportName = (
|
||||
app: { name: string },
|
||||
chosenConfig: ReturnType<typeof getChosenImportConfig>
|
||||
) =>
|
||||
`${getVariableName(app.name)}_${getVariableName(
|
||||
chosenConfig.fileToBeImported
|
||||
)}`;
|
||||
) => `${getVariableName(app.name)}_${getVariableName(chosenConfig.fileToBeImported)}`;
|
||||
|
||||
const fileToBeImportedExists = (
|
||||
app: { path: string },
|
||||
chosenConfig: ReturnType<typeof getChosenImportConfig>
|
||||
) =>
|
||||
fs.existsSync(
|
||||
path.join(APP_STORE_PATH, app.path, chosenConfig.fileToBeImported)
|
||||
);
|
||||
) => fs.existsSync(path.join(APP_STORE_PATH, app.path, chosenConfig.fileToBeImported));
|
||||
|
||||
addImportStatements();
|
||||
createExportObject();
|
||||
@@ -201,19 +175,13 @@ function generateFiles() {
|
||||
function addImportStatements() {
|
||||
forEachAppDir((app) => {
|
||||
const chosenConfig = getChosenImportConfig(importConfig, app);
|
||||
if (
|
||||
fileToBeImportedExists(app, chosenConfig) &&
|
||||
chosenConfig.importName
|
||||
) {
|
||||
if (fileToBeImportedExists(app, chosenConfig) && chosenConfig.importName) {
|
||||
const importName = chosenConfig.importName;
|
||||
if (!lazyImport) {
|
||||
if (importName !== "default") {
|
||||
// Import with local alias that will be used by createExportObject
|
||||
output.push(
|
||||
`import { ${importName} as ${getLocalImportName(
|
||||
app,
|
||||
chosenConfig
|
||||
)} } from "${getModulePath(
|
||||
`import { ${importName} as ${getLocalImportName(app, chosenConfig)} } from "${getModulePath(
|
||||
app.path,
|
||||
chosenConfig.fileToBeImported
|
||||
)}"`
|
||||
@@ -221,10 +189,7 @@ function generateFiles() {
|
||||
} else {
|
||||
// Default Import
|
||||
output.push(
|
||||
`import ${getLocalImportName(
|
||||
app,
|
||||
chosenConfig
|
||||
)} from "${getModulePath(
|
||||
`import ${getLocalImportName(app, chosenConfig)} from "${getModulePath(
|
||||
app.path,
|
||||
chosenConfig.fileToBeImported
|
||||
)}"`
|
||||
@@ -255,12 +220,7 @@ function generateFiles() {
|
||||
)}")),`
|
||||
);
|
||||
} else {
|
||||
output.push(
|
||||
`"${key}": import("${getModulePath(
|
||||
app.path,
|
||||
chosenConfig.fileToBeImported
|
||||
)}"),`
|
||||
);
|
||||
output.push(`"${key}": import("${getModulePath(app.path, chosenConfig.fileToBeImported)}"),`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,24 +229,13 @@ function generateFiles() {
|
||||
output.push(`};`);
|
||||
}
|
||||
|
||||
function getChosenImportConfig(
|
||||
importConfig: ImportConfig,
|
||||
app: { path: string }
|
||||
) {
|
||||
function getChosenImportConfig(importConfig: ImportConfig, app: { path: string }) {
|
||||
let chosenConfig: ImportConfig;
|
||||
|
||||
if (!Array.isArray(importConfig)) {
|
||||
chosenConfig = importConfig;
|
||||
} else {
|
||||
if (
|
||||
fs.existsSync(
|
||||
path.join(
|
||||
APP_STORE_PATH,
|
||||
app.path,
|
||||
importConfig[0].fileToBeImported
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (fs.existsSync(path.join(APP_STORE_PATH, app.path, importConfig[0].fileToBeImported))) {
|
||||
chosenConfig = importConfig[0];
|
||||
} else {
|
||||
chosenConfig = importConfig[1];
|
||||
@@ -472,10 +421,7 @@ function generateFiles() {
|
||||
);
|
||||
if (analyticsExportLineIndex !== -1) {
|
||||
const exportLine = analyticsServices[analyticsExportLineIndex];
|
||||
const objectContent = analyticsServices.slice(
|
||||
analyticsExportLineIndex + 1,
|
||||
-1
|
||||
);
|
||||
const objectContent = analyticsServices.slice(analyticsExportLineIndex + 1, -1);
|
||||
|
||||
analyticsOutput.push(
|
||||
exportLine.replace(
|
||||
@@ -500,9 +446,7 @@ function generateFiles() {
|
||||
lazyImport: true,
|
||||
},
|
||||
(app: App) => {
|
||||
const hasPaymentService = fs.existsSync(
|
||||
path.join(APP_STORE_PATH, app.path, "lib/PaymentService.ts")
|
||||
);
|
||||
const hasPaymentService = fs.existsSync(path.join(APP_STORE_PATH, app.path, "lib/PaymentService.ts"));
|
||||
return hasPaymentService;
|
||||
}
|
||||
);
|
||||
@@ -520,9 +464,7 @@ function generateFiles() {
|
||||
lazyImport: true,
|
||||
},
|
||||
(app: App) => {
|
||||
return fs.existsSync(
|
||||
path.join(APP_STORE_PATH, app.path, "lib/VideoApiAdapter.ts")
|
||||
);
|
||||
return fs.existsSync(path.join(APP_STORE_PATH, app.path, "lib/VideoApiAdapter.ts"));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -568,9 +510,7 @@ function generateFiles() {
|
||||
fs.writeFileSync(filePath, formatOutput(`${banner}${output.join("\n")}`));
|
||||
formatFileWithBiome(filePath);
|
||||
});
|
||||
console.log(
|
||||
`Generated ${filesToGenerate.map(([fileName]) => fileName).join(", ")}`
|
||||
);
|
||||
console.log(`Generated ${filesToGenerate.map(([fileName]) => fileName).join(", ")}`);
|
||||
}
|
||||
|
||||
const debouncedGenerateFiles = debounce(generateFiles);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
import { render } from "ink";
|
||||
import meow from "meow";
|
||||
import React from "react";
|
||||
|
||||
import App from "./App";
|
||||
import { SupportedCommands } from "./types";
|
||||
import type { SupportedCommands } from "./types";
|
||||
|
||||
const cli = meow(
|
||||
`
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
import type React from "react";
|
||||
import { AppForm } from "../components/AppCreateUpdateForm";
|
||||
|
||||
export default function Create(props: Omit<React.ComponentProps<typeof AppForm>, "action">) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
import type React from "react";
|
||||
import { AppForm } from "../components/AppCreateUpdateForm";
|
||||
|
||||
export default function CreateTemplate(props: Omit<React.ComponentProps<typeof AppForm>, "action">) {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import React from "react";
|
||||
|
||||
import DeleteForm from "../components/DeleteForm";
|
||||
|
||||
export default function Delete({ slug }: { slug: string }) {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import React from "react";
|
||||
|
||||
import DeleteForm from "../components/DeleteForm";
|
||||
|
||||
export default function Delete({ slug }: { slug: string }) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
import type React from "react";
|
||||
import { AppForm } from "../components/AppCreateUpdateForm";
|
||||
|
||||
export default function Edit(props: Omit<React.ComponentProps<typeof AppForm>, "action">) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
import type React from "react";
|
||||
import { AppForm } from "../components/AppCreateUpdateForm";
|
||||
|
||||
export default function Edit(props: Omit<React.ComponentProps<typeof AppForm>, "action">) {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import fs from "node:fs"
|
||||
import fs from "node:fs";
|
||||
import type { AppMeta } from "@calcom/types/App";
|
||||
import { Box, Newline, Text, useApp } from "ink";
|
||||
import SelectInput from "ink-select-input";
|
||||
import TextInput from "ink-text-input";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import type { AppMeta } from "@calcom/types/App";
|
||||
|
||||
import { getSlugFromAppName, BaseAppFork, generateAppFiles, getAppDirPath } from "../core";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BaseAppFork, generateAppFiles, getAppDirPath, getSlugFromAppName } from "../core";
|
||||
import { getApp } from "../utils/getApp";
|
||||
import Templates from "../utils/templates";
|
||||
import Label from "./Label";
|
||||
@@ -46,7 +44,7 @@ export const AppForm = ({
|
||||
category: config.categories[0],
|
||||
template: config.__template,
|
||||
};
|
||||
} catch (e) {}
|
||||
} catch (_e) {}
|
||||
|
||||
const fields = [
|
||||
{
|
||||
@@ -130,7 +128,7 @@ export const AppForm = ({
|
||||
const formCompleted = inputIndex === fields.length;
|
||||
if (field?.name === "appCategory") {
|
||||
// Use template category as the default category
|
||||
fieldValue = Templates.find((t) => t.value === appInputData["template"])?.category || "";
|
||||
fieldValue = Templates.find((t) => t.value === appInputData.template)?.category || "";
|
||||
}
|
||||
const slug = getSlugFromAppName(name) || givenSlug;
|
||||
|
||||
@@ -158,7 +156,19 @@ export const AppForm = ({
|
||||
setStatus("done");
|
||||
}
|
||||
})();
|
||||
}, [formCompleted]);
|
||||
}, [
|
||||
formCompleted,
|
||||
category,
|
||||
description,
|
||||
email,
|
||||
givenSlug,
|
||||
isEditAction,
|
||||
isTemplate,
|
||||
name,
|
||||
publisher,
|
||||
slug,
|
||||
template,
|
||||
]);
|
||||
|
||||
if (action === "edit" || action === "edit-template") {
|
||||
if (!slug) {
|
||||
@@ -291,7 +301,7 @@ export const AppForm = ({
|
||||
)}
|
||||
<Box>
|
||||
<Label>{`${fieldLabel}`}</Label>
|
||||
{field?.type == "text" ? (
|
||||
{field?.type === "text" ? (
|
||||
<TextInput
|
||||
value={fieldValue}
|
||||
placeholder={field?.defaultValue}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Text } from "ink";
|
||||
import TextInput from "ink-text-input";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { ImportantText } from "../components/ImportantText";
|
||||
import { Message } from "../components/Message";
|
||||
import { BaseAppFork, generateAppFiles } from "../core";
|
||||
@@ -22,7 +21,7 @@ export default function DeleteForm({ slug, action }: { slug: string; action: "de
|
||||
if (!app) {
|
||||
setState("APP_NOT_EXISTS");
|
||||
}
|
||||
}, []);
|
||||
}, [app]);
|
||||
|
||||
useEffect(() => {
|
||||
if (state === "DELETION_CONFIRMATION_SUCCESSFUL") {
|
||||
@@ -33,7 +32,7 @@ export default function DeleteForm({ slug, action }: { slug: string; action: "de
|
||||
setState("DELETION_COMPLETED");
|
||||
})();
|
||||
}
|
||||
}, [slug, state]);
|
||||
}, [slug, state, isTemplate]);
|
||||
|
||||
if (state === "INITIALIZED") {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Text } from "ink";
|
||||
import React from "react";
|
||||
import type React from "react";
|
||||
|
||||
export function ImportantText({ children }: { children: React.ReactNode }) {
|
||||
return <Text color="red">{children}</Text>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Box, Text } from "ink";
|
||||
import React from "react";
|
||||
import type React from "react";
|
||||
|
||||
export default function Label({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Text } from "ink";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function Message({
|
||||
message,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path"
|
||||
import path from "node:path";
|
||||
|
||||
export const APP_STORE_PATH = path.join(__dirname, "..", "..", "app-store");
|
||||
export const TEMPLATES_PATH = path.join(APP_STORE_PATH, "templates");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
import { APP_STORE_PATH, TEMPLATES_PATH, IS_WINDOWS_PLATFORM } from "./constants";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { APP_STORE_PATH, IS_WINDOWS_PLATFORM, TEMPLATES_PATH } from "./constants";
|
||||
import execSync from "./utils/execSync";
|
||||
|
||||
const slugify = (str: string) => {
|
||||
@@ -41,10 +40,10 @@ const updatePackageJson = ({
|
||||
fs.writeFileSync(`${appDirPath}/package.json`, JSON.stringify(packageJsonConfig, null, 2));
|
||||
};
|
||||
|
||||
const workspaceDir = path.resolve(__dirname, "..", "..", "..");
|
||||
const _workspaceDir = path.resolve(__dirname, "..", "..", "..");
|
||||
|
||||
export const BaseAppFork = {
|
||||
create: async function ({
|
||||
create: async ({
|
||||
category,
|
||||
editMode = false,
|
||||
description,
|
||||
@@ -66,7 +65,7 @@ export const BaseAppFork = {
|
||||
template: string;
|
||||
isTemplate: boolean;
|
||||
oldSlug?: string;
|
||||
}) {
|
||||
}) => {
|
||||
const appDirPath = getAppDirPath(slug, isTemplate);
|
||||
if (!editMode) {
|
||||
await execSync(IS_WINDOWS_PLATFORM ? `mkdir ${appDirPath}` : `mkdir -p ${appDirPath}`);
|
||||
@@ -129,7 +128,7 @@ export const BaseAppFork = {
|
||||
await execSync("yarn");
|
||||
},
|
||||
|
||||
delete: async function ({ slug, isTemplate }: { slug: string; isTemplate: boolean }) {
|
||||
delete: async ({ slug, isTemplate }: { slug: string; isTemplate: boolean }) => {
|
||||
const appDirPath = getAppDirPath(slug, isTemplate);
|
||||
await execSync(IS_WINDOWS_PLATFORM ? `rd /s /q ${appDirPath}` : `rm -rf ${appDirPath}`);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import child_process from "node:child_process";
|
||||
import process from "node:process";
|
||||
|
||||
const execSync = async (cmd: string) => {
|
||||
const silent = process.env.DEBUG === "1" ? false : true;
|
||||
const silent = process.env.DEBUG !== "1";
|
||||
if (!silent) {
|
||||
console.log(`${process.cwd()}$: ${cmd}`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { APP_STORE_PATH, TEMPLATES_PATH } from "../constants";
|
||||
import { getAppName } from "./getAppName";
|
||||
|
||||
@@ -18,7 +17,7 @@ export const getApp = (slug: string, isTemplate: boolean) => {
|
||||
if (foundApp) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(path.join(base, foundApp, "config.json")).toString());
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import path from "node:path"
|
||||
|
||||
import path from "node:path";
|
||||
import { APP_STORE_PATH } from "../constants";
|
||||
|
||||
export function getAppName(candidatePath) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { TEMPLATES_PATH } from "../constants";
|
||||
import { getAppName } from "./getAppName";
|
||||
|
||||
@@ -20,7 +19,7 @@ const Templates = fs
|
||||
value: dir,
|
||||
category: config.categories[0],
|
||||
};
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
// config.json might not exist
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const hexToHSL = (hex: string): HSL => {
|
||||
s,
|
||||
// eslint-disable-next-line prefer-const
|
||||
l = (max + min) / 2;
|
||||
if (max == min) {
|
||||
if (max === min) {
|
||||
h = s = 0; // achromatic
|
||||
} else {
|
||||
const d = max - min;
|
||||
@@ -37,7 +37,7 @@ const hexToHSL = (hex: string): HSL => {
|
||||
HSL.s = Math.round(s * 100);
|
||||
HSL.l = Math.round(l * 100);
|
||||
return HSL;
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
console.log(hex);
|
||||
return { h: 0, s: 0, l: 0 };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@source "../../../apps/web/pages/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../apps/web/app/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../apps/web/modules/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../apps/web/modules/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../apps/web/components/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../packages/app-store/**/*{components,pages}/**/*.{js,ts,jsx,tsx}";
|
||||
@source "../../../packages/features/**/*.{js,ts,jsx,tsx}";
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import timezone from "dayjs/plugin/timezone";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
// biome-ignore lint/nursery/useExplicitType: mock function
|
||||
const mockDayjs = Object.assign(vi.fn((date: Parameters<typeof dayjs>[0]) => dayjs(date)), {
|
||||
utc: vi.fn((date: Parameters<typeof dayjs.utc>[0]) => dayjs.utc(date)),
|
||||
tz: vi.fn(),
|
||||
extend: vi.fn(),
|
||||
});
|
||||
const mockDayjs = Object.assign(
|
||||
vi.fn((date: Parameters<typeof dayjs>[0]) => dayjs(date)),
|
||||
{
|
||||
utc: vi.fn((date: Parameters<typeof dayjs.utc>[0]) => dayjs.utc(date)),
|
||||
tz: vi.fn(),
|
||||
extend: vi.fn(),
|
||||
}
|
||||
);
|
||||
|
||||
export default mockDayjs;
|
||||
@@ -10,7 +10,6 @@ import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import timeZone from "dayjs/plugin/timezone";
|
||||
import toArray from "dayjs/plugin/toArray";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
|
||||
import BusinessDaysPlugin from "./plugins/business-days-plugin";
|
||||
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
@@ -15,43 +15,33 @@ const BusinessDaysPlugin: PluginFunc<BusinessDaysPluginOptions> = (
|
||||
) => {
|
||||
const defaultWorkingWeekdays = [1, 2, 3, 4, 5];
|
||||
|
||||
dayjsFactory.getWorkingWeekdays = function (): number[] {
|
||||
return options.workingWeekdays || defaultWorkingWeekdays;
|
||||
};
|
||||
dayjsFactory.getWorkingWeekdays = (): number[] => options.workingWeekdays || defaultWorkingWeekdays;
|
||||
|
||||
dayjsFactory.setWorkingWeekdays = function (workingWeekdays: number[]): void {
|
||||
dayjsFactory.setWorkingWeekdays = (workingWeekdays: number[]): void => {
|
||||
options.workingWeekdays = workingWeekdays;
|
||||
};
|
||||
|
||||
dayjsFactory.getHolidays = function (): string[] {
|
||||
return options.holidays || [];
|
||||
};
|
||||
dayjsFactory.getHolidays = (): string[] => options.holidays || [];
|
||||
|
||||
dayjsFactory.setHolidays = function (holidays: string[]): void {
|
||||
dayjsFactory.setHolidays = (holidays: string[]): void => {
|
||||
options.holidays = holidays;
|
||||
};
|
||||
|
||||
dayjsFactory.getHolidayFormat = function (): string | undefined {
|
||||
return options.holidayFormat;
|
||||
};
|
||||
dayjsFactory.getHolidayFormat = (): string | undefined => options.holidayFormat;
|
||||
|
||||
dayjsFactory.setHolidayFormat = function (holidayFormat: string): void {
|
||||
dayjsFactory.setHolidayFormat = (holidayFormat: string): void => {
|
||||
options.holidayFormat = holidayFormat;
|
||||
};
|
||||
|
||||
dayjsFactory.getAdditionalWorkingDays = function (): string[] {
|
||||
return options.additionalWorkingDays || [];
|
||||
};
|
||||
dayjsFactory.getAdditionalWorkingDays = (): string[] => options.additionalWorkingDays || [];
|
||||
|
||||
dayjsFactory.setAdditionalWorkingDays = function (additionalWorkingDays: string[]): void {
|
||||
dayjsFactory.setAdditionalWorkingDays = (additionalWorkingDays: string[]): void => {
|
||||
options.additionalWorkingDays = additionalWorkingDays;
|
||||
};
|
||||
|
||||
dayjsFactory.getAdditionalWorkingDayFormat = function (): string | undefined {
|
||||
return options.additionalWorkingDayFormat;
|
||||
};
|
||||
dayjsFactory.getAdditionalWorkingDayFormat = (): string | undefined => options.additionalWorkingDayFormat;
|
||||
|
||||
dayjsFactory.setAdditionalWorkingDayFormat = function (additionalWorkingDayFormat: string): void {
|
||||
dayjsFactory.setAdditionalWorkingDayFormat = (additionalWorkingDayFormat: string): void => {
|
||||
options.additionalWorkingDayFormat = additionalWorkingDayFormat;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Kysely, ParseJSONResultsPlugin, PostgresDialect, DeduplicateJoinsPlugin } from "kysely";
|
||||
import process from "node:process";
|
||||
import { DeduplicateJoinsPlugin, Kysely, ParseJSONResultsPlugin, PostgresDialect } from "kysely";
|
||||
import { Pool } from "pg";
|
||||
|
||||
import type { DB, Booking } from "./types";
|
||||
import type { Booking, DB } from "./types";
|
||||
|
||||
export type { DB, Booking };
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ExpressionBuilder, StringReference } from "kysely";
|
||||
import { sql } from "kysely";
|
||||
|
||||
export function traverseJSON<DB, TB extends keyof DB>(
|
||||
eb: ExpressionBuilder<DB, TB>,
|
||||
_eb: ExpressionBuilder<DB, TB>,
|
||||
column: StringReference<DB, TB>,
|
||||
path: string | [string, ...string[]]
|
||||
) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from "./permissions";
|
||||
export * from "./api";
|
||||
export * from "./apps";
|
||||
export * from "./permissions";
|
||||
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
APPS_READ,
|
||||
APPS_WRITE,
|
||||
BOOKING_READ,
|
||||
BOOKING_WRITE,
|
||||
EVENT_TYPE_READ,
|
||||
EVENT_TYPE_WRITE,
|
||||
PERMISSIONS,
|
||||
SCHEDULE_READ,
|
||||
SCHEDULE_WRITE,
|
||||
APPS_READ,
|
||||
APPS_WRITE,
|
||||
PROFILE_READ,
|
||||
PROFILE_WRITE,
|
||||
SCHEDULE_READ,
|
||||
SCHEDULE_WRITE,
|
||||
} from "@calcom/platform-constants";
|
||||
import type { PLATFORM_PERMISSION } from "@calcom/platform-types";
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
SCHEDULE_READ,
|
||||
SCHEDULE_WRITE,
|
||||
} from "@calcom/platform-constants";
|
||||
|
||||
import { hasPermission, hasPermissions, listPermissions } from "../permissions";
|
||||
|
||||
describe("Permissions Function: hasPermission", () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sleep } from "k6";
|
||||
|
||||
import { THRESHOLDS } from "../utils/config.js";
|
||||
import { viewBookingPage } from "../utils/helpers.js";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sleep } from "k6";
|
||||
|
||||
import { THRESHOLDS } from "../utils/config.js";
|
||||
import { viewBookingPage } from "../utils/helpers.js";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sleep } from "k6";
|
||||
|
||||
import { THRESHOLDS } from "../utils/config.js";
|
||||
import { viewBookingPage } from "../utils/helpers.js";
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sleep } from "k6";
|
||||
|
||||
import { THRESHOLDS } from "../utils/config.js";
|
||||
import { viewBookingPage } from "../utils/helpers.js";
|
||||
|
||||
|
||||
@@ -35,12 +35,10 @@ export const THRESHOLDS = {
|
||||
},
|
||||
};
|
||||
|
||||
export const TEST_USERS = new SharedArray("users", function () {
|
||||
return [
|
||||
{ username: __ENV.TEST_USER_FREE || "free", password: __ENV.TEST_PASSWORD_FREE || "free" },
|
||||
{ username: __ENV.TEST_USER_PRO || "pro", password: __ENV.TEST_PASSWORD_PRO || "pro" },
|
||||
];
|
||||
});
|
||||
export const TEST_USERS = new SharedArray("users", () => [
|
||||
{ username: __ENV.TEST_USER_FREE || "free", password: __ENV.TEST_PASSWORD_FREE || "free" },
|
||||
{ username: __ENV.TEST_USER_PRO || "pro", password: __ENV.TEST_PASSWORD_PRO || "pro" },
|
||||
]);
|
||||
|
||||
export function getRandomUser() {
|
||||
return TEST_USERS[Math.floor(Math.random() * TEST_USERS.length)];
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { check, group } from "k6";
|
||||
import http from "k6/http";
|
||||
|
||||
import { randomSleep, BASE_URL, randomQueryParam } from "./config.js";
|
||||
import { BASE_URL, randomQueryParam, randomSleep } from "./config.js";
|
||||
|
||||
export function viewBookingPage(username, eventSlug) {
|
||||
return group("View Booking Page", () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { mockReset, mockDeep } from "vitest-mock-extended";
|
||||
|
||||
import type * as i18n from "@calcom/lib/server/i18n";
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { mockDeep, mockReset } from "vitest-mock-extended";
|
||||
|
||||
vi.mock("@calcom/lib/server/i18n", () => i18nMock);
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { type DMMF } from "@prisma/client/runtime/client";
|
||||
import { getDMMF } from "@prisma/internals";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { createPrismock } from "prismock/build/main/lib/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import * as selects from "@calcom/prisma/selects";
|
||||
import type { DMMF } from "@prisma/client/runtime/client";
|
||||
import { getDMMF } from "@prisma/internals";
|
||||
import { createPrismock } from "prismock/build/main/lib/client";
|
||||
import { beforeEach, vi } from "vitest";
|
||||
|
||||
vi.stubEnv("DATABASE_URL", "postgresql://user:password@localhost:5432/testdb");
|
||||
|
||||
@@ -56,7 +55,7 @@ const prismaMockProxy = new Proxy(proxyTarget, {
|
||||
}
|
||||
return prop in prismockInstance;
|
||||
},
|
||||
ownKeys(target) {
|
||||
ownKeys(_target) {
|
||||
if (!prismockInstance) {
|
||||
return [];
|
||||
}
|
||||
@@ -68,7 +67,7 @@ const prismaMockProxy = new Proxy(proxyTarget, {
|
||||
}
|
||||
(target as any)[prop] = value;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
vi.mock("@calcom/prisma", async (importOriginal) => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { type DeepMockProxy, mockDeep, mockReset } from "vitest-mock-extended";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
const prisma = mockDeep<PrismaClient>() as unknown as DeepMockProxy<PrismaClient>;
|
||||
|
||||
vi.mock("@calcom/prisma", () => ({
|
||||
|
||||
@@ -4,7 +4,7 @@ import "vitest-fetch-mock";
|
||||
|
||||
import { sendAwaitingPaymentEmailAndSMS } from "@calcom/emails/email-manager";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { Payment, Prisma, PaymentOption, Booking } from "@calcom/prisma/client";
|
||||
import type { Booking, Payment, PaymentOption, Prisma } from "@calcom/prisma/client";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { IAbstractPaymentService } from "@calcom/types/PaymentService";
|
||||
|
||||
@@ -23,10 +23,10 @@ export function getMockPaymentService() {
|
||||
async create(
|
||||
payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
|
||||
bookingId: Booking["id"],
|
||||
userId: Booking["userId"],
|
||||
username: string | null,
|
||||
bookerName: string | null,
|
||||
bookerEmail: string,
|
||||
_userId: Booking["userId"],
|
||||
_username: string | null,
|
||||
_bookerName: string | null,
|
||||
_bookerEmail: string,
|
||||
paymentOption: PaymentOption
|
||||
) {
|
||||
const paymentCreateData = {
|
||||
@@ -59,7 +59,7 @@ export function getMockPaymentService() {
|
||||
}
|
||||
async afterPayment(
|
||||
event: CalendarEvent,
|
||||
booking: {
|
||||
_booking: {
|
||||
user: { email: string | null; name: string | null; timeZone: string } | null;
|
||||
id: number;
|
||||
startTime: { toISOString: () => string };
|
||||
@@ -71,12 +71,14 @@ export function getMockPaymentService() {
|
||||
await sendAwaitingPaymentEmailAndSMS({
|
||||
...event,
|
||||
paymentInfo: {
|
||||
link: createPaymentLink(/*{
|
||||
link: createPaymentLink(
|
||||
/*{
|
||||
paymentUid: paymentData.uid,
|
||||
name: booking.user?.name,
|
||||
email: booking.user?.email,
|
||||
date: booking.startTime.toISOString(),
|
||||
}*/),
|
||||
}*/
|
||||
),
|
||||
paymentOption: paymentData.paymentOption || "ON_BOOKING",
|
||||
amount: paymentData.amount,
|
||||
currency: paymentData.currency,
|
||||
|
||||
@@ -1,45 +1,52 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import i18nMock from "../__mocks__/libServerI18n";
|
||||
import prismock from "../__mocks__/prisma";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { vi } from "vitest";
|
||||
import "vitest-fetch-mock";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
|
||||
import { weekdayToWeekIndex, type WeekDays } from "@calcom/lib/dayjs";
|
||||
import { type WeekDays, weekdayToWeekIndex } from "@calcom/lib/dayjs";
|
||||
import type { IntervalLimit } from "@calcom/lib/intervalLimits/intervalLimitSchema";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type { BookingReference, Attendee, Booking, Membership } from "@calcom/prisma/client";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import type { WebhookTriggerEvents } from "@calcom/prisma/client";
|
||||
import type {
|
||||
Attendee,
|
||||
Booking,
|
||||
BookingReference,
|
||||
Membership,
|
||||
Prisma,
|
||||
WebhookTriggerEvents,
|
||||
WorkflowActions,
|
||||
WorkflowMethods,
|
||||
WorkflowTemplates,
|
||||
WorkflowTriggerEvents,
|
||||
WorkflowMethods,
|
||||
} from "@calcom/prisma/client";
|
||||
import type { PaymentOption, SchedulingType, SMSLockState, TimeUnit } from "@calcom/prisma/enums";
|
||||
import type { BookingStatus } from "@calcom/prisma/enums";
|
||||
import type { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { userMetadataType } from "@calcom/prisma/zod-utils";
|
||||
import type { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type {
|
||||
BookingStatus,
|
||||
PaymentOption,
|
||||
SchedulingType,
|
||||
SMSLockState,
|
||||
TimeUnit,
|
||||
} from "@calcom/prisma/enums";
|
||||
import type {
|
||||
EventTypeMetaDataSchema,
|
||||
eventTypeBookingFields,
|
||||
teamMetadataSchema,
|
||||
userMetadataType,
|
||||
} from "@calcom/prisma/zod-utils";
|
||||
import type { AppMeta } from "@calcom/types/App";
|
||||
import type {
|
||||
Calendar,
|
||||
CalendarEvent,
|
||||
EventBusyDate,
|
||||
IntegrationCalendar,
|
||||
NewCalendarEventType,
|
||||
EventBusyDate,
|
||||
} from "@calcom/types/Calendar";
|
||||
import type { CredentialPayload } from "@calcom/types/Credential";
|
||||
import type { VideoApiAdapter } from "@calcom/types/VideoApiAdapter";
|
||||
|
||||
import { getMockPaymentService } from "./MockPaymentService";
|
||||
import type { z } from "zod";
|
||||
import type { getMockRequestDataForBooking } from "./getMockRequestDataForBooking";
|
||||
import { getMockPaymentService } from "./MockPaymentService";
|
||||
|
||||
type NonNullableVideoApiAdapter = NonNullable<VideoApiAdapter>;
|
||||
vi.mock("@calcom/app-store/calendar.services.generated", () => ({
|
||||
@@ -57,7 +64,7 @@ vi.mock("@calcom/app-store/video.adapters.generated", () => ({
|
||||
VideoApiAdapterMap: new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, prop) {
|
||||
get(_target, prop) {
|
||||
if (typeof prop === "string" && mockVideoAdapterRegistry[prop]) {
|
||||
return mockVideoAdapterRegistry[prop];
|
||||
}
|
||||
@@ -578,7 +585,7 @@ export async function addEventTypes(eventTypes: InputEventType[], usersStore: In
|
||||
data: eventType.restrictionSchedule.create.availability.createMany.data,
|
||||
},
|
||||
},
|
||||
user: { connect: { id: eventType.userId || (eventType.users && eventType.users[0]?.id) || 1 } },
|
||||
user: { connect: { id: eventType.userId || eventType.users?.[0]?.id || 1 } },
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
@@ -1131,12 +1138,7 @@ export async function createCredentials(
|
||||
* use vi.setSystemTime to fix the date and time and then use hardcoded days instead of dynamic date calculation.
|
||||
*/
|
||||
export const getDate = (
|
||||
param: {
|
||||
dateIncrement?: number;
|
||||
monthIncrement?: number;
|
||||
yearIncrement?: number;
|
||||
fromDate?: Date;
|
||||
} = {}
|
||||
param: { dateIncrement?: number; monthIncrement?: number; yearIncrement?: number; fromDate?: Date } = {}
|
||||
) => {
|
||||
let { dateIncrement, monthIncrement, yearIncrement, fromDate } = param;
|
||||
|
||||
@@ -1837,163 +1839,154 @@ export async function mockCalendar(
|
||||
if (calendarServicePromise) {
|
||||
const resolvedService = await calendarServicePromise;
|
||||
vi.mocked(resolvedService.default).mockImplementation(function MockCalendarService(credential) {
|
||||
return {
|
||||
createEvent: async function (
|
||||
...rest: Parameters<Calendar["createEvent"]>
|
||||
): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.creationCrash) {
|
||||
throw new Error("MockCalendarService.createEvent fake error");
|
||||
}
|
||||
const [calEvent, credentialId, externalCalendarId] = rest;
|
||||
log.debug(
|
||||
"mockCalendar.createEvent",
|
||||
JSON.stringify({ calEvent, credentialId, externalCalendarId })
|
||||
);
|
||||
createEventCalls.push({
|
||||
args: {
|
||||
calEvent,
|
||||
credentialId,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = calEvent?.location === BookingLocations.GoogleMeet;
|
||||
if (app.type === "google_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {
|
||||
hangoutLink:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
},
|
||||
return {
|
||||
createEvent: async (...rest: Parameters<Calendar["createEvent"]>): Promise<NewCalendarEventType> => {
|
||||
if (calendarData?.creationCrash) {
|
||||
throw new Error("MockCalendarService.createEvent fake error");
|
||||
}
|
||||
const [calEvent, credentialId, externalCalendarId] = rest;
|
||||
log.debug(
|
||||
"mockCalendar.createEvent",
|
||||
JSON.stringify({ calEvent, credentialId, externalCalendarId })
|
||||
);
|
||||
createEventCalls.push({
|
||||
args: {
|
||||
calEvent,
|
||||
credentialId,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = calEvent?.location === BookingLocations.GoogleMeet;
|
||||
if (app.type === "google_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {
|
||||
hangoutLink:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
uid: normalizedCalendarData.create?.uid || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID || calEvent.iCalUID || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
});
|
||||
} else if (app.type === "office365_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: normalizedCalendarData.create?.uid || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID ||
|
||||
calEvent.iCalUID ||
|
||||
"OFFICE_365_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.office365Calendar?.url ||
|
||||
"https://UNUSED_URL",
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
// A Calendar is always expected to return an id.
|
||||
id: normalizedCalendarData.create?.id || "FALLBACK_MOCK_CALENDAR_EVENT_ID",
|
||||
iCalUID: normalizedCalendarData.create?.iCalUID,
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
});
|
||||
}
|
||||
},
|
||||
updateEvent: async function (
|
||||
...rest: Parameters<Calendar["updateEvent"]>
|
||||
): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.updationCrash) {
|
||||
throw new Error("MockCalendarService.updateEvent fake error");
|
||||
}
|
||||
const [uid, event, externalCalendarId] = rest;
|
||||
log.silly("mockCalendar.updateEvent", JSON.stringify({ uid, event, externalCalendarId }));
|
||||
updateEventCalls.push({
|
||||
args: {
|
||||
uid,
|
||||
event,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
hangoutLink:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
uid: normalizedCalendarData.create?.uid || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID || calEvent.iCalUID || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
});
|
||||
const isGoogleMeetLocation = event.location === BookingLocations.GoogleMeet;
|
||||
} else if (app.type === "office365_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: normalizedCalendarData.create?.uid || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID || calEvent.iCalUID || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.office365Calendar?.url ||
|
||||
"https://UNUSED_URL",
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
iCalUID: normalizedCalendarData.update?.iCalUID,
|
||||
id: normalizedCalendarData.update?.uid || "FALLBACK_MOCK_ID",
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
// A Calendar is always expected to return an id.
|
||||
id: normalizedCalendarData.create?.id || "FALLBACK_MOCK_CALENDAR_EVENT_ID",
|
||||
iCalUID: normalizedCalendarData.create?.iCalUID,
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
location: isGoogleMeetLocation ? "https://UNUSED_URL" : undefined,
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.update?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
conferenceData: isGoogleMeetLocation ? event.conferenceData : undefined,
|
||||
});
|
||||
},
|
||||
deleteEvent: async (...rest: Parameters<Calendar["deleteEvent"]>) => {
|
||||
log.silly("mockCalendar.deleteEvent", JSON.stringify({ rest }));
|
||||
deleteEventCalls.push({
|
||||
args: {
|
||||
uid: rest[0],
|
||||
event: rest[1],
|
||||
externalCalendarId: rest[2],
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
},
|
||||
getAvailability: async (params: {
|
||||
dateFrom: string;
|
||||
dateTo: string;
|
||||
selectedCalendars: IntegrationCalendar[];
|
||||
mode: "slots" | "overlay" | "booking";
|
||||
fallbackToPrimary?: boolean;
|
||||
}): Promise<EventBusyDate[]> => {
|
||||
const { dateFrom, dateTo, selectedCalendars, mode } = params;
|
||||
if (calendarData?.getAvailabilityCrash) {
|
||||
throw new Error("MockCalendarService.getAvailability fake error");
|
||||
}
|
||||
getAvailabilityCalls.push({
|
||||
args: {
|
||||
dateFrom,
|
||||
dateTo,
|
||||
selectedCalendars,
|
||||
mode,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
resolve(calendarData?.busySlots || []);
|
||||
});
|
||||
},
|
||||
listCalendars: async function (): Promise<IntegrationCalendar[]> {
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
} as Calendar;
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
updateEvent: async (...rest: Parameters<Calendar["updateEvent"]>): Promise<NewCalendarEventType> => {
|
||||
if (calendarData?.updationCrash) {
|
||||
throw new Error("MockCalendarService.updateEvent fake error");
|
||||
}
|
||||
const [uid, event, externalCalendarId] = rest;
|
||||
log.silly("mockCalendar.updateEvent", JSON.stringify({ uid, event, externalCalendarId }));
|
||||
updateEventCalls.push({
|
||||
args: {
|
||||
uid,
|
||||
event,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = event.location === BookingLocations.GoogleMeet;
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
iCalUID: normalizedCalendarData.update?.iCalUID,
|
||||
id: normalizedCalendarData.update?.uid || "FALLBACK_MOCK_ID",
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
location: isGoogleMeetLocation ? "https://UNUSED_URL" : undefined,
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.update?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
conferenceData: isGoogleMeetLocation ? event.conferenceData : undefined,
|
||||
});
|
||||
},
|
||||
deleteEvent: async (...rest: Parameters<Calendar["deleteEvent"]>) => {
|
||||
log.silly("mockCalendar.deleteEvent", JSON.stringify({ rest }));
|
||||
deleteEventCalls.push({
|
||||
args: {
|
||||
uid: rest[0],
|
||||
event: rest[1],
|
||||
externalCalendarId: rest[2],
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
},
|
||||
getAvailability: async (params: {
|
||||
dateFrom: string;
|
||||
dateTo: string;
|
||||
selectedCalendars: IntegrationCalendar[];
|
||||
mode: "slots" | "overlay" | "booking";
|
||||
fallbackToPrimary?: boolean;
|
||||
}): Promise<EventBusyDate[]> => {
|
||||
const { dateFrom, dateTo, selectedCalendars, mode } = params;
|
||||
if (calendarData?.getAvailabilityCrash) {
|
||||
throw new Error("MockCalendarService.getAvailability fake error");
|
||||
}
|
||||
getAvailabilityCalls.push({
|
||||
args: {
|
||||
dateFrom,
|
||||
dateTo,
|
||||
selectedCalendars,
|
||||
mode,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
resolve(calendarData?.busySlots || []);
|
||||
});
|
||||
},
|
||||
listCalendars: async (): Promise<IntegrationCalendar[]> => Promise.resolve([]),
|
||||
} as Calendar;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createMocks } from "node-mocks-http";
|
||||
|
||||
import type { CustomNextApiRequest, CustomNextApiResponse } from "./types";
|
||||
|
||||
export function createMockNextJsRequest(...args: Parameters<typeof createMocks>) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import prismaMock from "../__mocks__/prisma";
|
||||
|
||||
import type { InputEventType, getOrganizer, CalendarServiceMethodMock } from "./bookingScenario";
|
||||
|
||||
import type { CalendarServiceMethodMock, getOrganizer, InputEventType } from "./bookingScenario";
|
||||
import { parse } from "node-html-parser";
|
||||
import type { VEvent } from "node-ical";
|
||||
import ical from "node-ical";
|
||||
@@ -9,22 +7,20 @@ import { expect, vi } from "vitest";
|
||||
import "vitest-fetch-mock";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import type { Tracking } from "../types";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type {
|
||||
WebhookTriggerEvents,
|
||||
Booking,
|
||||
BookingReference,
|
||||
DestinationCalendar,
|
||||
WebhookTriggerEvents,
|
||||
} from "@calcom/prisma/client";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import type { AppsStatus } from "@calcom/types/Calendar";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { AppsStatus, CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { CredentialForCalendarService } from "@calcom/types/Credential";
|
||||
import type { Fixtures } from "../fixtures/fixtures";
|
||||
|
||||
import type { Tracking } from "../types";
|
||||
import { DEFAULT_TIMEZONE_BOOKER } from "./getMockRequestDataForBooking";
|
||||
|
||||
// This is too complex at the moment, I really need to simplify this.
|
||||
@@ -123,10 +119,9 @@ expect.extend({
|
||||
|
||||
let isToAddressExpected = true;
|
||||
const isIcsFilenameExpected = expectedEmail.ics ? ics?.filename === expectedEmail.ics.filename : true;
|
||||
const isIcsUIDExpected =
|
||||
expectedEmail.ics && expectedEmail.ics.iCalUID
|
||||
? !!(icsObject ? icsObject[expectedEmail.ics.iCalUID] : null)
|
||||
: true;
|
||||
const isIcsUIDExpected = expectedEmail.ics?.iCalUID
|
||||
? !!(icsObject ? icsObject[expectedEmail.ics.iCalUID] : null)
|
||||
: true;
|
||||
const emailDom = parse(testEmail.html);
|
||||
|
||||
const actualEmailContent = {
|
||||
@@ -1242,7 +1237,7 @@ export function expectSuccessfulCalendarEventCreationInCalendar(
|
||||
| ExpectedForSuccessfulCalendarEventCreationInCalendar
|
||||
| ExpectedForSuccessfulCalendarEventCreationInCalendar[]
|
||||
) {
|
||||
const expecteds = expected instanceof Array ? expected : [expected];
|
||||
const expecteds = Array.isArray(expected) ? expected : [expected];
|
||||
expect(calendarMock.createEventCalls.length).toBe(expecteds.length);
|
||||
|
||||
for (let i = 0; i < calendarMock.createEventCalls.length; i++) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { getDate } from "./bookingScenario";
|
||||
|
||||
import type { Tracking } from "../types";
|
||||
import type { SchedulingType } from "@calcom/prisma/client";
|
||||
import type { CreationSource } from "@calcom/prisma/enums";
|
||||
import type { Tracking } from "../types";
|
||||
|
||||
export const DEFAULT_TIMEZONE_BOOKER = "Asia/Kolkata";
|
||||
export function getBasicMockRequestDataForBooking() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type z from "zod";
|
||||
|
||||
import type { bookingCancelSchema } from "@calcom/prisma/zod-utils";
|
||||
import type z from "zod";
|
||||
|
||||
export function getMockRequestDataForCancelBooking(data: z.infer<typeof bookingCancelSchema>) {
|
||||
return data;
|
||||
|
||||
@@ -1,45 +1,43 @@
|
||||
import { IdentityProvider, UserPermissionRole } from "@calcom/prisma/enums";
|
||||
|
||||
export const getSampleUserInSession = function () {
|
||||
return {
|
||||
locale: "",
|
||||
avatar: "",
|
||||
organization: {
|
||||
isOrgAdmin: false,
|
||||
metadata: null,
|
||||
id: 1,
|
||||
requestedSlug: null,
|
||||
},
|
||||
profile: null,
|
||||
defaultScheduleId: null,
|
||||
name: "",
|
||||
defaultBookerLayouts: null,
|
||||
timeZone: "Asia/Kolkata",
|
||||
selectedCalendars: [],
|
||||
destinationCalendar: null,
|
||||
emailVerified: new Date(),
|
||||
allowDynamicBooking: false,
|
||||
bio: "",
|
||||
weekStart: "",
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
bufferTime: 0,
|
||||
hideBranding: false,
|
||||
timeFormat: 12,
|
||||
twoFactorEnabled: false,
|
||||
identityProvider: IdentityProvider.CAL,
|
||||
brandColor: "#292929",
|
||||
darkBrandColor: "#fafafa",
|
||||
export const getSampleUserInSession = () => ({
|
||||
locale: "",
|
||||
avatar: "",
|
||||
organization: {
|
||||
isOrgAdmin: false,
|
||||
metadata: null,
|
||||
role: UserPermissionRole.USER,
|
||||
disableImpersonation: false,
|
||||
organizationId: null,
|
||||
theme: "",
|
||||
appTheme: "",
|
||||
createdDate: new Date(),
|
||||
trialEndsAt: new Date(),
|
||||
completedOnboarding: false,
|
||||
allowSEOIndexing: false,
|
||||
receiveMonthlyDigestEmail: false,
|
||||
};
|
||||
};
|
||||
id: 1,
|
||||
requestedSlug: null,
|
||||
},
|
||||
profile: null,
|
||||
defaultScheduleId: null,
|
||||
name: "",
|
||||
defaultBookerLayouts: null,
|
||||
timeZone: "Asia/Kolkata",
|
||||
selectedCalendars: [],
|
||||
destinationCalendar: null,
|
||||
emailVerified: new Date(),
|
||||
allowDynamicBooking: false,
|
||||
bio: "",
|
||||
weekStart: "",
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
bufferTime: 0,
|
||||
hideBranding: false,
|
||||
timeFormat: 12,
|
||||
twoFactorEnabled: false,
|
||||
identityProvider: IdentityProvider.CAL,
|
||||
brandColor: "#292929",
|
||||
darkBrandColor: "#fafafa",
|
||||
metadata: null,
|
||||
role: UserPermissionRole.USER,
|
||||
disableImpersonation: false,
|
||||
organizationId: null,
|
||||
theme: "",
|
||||
appTheme: "",
|
||||
createdDate: new Date(),
|
||||
trialEndsAt: new Date(),
|
||||
completedOnboarding: false,
|
||||
allowSEOIndexing: false,
|
||||
receiveMonthlyDigestEmail: false,
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { enableEmailFeature, mockNoTranslations } from "./bookingScenario";
|
||||
|
||||
import { beforeEach, afterEach } from "vitest";
|
||||
import process from "node:process";
|
||||
import { afterEach, beforeEach } from "vitest";
|
||||
|
||||
export function setupAndTeardown() {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { createOrganization } from "./bookingScenario";
|
||||
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { test } from "../fixtures/fixtures";
|
||||
import type { Fixtures } from "../fixtures/fixtures";
|
||||
import { test } from "../fixtures/fixtures";
|
||||
|
||||
type OrgContext = {
|
||||
org: {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// my-test.ts
|
||||
import { test as base } from "vitest";
|
||||
|
||||
import { getTestEmails } from "@calcom/lib/testEmails";
|
||||
import { getTestSMS } from "@calcom/lib/testSMS";
|
||||
import { test as base } from "vitest";
|
||||
|
||||
export interface Fixtures {
|
||||
emails: ReturnType<typeof getEmailsFixture>;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import process from "node:process";
|
||||
import type { CalendarService } from "@calcom/types/Calendar";
|
||||
import matchers from "@testing-library/jest-dom/matchers";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { vi, expect } from "vitest";
|
||||
import { expect, vi } from "vitest";
|
||||
import createFetchMock from "vitest-fetch-mock";
|
||||
|
||||
import type { CalendarService } from "@calcom/types/Calendar";
|
||||
|
||||
global.ResizeObserver = ResizeObserver;
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -32,7 +32,6 @@ fetchMocker.enableMocks();
|
||||
expect.extend(matchers);
|
||||
|
||||
class MockExchangeCalendarService implements CalendarService {
|
||||
constructor() {}
|
||||
async createEvent() {
|
||||
return {
|
||||
uid: "mock",
|
||||
@@ -181,7 +180,6 @@ vi.mock("@calcom/app-store/payment.services.generated", () => ({
|
||||
}));
|
||||
|
||||
class MockCrmService {
|
||||
constructor() {}
|
||||
async createEvent() {
|
||||
return [];
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user