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
4 changes: 2 additions & 2 deletions packages/cli/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"format:check": "prettier --check --ignore-unknown --ignore-path ../../../shared/.prettierignore \"**\"",
"lint:eslint": "eslint --max-warnings 0 . --ignore-pattern=../../../.eslintignore",
"lint:eslint:fix": "pnpm lint:eslint --fix",
"publish:cli:dev": "npm publish ./dist/dev",
"publish:cli:prod": "npm publish ./dist/prod",
"publish:cli:dev": "pnpm publish ./dist/dev --no-git-checks",
"publish:cli:prod": "pnpm publish ./dist/prod --no-git-checks",
"test": "vitest --passWithNoTests --run",
"test:debug": "pnpm run test --inspect --no-file-parallelism",
"test:update": "vitest --passWithNoTests --run -u"
Expand Down
35 changes: 21 additions & 14 deletions packages/cli/ete-tests/src/tests/docs-dev/docsDev.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ describe.sequential("fern docs dev --legacy", () => {
cwd: join(fixturesDir, RelativeFilePath.of("simple"))
});

await sleep(20_000);

const response = await fetch("http://localhost:3000/v2/registry/docs/load-with-url", {
const response = await waitForServer("http://localhost:3000/v2/registry/docs/load-with-url", {
method: "POST"
});

Expand All @@ -36,7 +34,7 @@ describe.sequential("fern docs dev --legacy", () => {
// kill the process
const finishProcess = process.kill();
expect(finishProcess).toBeTruthy();
}, 30_000);
}, 90_000);
});

describe.sequential("fern docs dev --beta", () => {
Expand All @@ -53,9 +51,7 @@ describe.sequential("fern docs dev --beta", () => {
reject: true
});

await sleep(40_000);

const response = await fetch("http://localhost:3001/v2/registry/docs/load-with-url", {
const response = await waitForServer("http://localhost:3001/v2/registry/docs/load-with-url", {
method: "POST"
});

Expand All @@ -70,7 +66,7 @@ describe.sequential("fern docs dev --beta", () => {

const finishProcess = process.kill();
expect(finishProcess).toBeTruthy();
}, 50_000);
}, 90_000);
});

describe.sequential("fern docs dev", () => {
Expand All @@ -85,9 +81,7 @@ describe.sequential("fern docs dev", () => {
cwd: join(fixturesDir, RelativeFilePath.of("simple"))
});

await sleep(40_000);

const response = await fetch("http://localhost:3002/v2/registry/docs/load-with-url", {
const response = await waitForServer("http://localhost:3002/v2/registry/docs/load-with-url", {
method: "POST"
});

Expand All @@ -99,9 +93,22 @@ describe.sequential("fern docs dev", () => {
expect(typeof responseBody === "object").toEqual(true);
// biome-ignore lint/suspicious/noExplicitAny: allow explicit any
expect(Object.keys(responseBody as any)).toEqual(["baseUrl", "definition", "lightModeEnabled", "orgId"]);
}, 50_000);
}, 90_000);
});

function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
async function waitForServer(
url: string,
init: Parameters<typeof fetch>[1],
{ interval = 1_000, timeout = 60_000 }: { interval?: number; timeout?: number } = {}
): Promise<Awaited<ReturnType<typeof fetch>>> {
const deadline = Date.now() + timeout;
while (Date.now() < deadline) {
try {
return await fetch(url, init);
} catch {
await new Promise((resolve) => setTimeout(resolve, interval));
}
}
// Final attempt – let it throw if the server is still unreachable
return await fetch(url, init);
}
4 changes: 2 additions & 2 deletions packages/cli/ete-tests/src/tests/generate/fernignore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Practice schema-first API design with Fern

