UNPKG

@posthog/wizard

Version:

The PostHog wizard helps you to configure your project

208 lines (200 loc) 9.48 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs = __importStar(require("fs")); const path_1 = __importDefault(require("path")); const add_editor_rules_1 = require("../add-editor-rules"); const analytics_1 = require("../../utils/analytics"); const clack_1 = __importDefault(require("../../utils/clack")); const chalk_1 = __importDefault(require("chalk")); // Mock dependencies jest.mock('fs', () => ({ promises: { mkdir: jest.fn(), readFile: jest.fn(), writeFile: jest.fn(), }, })); jest.mock('../../utils/analytics', () => ({ analytics: { capture: jest.fn(), setTag: jest.fn(), shutdown: jest.fn().mockResolvedValue(undefined), }, })); jest.mock('../../utils/clack', () => ({ log: { info: jest.fn(), }, select: jest.fn().mockResolvedValue(true), isCancel: jest.fn((value) => false), cancel: jest.fn(), })); describe('addEditorRules', () => { const mockOptions = { installDir: '/test/dir', rulesName: 'react-rules.md', integration: 'react', }; const originalEnv = process.env; const mkdirMock = fs.promises.mkdir; const readFileMock = fs.promises.readFile; const writeFileMock = fs.promises.writeFile; // eslint-disable-next-line @typescript-eslint/unbound-method const captureMock = analytics_1.analytics.capture; const infoMock = clack_1.default.log.info; const selectMock = clack_1.default.select; const isCancelMock = clack_1.default.isCancel; const cancelMock = clack_1.default.cancel; beforeEach(() => { // Reset all mocks before each test jest.clearAllMocks(); // Clear mock implementations fs.promises.mkdir.mockReset(); fs.promises.readFile.mockReset(); fs.promises.writeFile.mockReset(); selectMock.mockReset(); selectMock.mockResolvedValue(true); // Default to "Yes" for the prompt isCancelMock.mockReset(); isCancelMock.mockReturnValue(false); cancelMock.mockReset(); process.env = { ...originalEnv }; }); afterAll(() => { process.env = originalEnv; }); it('should not install rules when CURSOR_TRACE_ID is not set', async () => { delete process.env.CURSOR_TRACE_ID; await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions); expect(mkdirMock).not.toHaveBeenCalled(); expect(readFileMock).not.toHaveBeenCalled(); expect(writeFileMock).not.toHaveBeenCalled(); expect(captureMock).not.toHaveBeenCalled(); expect(infoMock).not.toHaveBeenCalled(); }); it('should install rules when CURSOR_TRACE_ID is set', async () => { process.env.CURSOR_TRACE_ID = 'test-trace-id'; const mockFrameworkRules = 'framework rules {universal} content'; const mockUniversalRules = 'universal rules content'; const expectedCombinedRules = 'framework rules universal rules content content'; fs.promises.readFile .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules)) .mockImplementationOnce(() => Promise.resolve(mockUniversalRules)); await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions); // Check if directory was created expect(mkdirMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules'), { recursive: true }); // Check if correct files were read expect(readFileMock).toHaveBeenCalledTimes(2); expect(readFileMock).toHaveBeenNthCalledWith(1, expect.stringMatching(/react-rules\.md$/), 'utf8'); expect(readFileMock).toHaveBeenNthCalledWith(2, expect.stringMatching(/universal\.md$/), 'utf8'); // Check if combined rules were written correctly expect(writeFileMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'), expectedCombinedRules, 'utf8'); // Check if analytics were captured expect(captureMock).toHaveBeenCalledWith('wizard interaction', { action: 'added editor rules', integration: mockOptions.integration, }); // Check if success message was logged expect(infoMock).toHaveBeenCalledWith(`Added Cursor rules to ${chalk_1.default.bold.cyan('.cursor/rules/posthog-integration.mdc')}`); }); it('should handle file system errors gracefully', async () => { process.env.CURSOR_TRACE_ID = 'test-trace-id'; const mockError = new Error('File not found'); // Mock readFile to throw an error fs.promises.readFile.mockRejectedValue(mockError); await expect((0, add_editor_rules_1.addEditorRulesStep)(mockOptions)).rejects.toThrow(mockError); expect(writeFileMock).not.toHaveBeenCalled(); expect(captureMock).not.toHaveBeenCalled(); expect(infoMock).not.toHaveBeenCalled(); }); it('should handle missing rules files gracefully', async () => { process.env.CURSOR_TRACE_ID = 'test-trace-id'; const mockError = new Error('File system error'); // Mock mkdir to throw an error fs.promises.mkdir.mockRejectedValue(mockError); await expect((0, add_editor_rules_1.addEditorRulesStep)(mockOptions)).rejects.toThrow(mockError); expect(writeFileMock).not.toHaveBeenCalled(); expect(captureMock).not.toHaveBeenCalled(); expect(infoMock).not.toHaveBeenCalled(); }); it('should correctly substitute universal rules with realistic content', async () => { process.env.CURSOR_TRACE_ID = 'test-trace-id'; const mockFrameworkRules = `--- description: apply when interacting with PostHog/analytics tasks globs: alwaysApply: true --- {universal} # Framework-specific rules - Rule 1 - Rule 2`; const mockUniversalRules = `Never hallucinate an API key. Instead, always use the API key populated in the .env file. # Feature flags A given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code.`; const expectedCombinedRules = `--- description: apply when interacting with PostHog/analytics tasks globs: alwaysApply: true --- Never hallucinate an API key. Instead, always use the API key populated in the .env file. # Feature flags A given feature flag should be used in as few places as possible. Do not increase the risk of undefined behavior by scattering the same feature flag across multiple areas of code. # Framework-specific rules - Rule 1 - Rule 2`; fs.promises.readFile .mockImplementationOnce(() => Promise.resolve(mockFrameworkRules)) .mockImplementationOnce(() => Promise.resolve(mockUniversalRules)); await (0, add_editor_rules_1.addEditorRulesStep)(mockOptions); // Check if directory was created expect(mkdirMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules'), { recursive: true }); // Check if correct files were read expect(readFileMock).toHaveBeenCalledWith(expect.stringMatching(/react-rules\.md$/), 'utf8'); expect(readFileMock).toHaveBeenCalledWith(expect.stringMatching(/universal\.md$/), 'utf8'); // Check if combined rules were written correctly expect(writeFileMock).toHaveBeenCalledWith(path_1.default.join('/test/dir', '.cursor', 'rules', 'posthog-integration.mdc'), expectedCombinedRules, 'utf8'); // Check if analytics were captured expect(captureMock).toHaveBeenCalledWith('wizard interaction', { action: 'added editor rules', integration: mockOptions.integration, }); // Check if success message was logged expect(infoMock).toHaveBeenCalledWith(`Added Cursor rules to ${chalk_1.default.bold.cyan('.cursor/rules/posthog-integration.mdc')}`); }); }); //# sourceMappingURL=add-editor-rules.test.js.map