// ---------------------------------------------------------------------------// GraphQL plugin — `configureAuth` (custom auth method merge-append) coverage.//// `configureAuth` merge-appends apikey/oauth2 methods onto an existing// integration's opaque `authenticationTemplate`. These tests exercise the// extension method directly (the same path the HTTP `configure` handler calls):// - round-trip: add a custom apikey method → `getConfig` shows it,// - append: a configured method does not drop the integration's existing// declared methods,// - slug generation: a method with a blank slug is assigned `custom_<id>`,// - dedupe: a matching slug replaces in place; two slug-less methods in one// call get distinct generated slugs,// - unknown slug is a no-op (returns []).// --------------------------------------------------------------------------- import { describe, expect, it } from "@effect/vitest";import { Effect } from "effect"; import { createExecutor } from "@executor-js/sdk";import { makeTestConfig, memoryCredentialsPlugin } from "@executor-js/sdk/testing"; import { graphqlPlugin } from "./plugin";import type { GraphqlAuthMethod } from "./types"; const makeExecutor = () => createExecutor( makeTestConfig({ plugins: [memoryCredentialsPlugin(), graphqlPlugin()] as const, }), ); const customApiKey: GraphqlAuthMethod = { slug: "my_custom", kind: "apikey", placements: [{ carrier: "header", name: "X-Api-Key" }],}; describe("GraphQL Plugin — configureAuth (custom auth method)", () => { it.effect("adds a custom apiKey method and getConfig reflects it", () => Effect.gen(function* () { const executor = yield* makeExecutor(); yield* executor.graphql.addIntegration({ endpoint: "https://x.example/graphql", slug: "cfg_api", }); const merged = yield* executor.graphql.configureAuth("cfg_api", { authenticationTemplate: [customApiKey], }); expect(merged).toHaveLength(1); expect(merged[0]!.slug).toBe("my_custom"); const config = yield* executor.graphql.getConfig("cfg_api"); const template = config?.authenticationTemplate ?? []; expect(template).toEqual([ { slug: "my_custom", kind: "apikey", placements: [{ carrier: "header", name: "X-Api-Key" }], }, ]); }), ); it.effect("appends to an existing declared template without dropping entries", () => Effect.gen(function* () { const executor = yield* makeExecutor(); yield* executor.graphql.addIntegration({ endpoint: "https://x.example/graphql", slug: "cfg_append", authenticationTemplate: [ { slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] }, ], }); const merged = yield* executor.graphql.configureAuth("cfg_append", { authenticationTemplate: [customApiKey], }); expect(merged.map((m: GraphqlAuthMethod) => m.slug)).toEqual(["seed", "my_custom"]); }), ); it.effect("generates a custom_<id> slug for a method submitted with a blank slug", () => Effect.gen(function* () { const executor = yield* makeExecutor(); yield* executor.graphql.addIntegration({ endpoint: "https://x.example/graphql", slug: "cfg_genslug", }); const merged = yield* executor.graphql.configureAuth("cfg_genslug", { authenticationTemplate: [ { slug: "", kind: "apikey", placements: [{ carrier: "header", name: "X-Api-Key" }] }, ], }); expect(merged).toHaveLength(1); expect(merged[0]!.slug).toMatch(/^custom_[a-z0-9]+$/); }), ); it.effect("dedupes: a matching slug replaces in place; two slug-less get distinct slugs", () => Effect.gen(function* () { const executor = yield* makeExecutor(); yield* executor.graphql.addIntegration({ endpoint: "https://x.example/graphql", slug: "cfg_dedupe", authenticationTemplate: [customApiKey], }); const merged = yield* executor.graphql.configureAuth("cfg_dedupe", { authenticationTemplate: [ // Re-submit the same slug with a different placement → replace in place. { slug: "my_custom", kind: "apikey", placements: [{ carrier: "header", name: "X-Other" }], }, { slug: "", kind: "apikey", placements: [{ carrier: "query", name: "api_key" }] }, { slug: "", kind: "apikey", placements: [{ carrier: "query", name: "token" }] }, ], }); const slugs = merged.map((m: GraphqlAuthMethod) => m.slug); expect(slugs.filter((s: string) => s === "my_custom")).toHaveLength(1); expect(merged).toHaveLength(3); const generated = slugs.filter((s: string) => s.startsWith("custom_")); expect(generated).toHaveLength(2); expect(new Set(generated).size).toBe(2); const replaced = merged.find((m: GraphqlAuthMethod) => m.slug === "my_custom")!; expect(replaced).toEqual({ slug: "my_custom", kind: "apikey", placements: [{ carrier: "header", name: "X-Other" }], }); }), ); it.effect("replace mode overwrites the auth template array", () => Effect.gen(function* () { const executor = yield* makeExecutor(); yield* executor.graphql.addIntegration({ endpoint: "https://x.example/graphql", slug: "cfg_replace", authenticationTemplate: [ { slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] }, customApiKey, ], }); const merged = yield* executor.graphql.configureAuth("cfg_replace", { authenticationTemplate: [ { slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] }, ], mode: "replace", }); expect(merged.map((m: GraphqlAuthMethod) => m.slug)).toEqual(["seed"]); }), ); it.effect("configureAuth is a no-op for an unknown integration", () => Effect.gen(function* () { const executor = yield* makeExecutor(); const merged = yield* executor.graphql.configureAuth("nope", { authenticationTemplate: [customApiKey], }); expect(merged).toEqual([]); }), ); it.effect("getConfig returns null for an unknown integration", () => Effect.gen(function* () { const executor = yield* makeExecutor(); expect(yield* executor.graphql.getConfig("nope")).toBeNull(); }), );});
// ---------------------------------------------------------------------------
// GraphQL plugin — `configureAuth` (custom auth method merge-append) coverage.
//
// `configureAuth` merge-appends apikey/oauth2 methods onto an existing
// integration's opaque `authenticationTemplate`. These tests exercise the
// extension method directly (the same path the HTTP `configure` handler calls):
// - round-trip: add a custom apikey method → `getConfig` shows it,
// - append: a configured method does not drop the integration's existing
// declared methods,
// - slug generation: a method with a blank slug is assigned `custom_<id>`,
// - dedupe: a matching slug replaces in place; two slug-less methods in one
// call get distinct generated slugs,
// - unknown slug is a no-op (returns []).
// ---------------------------------------------------------------------------
import { describe, expect, it } from "@effect/vitest";
import { Effect } from "effect";
import { createExecutor } from "@executor-js/sdk";
import { makeTestConfig, memoryCredentialsPlugin } from "@executor-js/sdk/testing";
import { graphqlPlugin } from "./plugin";
import type { GraphqlAuthMethod } from "./types";
const makeExecutor = () =>
createExecutor(
makeTestConfig({
plugins: [memoryCredentialsPlugin(), graphqlPlugin()] as const,
}),
);
const customApiKey: GraphqlAuthMethod = {
slug: "my_custom",
kind: "apikey",
placements: [{ carrier: "header", name: "X-Api-Key" }],
};
describe("GraphQL Plugin — configureAuth (custom auth method)", () => {
it.effect("adds a custom apiKey method and getConfig reflects it", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
yield* executor.graphql.addIntegration({
endpoint: "https://x.example/graphql",
slug: "cfg_api",
});
const merged = yield* executor.graphql.configureAuth("cfg_api", {
authenticationTemplate: [customApiKey],
});
expect(merged).toHaveLength(1);
expect(merged[0]!.slug).toBe("my_custom");
const config = yield* executor.graphql.getConfig("cfg_api");
const template = config?.authenticationTemplate ?? [];
expect(template).toEqual([
{
slug: "my_custom",
kind: "apikey",
placements: [{ carrier: "header", name: "X-Api-Key" }],
},
]);
}),
);
it.effect("appends to an existing declared template without dropping entries", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
yield* executor.graphql.addIntegration({
endpoint: "https://x.example/graphql",
slug: "cfg_append",
authenticationTemplate: [
{ slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] },
],
});
const merged = yield* executor.graphql.configureAuth("cfg_append", {
authenticationTemplate: [customApiKey],
});
expect(merged.map((m: GraphqlAuthMethod) => m.slug)).toEqual(["seed", "my_custom"]);
}),
);
it.effect("generates a custom_<id> slug for a method submitted with a blank slug", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
yield* executor.graphql.addIntegration({
endpoint: "https://x.example/graphql",
slug: "cfg_genslug",
});
const merged = yield* executor.graphql.configureAuth("cfg_genslug", {
authenticationTemplate: [
{ slug: "", kind: "apikey", placements: [{ carrier: "header", name: "X-Api-Key" }] },
],
});
expect(merged).toHaveLength(1);
expect(merged[0]!.slug).toMatch(/^custom_[a-z0-9]+$/);
}),
);
it.effect("dedupes: a matching slug replaces in place; two slug-less get distinct slugs", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
yield* executor.graphql.addIntegration({
endpoint: "https://x.example/graphql",
slug: "cfg_dedupe",
authenticationTemplate: [customApiKey],
});
const merged = yield* executor.graphql.configureAuth("cfg_dedupe", {
authenticationTemplate: [
// Re-submit the same slug with a different placement → replace in place.
{
slug: "my_custom",
kind: "apikey",
placements: [{ carrier: "header", name: "X-Other" }],
},
{ slug: "", kind: "apikey", placements: [{ carrier: "query", name: "api_key" }] },
{ slug: "", kind: "apikey", placements: [{ carrier: "query", name: "token" }] },
],
});
const slugs = merged.map((m: GraphqlAuthMethod) => m.slug);
expect(slugs.filter((s: string) => s === "my_custom")).toHaveLength(1);
expect(merged).toHaveLength(3);
const generated = slugs.filter((s: string) => s.startsWith("custom_"));
expect(generated).toHaveLength(2);
expect(new Set(generated).size).toBe(2);
const replaced = merged.find((m: GraphqlAuthMethod) => m.slug === "my_custom")!;
expect(replaced).toEqual({
slug: "my_custom",
kind: "apikey",
placements: [{ carrier: "header", name: "X-Other" }],
});
}),
);
it.effect("replace mode overwrites the auth template array", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
yield* executor.graphql.addIntegration({
endpoint: "https://x.example/graphql",
slug: "cfg_replace",
authenticationTemplate: [
{ slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] },
customApiKey,
],
});
const merged = yield* executor.graphql.configureAuth("cfg_replace", {
authenticationTemplate: [
{ slug: "seed", kind: "apikey", placements: [{ carrier: "header", name: "X-Seed" }] },
],
mode: "replace",
});
expect(merged.map((m: GraphqlAuthMethod) => m.slug)).toEqual(["seed"]);
}),
);
it.effect("configureAuth is a no-op for an unknown integration", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
const merged = yield* executor.graphql.configureAuth("nope", {
authenticationTemplate: [customApiKey],
});
expect(merged).toEqual([]);
}),
);
it.effect("getConfig returns null for an unknown integration", () =>
Effect.gen(function* () {
const executor = yield* makeExecutor();
expect(yield* executor.graphql.getConfig("nope")).toBeNull();
}),
);
});