UNPKG

@prismatic-io/spectral

Version:

Utility library for building Prismatic connectors and code-native integrations

168 lines (167 loc) 8.63 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * Verifies what spectral serializes for the inline-action example-perform fields * on publish — the converted server component `prism component publish` sends. * * Scope is conversion output only: which fields land on the wire, with what values. * It does not verify runtime dispatch (SAFE vs. NOT_ALLOWED choosing * which perform runs) — the safety flags are inert metadata, converted from the * author-facing camelCase values to the platform's GraphQL enum names, and the * runner decides at execution time. */ const ejs_1 = require("ejs"); const path_1 = __importDefault(require("path")); const vitest_1 = require("vitest"); const helpers_1 = require("../generators/componentManifest/helpers"); const index_1 = require("../index"); const display = (label) => ({ label, description: label }); // Three input shapes exercised on every permutation. const connectionInput = (0, index_1.input)({ label: "Connection", type: "connection", required: true }); const structuredInput = (0, index_1.structuredObjectInput)({ label: "Name", inputs: { first: (0, index_1.input)({ type: "string", label: "First", required: true }), last: (0, index_1.input)({ type: "string", label: "Last", required: true }), }, }); const collectionInput = (0, index_1.input)({ label: "Tags", type: "string", collection: "valuelist" }); const sharedInputs = { connection: connectionInput, name: structuredInput, tags: collectionInput, }; const noop = () => __awaiter(void 0, void 0, void 0, function* () { return ({ data: null }); }); const echo = (_ctx, params) => __awaiter(void 0, void 0, void 0, function* () { return ({ data: params }); }); // Action permutations. const testComponent = (0, index_1.component)({ key: "inline-action-testbed", public: false, display: Object.assign(Object.assign({}, display("Inline Action Testbed")), { iconPath: "icon.png" }), actions: { // A — no inline-calling fields. plainAction: (0, index_1.action)({ display: display("Plain Action"), inputs: sharedInputs, perform: noop, }), // B — example perform. examplePerformAction: (0, index_1.action)({ display: display("Example Perform Action"), inputs: sharedInputs, perform: noop, examplePerform: echo, }), // C — real perform marked runnable. runnablePerformAction: (0, index_1.action)({ display: display("Runnable Perform Action"), inputs: sharedInputs, perform: noop, performSafety: index_1.PerformSafety.SAFE, }), // D — real perform marked not runnable. notAllowedPerformAction: (0, index_1.action)({ display: display("Not Allowed Perform Action"), inputs: sharedInputs, perform: noop, performSafety: index_1.PerformSafety.NOT_ALLOWED, }), }, }); // Converted actions are keyed by action key. const actionsByKey = testComponent.actions; (0, vitest_1.describe)("inline action calling: publish-wire conversion output", () => { (0, vitest_1.it)("A — plain action: no inline-calling fields leak onto the wire", () => { const a = actionsByKey.plainAction; (0, vitest_1.expect)("examplePerform" in a).toBe(false); (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined(); (0, vitest_1.expect)(a.performSafety).toBeUndefined(); }); (0, vitest_1.it)("B — example perform is wrapped (invokable) and implies a SAFE safety flag", () => __awaiter(void 0, void 0, void 0, function* () { var _a; const a = actionsByKey.examplePerformAction; (0, vitest_1.expect)(typeof a.examplePerform).toBe("function"); (0, vitest_1.expect)(a.examplePerformSafety).toBe("SAFE"); // The example flag must not imply anything about the real perform. (0, vitest_1.expect)(a.performSafety).toBeUndefined(); // Wrapped fn is invokable and passes params through. const result = yield ((_a = a.examplePerform) === null || _a === void 0 ? void 0 : _a.call(a, {}, { tags: ["x"] })); (0, vitest_1.expect)(result.data.tags).toStrictEqual(["x"]); })); (0, vitest_1.it)("C — real-perform SAFE flag carried; no separate example perform", () => { const a = actionsByKey.runnablePerformAction; (0, vitest_1.expect)(a.performSafety).toBe("SAFE"); (0, vitest_1.expect)("examplePerform" in a).toBe(false); (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined(); }); (0, vitest_1.it)("D — real-perform notAllowed converts to NOT_ALLOWED; no example perform", () => { const a = actionsByKey.notAllowedPerformAction; (0, vitest_1.expect)(a.performSafety).toBe("NOT_ALLOWED"); (0, vitest_1.expect)("examplePerform" in a).toBe(false); (0, vitest_1.expect)(a.examplePerformSafety).toBeUndefined(); }); (0, vitest_1.it)("the three input shapes survive conversion on every permutation", () => { for (const key of [ "plainAction", "examplePerformAction", "runnablePerformAction", "notAllowedPerformAction", ]) { const inputs = actionsByKey[key].inputs; const byKey = Object.fromEntries(inputs.map((i) => [i.key, i])); (0, vitest_1.expect)(byKey.connection.type).toBe("connection"); (0, vitest_1.expect)(byKey.name.type).toBe("structuredObject"); (0, vitest_1.expect)(byKey.name.inputs).toHaveLength(2); // nested children survived (0, vitest_1.expect)(byKey.tags.collection).toBe("valuelist"); } }); }); (0, vitest_1.describe)("inline action calling: component-manifest emit", () => { const templatePath = path_1.default.join(__dirname, "../generators/componentManifest/templates/actions/action.ts.ejs"); const baseAction = { typeInterface: "DoThing", import: "doThing", key: "doThing", label: "Do Thing", description: "Does a thing.", inputs: [], componentKey: "testbed", }; const render = (extra) => (0, ejs_1.renderFile)(templatePath, { action: Object.assign(Object.assign({}, baseAction), extra), helpers: helpers_1.helpers, imports: {} }); (0, vitest_1.it)("emits both *Safety scalars when present", () => __awaiter(void 0, void 0, void 0, function* () { const out = yield render({ examplePerformSafety: "safe", performSafety: "notAllowed", }); (0, vitest_1.expect)(out).toContain('examplePerformSafety: "safe"'); (0, vitest_1.expect)(out).toContain('performSafety: "notAllowed"'); })); (0, vitest_1.it)("emits a notAllowed performSafety scalar", () => __awaiter(void 0, void 0, void 0, function* () { const out = yield render({ performSafety: "notAllowed" }); (0, vitest_1.expect)(out).toContain('performSafety: "notAllowed"'); })); (0, vitest_1.it)("omits the *Safety scalars when absent (permutation A)", () => __awaiter(void 0, void 0, void 0, function* () { const out = yield render({}); (0, vitest_1.expect)(out).not.toContain("examplePerformSafety"); (0, vitest_1.expect)(out).not.toContain("performSafety"); })); (0, vitest_1.it)("never emits an examplePerform stub (invoked via the server action, not the manifest)", () => __awaiter(void 0, void 0, void 0, function* () { const out = yield render({ examplePerformSafety: "safe", performSafety: "notAllowed", }); (0, vitest_1.expect)(out).not.toContain("examplePerform:"); })); });