describe("fern generate --local", () => {
// eslint-disable-next-line jest/expect-expect
it("Keep files listed in .fernignore from unmodified", async () => {
it.concurrent("Keep files listed in .fernignore from unmodified", async () => {
const pathOfDirectory = await init();
await runFernCli(["generate", "--local", "--keepDocker"], {
cwd: pathOfDirectory
Expand Down Expand Up @@ -61,7 +61,7 @@ describe("fern generate --local", () => {
}, 360_000);

// eslint-disable-next-line jest/expect-expect
it("Prevent initial generation of files listed in .fernignore", async () => {
it.concurrent("Prevent initial generation of files listed in .fernignore", async () => {
const pathOfDirectory = await init();

// Create output directory with .fernignore BEFORE first generation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import tmp from "tmp-promise";
import { runFernCli } from "../../utils/runFernCli.js";

describe("fern generate with settings", () => {
it("single api", async () => {
it.concurrent("single api", async ({ expect }) => {
const fixturesDir = join(AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures/api-settings"));

const tmpDir = await tmp.dir();
Expand All @@ -22,7 +22,7 @@ describe("fern generate with settings", () => {
).toMatchSnapshot();
}, 180_000);

it("dependencies-based api", async () => {
it.concurrent("dependencies-based api", async ({ expect }) => {
const fixturesDir = join(AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures/api-settings-unioned"));
const tmpDir = await tmp.dir();
const directory = AbsoluteFilePath.of(tmpDir.path);
Expand Down
25 changes: 12 additions & 13 deletions packages/cli/ete-tests/src/tests/generate/generate.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { AbsoluteFilePath, doesPathExist, join, RelativeFilePath } from "@fern-api/fs-utils";
import { exec } from "child_process";
import stripAnsi from "strip-ansi";
import { vi } from "vitest";

import { runFernCli, runFernCliWithoutAuthToken } from "../../utils/runFernCli.js";
import { init } from "../init/init.js";

const fixturesDir = join(AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures"));

describe("fern generate", () => {
it("default api (fern init)", async () => {
it.concurrent("default api (fern init)", async () => {
const pathOfDirectory = await init();

await runFernCli(["generate", "--local", "--keepDocker"], {
Expand All @@ -19,7 +18,7 @@ describe("fern generate", () => {
expect(await doesPathExist(join(pathOfDirectory, RelativeFilePath.of("sdks/typescript")))).toBe(true);
}, 180_000);

it("ir contains fdr definitionid", async () => {
it.concurrent("ir contains fdr definitionid", async () => {
const { stdout, stderr } = await runFernCli(["generate", "--log-level", "debug"], {
cwd: join(fixturesDir, RelativeFilePath.of("basic")),
reject: false
Expand Down Expand Up @@ -67,33 +66,33 @@ describe("fern generate", () => {
).toMatchSnapshot();
}, 180_000);

it("generate docs with no auth requires login", async () => {
vi.stubEnv("FERN_TOKEN", undefined);
it.concurrent("generate docs with no auth requires login", async () => {
const { stdout, stderr } = await runFernCliWithoutAuthToken(["generate", "--docs"], {
cwd: join(fixturesDir, RelativeFilePath.of("docs")),
reject: false
reject: false,
env: {
FERN_TOKEN: ""
}
});
const output = stdout + stderr;
expect(output).toContain(
"Authentication required. Please run 'fern login' or set the FERN_TOKEN environment variable."
);
}, 180_000);

it("generate docs with auth bypass fails", async () => {
vi.stubEnv("FERN_TOKEN", undefined);
it.concurrent("generate docs with auth bypass fails", async () => {
const { stdout } = await runFernCliWithoutAuthToken(["generate", "--docs"], {
cwd: join(fixturesDir, RelativeFilePath.of("docs")),
reject: false,
env: {
FERN_SELF_HOSTED: "true"
FERN_SELF_HOSTED: "true",
FERN_TOKEN: ""
}
});
expect(stdout).toContain("No token found. Please set the FERN_TOKEN environment variable.");
}, 180_000);

it("generate docs with auth bypass succeeds", async () => {
vi.stubEnv("FERN_TOKEN", "dummy");

it.concurrent("generate docs with auth bypass succeeds", async () => {
const { stdout } = await runFernCliWithoutAuthToken(["generate", "--docs"], {
cwd: join(fixturesDir, RelativeFilePath.of("docs")),
reject: false,
Expand All @@ -105,7 +104,7 @@ describe("fern generate", () => {
expect(stdout).toContain("ferndevtest.docs.dev.buildwithfern.com Started.");
}, 180_000);

it("generate docs with no docs.yml file fails", async () => {
it.concurrent("generate docs with no docs.yml file fails", async () => {
const { stdout } = await runFernCli(["generate", "--docs"], {
cwd: join(fixturesDir, RelativeFilePath.of("basic")),
reject: false
Expand Down
18 changes: 9 additions & 9 deletions packages/cli/ete-tests/src/tests/init/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import { init } from "./init.js";
const FIXTURES_DIR = join(AbsoluteFilePath.of(__dirname), RelativeFilePath.of("fixtures"));

describe("fern init", () => {
it("no existing fern directory", async () => {
it.concurrent("no existing fern directory", async ({ expect }) => {
const pathOfDirectory = await init();
expect(
await getDirectoryContentsForSnapshot(join(pathOfDirectory, RelativeFilePath.of(FERN_DIRECTORY)))
).toMatchSnapshot();
}, 60_000);

it("no existing fern directory with fern definition", async () => {
it.concurrent("no existing fern directory with fern definition", async ({ expect }) => {
const pathOfDirectory = await init({
additionalArgs: [{ name: "--fern-definition" }]
});
Expand All @@ -34,7 +34,7 @@ describe("fern init", () => {
).toMatchSnapshot();
}, 60_000);

it("existing fern directory", async () => {
it.concurrent("existing fern directory", async ({ expect }) => {
// add existing directory
const pathOfDirectory = await init({
additionalArgs: [{ name: "--fern-definition" }]
Expand All @@ -57,7 +57,7 @@ describe("fern init", () => {
).toBe(true);
}, 60_000);

it("init openapi", async () => {
it.concurrent("init openapi", async ({ expect }) => {
// Create a temporary directory for the OpenAPI test
const tmpDir = await tmp.dir();
const sourceOpenAPI = join(
Expand All @@ -78,7 +78,7 @@ describe("fern init", () => {
expect(await getDirectoryContentsForSnapshot(pathOfDirectory)).toMatchSnapshot();
}, 60_000);

it("existing openapi fern directory", async () => {
it.concurrent("existing openapi fern directory", async ({ expect }) => {
const pathOfDirectory = await init();

await init({
Expand Down Expand Up @@ -128,7 +128,7 @@ describe("fern init", () => {
).toBe(true);
}, 60_000);

it("existing openapi then fern-definition", async () => {
it.concurrent("existing openapi then fern-definition", async ({ expect }) => {
const pathOfDirectory = await init();

await init({
Expand Down Expand Up @@ -159,7 +159,7 @@ describe("fern init", () => {
).toBe(true);
}, 60_000);

it("conflicting --openapi and --fern-definition flags", async () => {
it.concurrent("conflicting --openapi and --fern-definition flags", async ({ expect }) => {
const tmpDir = await tmp.dir();
const sourceOpenAPI = join(
FIXTURES_DIR,
Expand All @@ -179,7 +179,7 @@ describe("fern init", () => {
expect(result.exitCode).not.toBe(0);
}, 60_000);

it("init docs", async () => {
it.concurrent("init docs", async ({ expect }) => {
const pathOfDirectory = await init({
additionalArgs: [{ name: "--fern-definition" }]
});
Expand All @@ -191,7 +191,7 @@ describe("fern init", () => {
expect(await getDirectoryContentsForSnapshot(pathOfDirectory)).toMatchSnapshot();
}, 60_000);

it("init mintlify", async () => {
it.concurrent("init mintlify", async ({ expect }) => {
const mintJsonPath = join(FIXTURES_DIR, RelativeFilePath.of("mintlify"), RelativeFilePath.of("mint.json"));

const pathOfDirectory = await init({
Expand Down
10 changes: 6 additions & 4 deletions packages/cli/ete-tests/src/tests/ir/generateIrAsString.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { generatorsYml } from "@fern-api/configuration";
import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils";
import { readFile, rm } from "fs/promises";
import { AbsoluteFilePath } from "@fern-api/fs-utils";
import { readFile } from "fs/promises";
import tmp from "tmp-promise";

import { runFernCli } from "../../utils/runFernCli.js";

Expand All @@ -17,8 +18,8 @@ export async function generateIrAsString({
apiName?: string;
version?: string;
}): Promise<string> {
const irOutputPath = join(fixturePath, RelativeFilePath.of("ir.json"));
await rm(irOutputPath, { force: true, recursive: true });
const tmpFile = await tmp.file({ postfix: ".json" });
const irOutputPath = AbsoluteFilePath.of(tmpFile.path);

const command = ["ir", irOutputPath];
if (language != null) {
Expand All @@ -42,5 +43,6 @@ export async function generateIrAsString({
});

const irContents = await readFile(irOutputPath);
await tmpFile.cleanup();
return irContents.toString();
}
17 changes: 11 additions & 6 deletions packages/cli/ete-tests/src/tests/ir/ir.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { generatorsYml } from "@fern-api/configuration";
import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils";
import { readFile } from "fs/promises";
import path from "path";
import tmp from "tmp-promise";
import { runFernCli } from "../../utils/runFernCli.js";
import { generateIrAsString } from "./generateIrAsString.js";

Expand Down Expand Up @@ -69,9 +70,9 @@ interface Fixture {
describe("ir", () => {
for (const fixture of FIXTURES) {
const { only = false } = fixture;
(only ? it.only : it)(
(only ? it.only : it.concurrent)(
`${JSON.stringify(fixture)}`,
async () => {
async ({ expect }) => {
const fixturePath = join(FIXTURES_DIR, RelativeFilePath.of(fixture.name));
const irContents = await generateIrAsString({
fixturePath,
Expand All @@ -86,19 +87,23 @@ describe("ir", () => {
);
}

it("works with latest version", async () => {
const { stdout } = await runFernCli(["ir", "ir.json", "--version", "v27"], {
it.concurrent("works with latest version", async ({ expect }) => {
const tmpFile = await tmp.file({ postfix: ".json" });
const { stdout } = await runFernCli(["ir", tmpFile.path, "--version", "v27"], {
cwd: join(FIXTURES_DIR, RelativeFilePath.of("migration")),
reject: false
});
await tmpFile.cleanup();
expect(stdout).toContain("Wrote IR to");
}, 10_000);

it("fails with invalid version", async () => {
const { stdout } = await runFernCli(["ir", "ir.json", "--version", "v100"], {
it.concurrent("fails with invalid version", async ({ expect }) => {
const tmpFile = await tmp.file({ postfix: ".json" });
const { stdout } = await runFernCli(["ir", tmpFile.path, "--version", "v100"], {
cwd: join(FIXTURES_DIR, RelativeFilePath.of("migration")),
reject: false
});
await tmpFile.cleanup();
expect(stdout).toContain("IR v100 does not exist");
}, 10_000);
});
Expand Down
Loading
Loading