UNPKG

@redocly/cli

Version:

[@Redocly](https://redocly.com) CLI is your all-in-one OpenAPI utility. It builds, manages, improves, and quality-checks your OpenAPI descriptions, all of which comes in handy for various phases of the API Lifecycle. Create your own rulesets to make API g

316 lines (315 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs = require("fs"); const path = require("path"); const push_1 = require("../push"); const api_1 = require("../../api"); const remotes = { push: jest.fn(), upsert: jest.fn(), getDefaultBranch: jest.fn(), }; jest.mock('@redocly/openapi-core', () => ({ slash: jest.fn().mockImplementation((p) => p), })); jest.mock('../../api', () => ({ ...jest.requireActual('../../api'), ReuniteApi: jest.fn().mockImplementation(function (...args) { this.remotes = remotes; this.reportSunsetWarnings = jest.fn(); }), })); describe('handlePush()', () => { let pathResolveSpy; let pathRelativeSpy; let pathDirnameSpy; let fsStatSyncSpy; let fsReaddirSyncSpy; beforeEach(() => { remotes.getDefaultBranch.mockResolvedValueOnce('test-default-branch'); remotes.upsert.mockResolvedValueOnce({ id: 'test-remote-id', mountPath: 'test-mount-path' }); remotes.push.mockResolvedValueOnce({ branchName: 'uploaded-to-branch', id: 'test-id' }); jest.spyOn(fs, 'createReadStream').mockReturnValue('stream'); pathResolveSpy = jest.spyOn(path, 'resolve'); pathRelativeSpy = jest.spyOn(path, 'relative'); pathDirnameSpy = jest.spyOn(path, 'dirname'); fsStatSyncSpy = jest.spyOn(fs, 'statSync'); fsReaddirSyncSpy = jest.spyOn(fs, 'readdirSync'); }); afterEach(() => { pathResolveSpy.mockRestore(); pathRelativeSpy.mockRestore(); pathDirnameSpy.mockRestore(); fsStatSyncSpy.mockRestore(); fsReaddirSyncSpy.mockRestore(); }); it('should upload files', async () => { const mockConfig = { apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; fsStatSyncSpy.mockReturnValueOnce({ isDirectory() { return false; }, }); pathResolveSpy.mockImplementationOnce((p) => p); pathRelativeSpy.mockImplementationOnce((_, p) => p); pathDirnameSpy.mockImplementation((_) => '.'); await (0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', organization: 'test-org', project: 'test-project', branch: 'test-branch', namespace: 'test-namespace', repository: 'test-repository', 'commit-sha': 'test-commit-sha', 'commit-url': 'test-commit-url', 'default-branch': 'test-branch', 'created-at': 'test-created-at', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', files: ['test-file'], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(remotes.getDefaultBranch).toHaveBeenCalledWith('test-org', 'test-project'); expect(remotes.upsert).toHaveBeenCalledWith('test-org', 'test-project', { mountBranchName: 'test-default-branch', mountPath: 'test-mount-path', }); expect(remotes.push).toHaveBeenCalledWith('test-org', 'test-project', { isMainBranch: true, remoteId: 'test-remote-id', commit: { message: 'Test message', branchName: 'test-branch', createdAt: 'test-created-at', namespace: 'test-namespace', repository: 'test-repository', sha: 'test-commit-sha', url: 'test-commit-url', author: { name: 'TestAuthor', email: 'test-author@mail.com', }, }, }, [ { path: 'test-file', stream: 'stream', }, ]); }); it('should return push id', async () => { const mockConfig = { apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; fsStatSyncSpy.mockReturnValueOnce({ isDirectory() { return false; }, }); pathResolveSpy.mockImplementationOnce((p) => p); pathRelativeSpy.mockImplementationOnce((_, p) => p); pathDirnameSpy.mockImplementation((_) => '.'); const result = await (0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', organization: 'test-org', project: 'test-project', branch: 'test-branch', namespace: 'test-namespace', repository: 'test-repository', 'commit-sha': 'test-commit-sha', 'commit-url': 'test-commit-url', 'default-branch': 'test-branch', 'created-at': 'test-created-at', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', files: ['test-file'], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(result).toEqual({ pushId: 'test-id' }); }); it('should collect files from directory and preserve file structure', async () => { const mockConfig = { apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; /* ├── app │ ├── index.html ├── openapi.yaml └── some-ref.yaml */ fsStatSyncSpy.mockImplementation((filePath) => ({ isDirectory() { return filePath === 'test-folder' || filePath === 'test-folder/app'; }, })); fsReaddirSyncSpy.mockImplementation((dirPath) => { if (dirPath === 'test-folder') { return ['app', 'another-ref.yaml', 'openapi.yaml']; } if (dirPath === 'test-folder/app') { return ['index.html']; } throw new Error('Not a directory'); }); await (0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', organization: 'test-org', project: 'test-project', branch: 'test-branch', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', 'default-branch': 'main', files: ['test-folder'], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(remotes.push).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.anything(), [ { path: 'app/index.html', stream: 'stream', }, { path: 'another-ref.yaml', stream: 'stream', }, { path: 'openapi.yaml', stream: 'stream', }, ]); }); it('should not upload files if no files passed', async () => { const mockConfig = { apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; await (0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', organization: 'test-org', project: 'test-project', branch: 'test-branch', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', 'default-branch': 'main', files: [], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(remotes.getDefaultBranch).not.toHaveBeenCalled(); expect(remotes.upsert).not.toHaveBeenCalled(); expect(remotes.push).not.toHaveBeenCalled(); }); it('should get organization from config if not passed', async () => { const mockConfig = { organization: 'test-org-from-config', apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; fsStatSyncSpy.mockReturnValueOnce({ isDirectory() { return false; }, }); pathResolveSpy.mockImplementationOnce((p) => p); pathRelativeSpy.mockImplementationOnce((_, p) => p); pathDirnameSpy.mockImplementation((_) => '.'); await (0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', project: 'test-project', branch: 'test-branch', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', files: ['test-file'], 'default-branch': 'main', 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(remotes.getDefaultBranch).toHaveBeenCalledWith('test-org-from-config', expect.anything()); expect(remotes.upsert).toHaveBeenCalledWith('test-org-from-config', expect.anything(), expect.anything()); expect(remotes.push).toHaveBeenCalledWith('test-org-from-config', expect.anything(), expect.anything(), expect.anything()); }); it('should get domain from env if not passed', async () => { const mockConfig = { organization: 'test-org-from-config', apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; process.env.REDOCLY_DOMAIN = 'test-domain-from-env'; fsStatSyncSpy.mockReturnValueOnce({ isDirectory() { return false; }, }); pathResolveSpy.mockImplementationOnce((p) => p); pathRelativeSpy.mockImplementationOnce((_, p) => p); pathDirnameSpy.mockImplementation((_) => '.'); await (0, push_1.handlePush)({ argv: { 'mount-path': 'test-mount-path', project: 'test-project', branch: 'test-branch', 'default-branch': 'main', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', files: ['test-file'], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', }); expect(api_1.ReuniteApi).toBeCalledWith({ domain: 'test-domain-from-env', apiKey: 'test-api-key', version: 'cli-version', command: 'push', }); }); it('should print error message', async () => { const mockConfig = { apis: {} }; process.env.REDOCLY_AUTHORIZATION = 'test-api-key'; remotes.push.mockRestore(); remotes.push.mockRejectedValueOnce(new api_1.ReuniteApiError('Deprecated.', 412)); fsStatSyncSpy.mockReturnValueOnce({ isDirectory() { return false; }, }); pathResolveSpy.mockImplementationOnce((p) => p); pathRelativeSpy.mockImplementationOnce((_, p) => p); pathDirnameSpy.mockImplementation((_) => '.'); expect((0, push_1.handlePush)({ argv: { domain: 'test-domain', 'mount-path': 'test-mount-path', organization: 'test-org', project: 'test-project', branch: 'test-branch', namespace: 'test-namespace', repository: 'test-repository', 'commit-sha': 'test-commit-sha', 'commit-url': 'test-commit-url', 'default-branch': 'test-branch', 'created-at': 'test-created-at', author: 'TestAuthor <test-author@mail.com>', message: 'Test message', files: ['test-file'], 'max-execution-time': 10, }, config: mockConfig, version: 'cli-version', })).rejects.toThrow('✗ File upload failed. Reason: Deprecated.'); }); });