Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cli/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Test environment variables for CLI tests
# Replace these values with your test environment values

OTTO_SERVER_URL=https://acme-dev.ottomatic.cloud
OTTO_ADMIN_API_KEY=ak_rSvHqOI5nFIKjVDNjn16wzo2MvdlI4Wl
FM_DATA_API_KEY=dk_fptdBZ9fSxUoVbwNikFX83Q5qS2u2lw9
FM_FILE_NAME=Foxtail_Demo.fmp12
FM_LAYOUT_NAME=API_Customers
7 changes: 6 additions & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
"release": "changeset version",
"pub:beta": "pnpm build && npm publish --tag beta --access public",
"pub:next": "pnpm build && npm publish --tag next --access public",
"pub:release": "pnpm build && npm publish --access public"
"pub:release": "pnpm build && npm publish --access public",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
},
"dependencies": {
"@clack/core": "^0.3.4",
Expand Down Expand Up @@ -112,6 +115,8 @@
"tsup": "^6.7.0",
"type-fest": "^3.13.1",
"typescript": "^5.6.3",
"vitest": "^1.4.0",
"@vitest/coverage-v8": "^1.4.0",
"zod": "^3.23.8"
}
}
File renamed without changes.
4 changes: 2 additions & 2 deletions cli/template/nextjs/src/utils/notification-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function showErrorNotification(message: string): void;
export function showErrorNotification(args?: string | NotificationData): void {
const message =
typeof args === "string" ? args : "An unexpected error occurred.";
const defaultProps = typeof args === "string" ? {} : args ?? {};
const defaultProps = typeof args === "string" ? {} : (args ?? {});

showNotification({ color: "red", title: "Error", message, ...defaultProps });
}
Expand All @@ -21,7 +21,7 @@ export function showSuccessNotification(
args?: string | NotificationData
): void {
const message = typeof args === "string" ? args : "Success!";
const defaultProps = typeof args === "string" ? {} : args ?? {};
const defaultProps = typeof args === "string" ? {} : (args ?? {});

showNotification({
color: "green",
Expand Down
4 changes: 2 additions & 2 deletions cli/template/vite-wv/src/utils/notification-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function showErrorNotification(message: string): void;
export function showErrorNotification(args?: string | NotificationData): void {
const message =
typeof args === "string" ? args : "An unexpected error occurred.";
const defaultProps = typeof args === "string" ? {} : args ?? {};
const defaultProps = typeof args === "string" ? {} : (args ?? {});

showNotification({ color: "red", title: "Error", message, ...defaultProps });
}
Expand All @@ -21,7 +21,7 @@ export function showSuccessNotification(
args?: string | NotificationData,
): void {
const message = typeof args === "string" ? args : "Success!";
const defaultProps = typeof args === "string" ? {} : args ?? {};
const defaultProps = typeof args === "string" ? {} : (args ?? {});

showNotification({
color: "green",
Expand Down
89 changes: 89 additions & 0 deletions cli/tests/browser-apps.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { execSync } from "child_process";
import { existsSync, mkdirSync, readFileSync } from "fs";
import { join } from "path";
import { beforeEach, describe, expect, it } from "vitest";
import { z } from "zod";

import { verifyProjectBuilds } from "./test-utils";

describe("Non-Interactive CLI Tests", () => {
// Use root-level tmp directory for test outputs
const testDir = join(__dirname, "..", "..", "tmp", "cli-tests");
const cliPath = join(__dirname, "..", "dist", "index.js");

// Parse test environment variables
const testEnv = z
.object({
OTTO_SERVER_URL: z.string().url(),
OTTO_ADMIN_API_KEY: z.string().min(1),
FM_DATA_API_KEY: z.string().min(1),
FM_FILE_NAME: z.string().min(1),
FM_LAYOUT_NAME: z.string().min(1),
})
.parse(process.env);

beforeEach(() => {
// Ensure the test directory exists
mkdirSync(testDir, { recursive: true });
});

it("should create a project with FileMaker integration in CI mode", () => {
const projectName = "test-fm-project";

// Build the command with all necessary flags for non-interactive mode
const command = [
`node "${cliPath}" init`,
projectName,
"--ci",
"--appType browser",
"--dataSource filemaker",
`--server "${testEnv.OTTO_SERVER_URL}"`,
`--adminApiKey "${testEnv.OTTO_ADMIN_API_KEY}"`,
`--dataApiKey "${testEnv.FM_DATA_API_KEY}"`,
`--fileName "${testEnv.FM_FILE_NAME}"`,
`--layoutName "${testEnv.FM_LAYOUT_NAME}"`,
"--noGit", // Skip git initialization for testing
].join(" ");

// Execute the command
expect(() => {
execSync(command, {
cwd: testDir,
env: {
...process.env,
CI: "true",
},
encoding: "utf-8",
});
}).not.toThrow();

const projectDir = join(testDir, projectName);

// Verify project structure
expect(existsSync(projectDir)).toBe(true);
expect(existsSync(join(projectDir, "package.json"))).toBe(true);
expect(existsSync(join(projectDir, "proofkit.json"))).toBe(true);
expect(existsSync(join(projectDir, ".env"))).toBe(true);

// Verify package.json content
const pkgJson = JSON.parse(
readFileSync(join(projectDir, "package.json"), "utf-8")
);
expect(pkgJson.name).toBe(projectName);

// Verify proofkit.json content
const proofkitConfig = JSON.parse(
readFileSync(join(projectDir, "proofkit.json"), "utf-8")
);
expect(proofkitConfig.appType).toBe("browser");
expect(proofkitConfig.dataSources).toContainEqual(
expect.objectContaining({
type: "fm",
name: "filemaker",
})
);

// Verify the project can be built successfully
verifyProjectBuilds(projectDir);
});
});
22 changes: 22 additions & 0 deletions cli/tests/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { execSync } from "child_process";
import { describe, expect, it } from "vitest";

describe("CLI Basic Tests", () => {
it("should show help without throwing", () => {
expect(() => {
execSync("node ../dist/index.js --help", {
cwd: __dirname,
encoding: "utf-8",
});
}).not.toThrow();
});

it("should be executable", () => {
expect(() => {
execSync("node ../dist/index.js --version", {
cwd: __dirname,
encoding: "utf-8",
});
}).not.toThrow();
});
});
12 changes: 12 additions & 0 deletions cli/tests/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { execSync } from "child_process";
import path, { join } from "path";
import dotenv from "dotenv";
import { beforeAll } from "vitest";

beforeAll(() => {
// Ensure test environment variables are loaded
dotenv.config({ path: path.resolve(__dirname, "../.env.test") });
});

// Build the CLI before running any tests
execSync("pnpm build", { cwd: join(__dirname, "..") });
38 changes: 38 additions & 0 deletions cli/tests/test-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { execSync } from "child_process";

/**
* Verifies that a project at the given directory can be built without errors
* @param projectDir The directory containing the project to build
* @throws If the build fails
*/
export function verifyProjectBuilds(projectDir: string): void {
console.log(`\nVerifying project build in ${projectDir}...`);

try {
console.log("Installing dependencies...");
// Run pnpm install while ignoring workspace settings
execSync("pnpm install --prefer-offline --ignore-workspace", {
cwd: projectDir,
stdio: "inherit",
encoding: "utf-8",
env: {
...process.env,
PNPM_DEBUG: "1", // Enable debug logging
},
});

console.log("Building project...");
execSync("pnpm build", {
cwd: projectDir,
stdio: "inherit",
encoding: "utf-8",
env: {
...process.env,
NEXT_TELEMETRY_DISABLED: "1",
},
});
} catch (error) {
console.error("Build process failed:", error);
throw error;
}
}
19 changes: 19 additions & 0 deletions cli/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import path from "path";
import dotenv from "dotenv";
import { defineConfig } from "vitest/config";

// Load test environment variables
dotenv.config({ path: path.resolve(__dirname, ".env.test") });

export default defineConfig({
test: {
globals: true,
environment: "node",
setupFiles: ["./tests/setup.ts"],
include: ["tests/**/*.test.ts"],
coverage: {
provider: "v8",
reporter: ["text", "json", "html"],
},
},
});
Loading