UNPKG

n8n-nodes-awx

Version:

n8n node to interact with Ansible AWX/Tower with improved type safety

295 lines 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const JobResources_1 = require("../src/resources/JobResources"); const mockApiClient = { get: jest.fn(), post: jest.fn(), put: jest.fn(), delete: jest.fn(), }; jest.mock('../src/ApiClient', () => { return jest.fn().mockImplementation(() => mockApiClient); }); const createMockJob = (overrides = {}) => ({ id: 100, type: 'job', url: '/api/v2/jobs/100/', related: { job_template: '/api/v2/job_templates/42/', cancel: '/api/v2/jobs/100/cancel/', stdout: '/api/v2/jobs/100/stdout/', }, summary_fields: { job_template: { id: 42, name: 'Deploy Web Application' }, inventory: { id: 15, name: 'Production Servers' }, project: { id: 10, name: 'Web App Project' }, created_by: { username: 'admin', id: 1 }, credentials: [ { id: 5, name: 'AWS Production', credential_type: 1 } ] }, name: 'Deploy Web Application', description: 'Deploy the web application to production', job_type: 'run', status: 'successful', failed: false, started: '2023-04-15T10:00:00Z', finished: '2023-04-15T10:05:00Z', elapsed: 300, job_template: 42, inventory: 15, project: 10, playbook: 'deploy.yml', scm_revision: 'a1b2c3d4', execution_environment: null, execution_node: 'node1.example.com', result_stdout: 'PLAY [Deploy web application] ***************************************', result_traceback: '', job_slice_number: 0, job_slice_count: 1, job_explanation: '', allow_simultaneous: false, artifacts: {}, scm_branch: 'main', webhook_service: null, webhook_credential: null, webhook_guid: null, diff_mode: false, job_vars: {}, limit: 'all', extra_vars: '{}', job_tags: '', skip_tags: '', force_handlers: false, start_at_task: null, timeout: 0, use_fact_cache: false, organization: 1, scm_type: 'git', job_slice: null, job_args: '', job_cwd: '', job_env: {}, job_status: 'successful', result_stdout_file: '/api/v2/jobs/100/stdout/', event_processing_finished: true, hosts: {}, event_data: {}, playbook_counts: { play_count: 1, task_count: 5, role_count: 0, handler_count: 1, }, custom_virtualenv: null, instance_group: 1, diff: false, host_status_counts: { ok: 5, failures: 0, dark: 0, changed: 2, skipped: 0, rescued: 0, ignored: 0, }, ...overrides }); describe('JobResources', () => { let jobResources; beforeEach(() => { jest.clearAllMocks(); jobResources = new JobResources_1.JobResources(mockApiClient); mockApiClient.get.mockImplementation((url) => { if (url.includes('/api/v2/jobs/')) { if (url.includes('name=')) { return Promise.resolve({ data: { count: 1, next: null, previous: null, results: [createMockJob()] } }); } else if (url.endsWith('/stdout/')) { return Promise.resolve({ data: 'Mocked job output\nLine 1\nLine 2\nLine 3' }); } else if (url.match(/\/api\/v2\/jobs\/\d+\/$/)) { return Promise.resolve({ data: createMockJob() }); } return Promise.resolve({ data: { count: 1, next: null, previous: null, results: [createMockJob()] } }); } return Promise.reject(new Error(`Unexpected URL: ${url}`)); }); mockApiClient.post.mockImplementation((url) => { if (url.endsWith('/cancel/')) { return Promise.resolve({ data: createMockJob({ status: 'canceled', finished: new Date().toISOString() }) }); } return Promise.reject(new Error(`Unexpected URL: ${url}`)); }); }); describe('list', () => { it('should list all jobs', async () => { const jobs = await jobResources.list(); expect(jobs).toBeInstanceOf(Array); expect(jobs).toHaveLength(1); expect(jobs[0]).toMatchObject({ id: 100, name: 'Deploy Web Application', status: 'successful' }); expect(mockApiClient.get).toHaveBeenCalledWith('/api/v2/jobs/'); }); it('should support filtering parameters', async () => { await jobResources.list({ name: 'Deploy', status: 'successful' }); expect(mockApiClient.get).toHaveBeenCalledWith(expect.stringContaining('name=Deploy&status=successful')); }); }); describe('get', () => { it('should get a job by ID', async () => { const job = await jobResources.get(100); expect(job).toBeDefined(); expect(job.id).toBe(100); expect(job.name).toBe('Deploy Web Application'); expect(mockApiClient.get).toHaveBeenCalledWith('/api/v2/jobs/100/'); }); it('should throw an error if job ID is not provided', async () => { await expect(jobResources.get(0)).rejects.toThrow('Job ID is required'); }); }); describe('getByName', () => { it('should get a job by name', async () => { const job = await jobResources.getByName('Deploy Web Application'); expect(job).toBeDefined(); expect(job === null || job === void 0 ? void 0 : job.id).toBe(100); expect(job === null || job === void 0 ? void 0 : job.name).toBe('Deploy Web Application'); expect(mockApiClient.get).toHaveBeenCalledWith(expect.stringContaining('name=Deploy%20Web%20Application')); }); it('should return null if job is not found', async () => { mockApiClient.get.mockResolvedValueOnce({ data: { count: 0, results: [] } }); const job = await jobResources.getByName('Nonexistent Job'); expect(job).toBeNull(); }); it('should throw an error if multiple jobs are found', async () => { mockApiClient.get.mockResolvedValueOnce({ data: { count: 2, results: [ createMockJob({ id: 100 }), createMockJob({ id: 101 }) ] } }); await expect(jobResources.getByName('Duplicate Job')).rejects.toThrow('Multiple jobs found with name: Duplicate Job'); }); }); describe('cancel', () => { it('should cancel a running job', async () => { const canceledJob = await jobResources.cancel(100); expect(canceledJob).toBeDefined(); expect(canceledJob.status).toBe('canceled'); expect(mockApiClient.post).toHaveBeenCalledWith('/api/v2/jobs/100/cancel/', {}); }); it('should throw an error when job ID is 0', async () => { await expect(jobResources.cancel(0)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is undefined', async () => { await expect(jobResources.cancel(undefined)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is null', async () => { await expect(jobResources.cancel(null)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is NaN', async () => { await expect(jobResources.cancel(NaN)).rejects.toThrow('Job ID is required'); }); }); describe('getStdout', () => { it('should get job stdout', async () => { const stdout = await jobResources.getStdout(100); expect(stdout).toBe('Mocked job output\nLine 1\nLine 2\nLine 3'); expect(mockApiClient.get).toHaveBeenCalledWith('/api/v2/jobs/100/stdout/'); }); it('should throw an error when job ID is 0', async () => { await expect(jobResources.getStdout(0)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is undefined', async () => { await expect(jobResources.getStdout(undefined)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is null', async () => { await expect(jobResources.getStdout(null)).rejects.toThrow('Job ID is required'); }); it('should throw an error when job ID is NaN', async () => { await expect(jobResources.getStdout(NaN)).rejects.toThrow('Job ID is required'); }); }); describe('buildUrl', () => { const testBuildUrl = (jobResources, path, params) => { const resourcesWithPrivate = jobResources; return resourcesWithPrivate.buildUrl(path, params); }; it('should return the path when no params are provided', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/'); expect(result).toBe('/api/v2/jobs/'); }); it('should handle empty params object', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/', {}); expect(result).toBe('/api/v2/jobs/'); }); it('should handle null params', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/', null); expect(result).toBe('/api/v2/jobs/'); }); it('should append query parameters correctly', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/', { name: 'test job', status: 'successful', page: 1 }); expect(result).toContain('name=test%20job'); expect(result).toContain('status=successful'); expect(result).toContain('page=1'); expect(result).toMatch(/^\/api\/v2\/jobs\/\?.*/); }); it('should handle special characters in parameters', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/', { search: 'job@example.com', filter: 'status=running&name=test' }); expect(result).toContain('search=job%40example.com'); expect(result).toContain('filter=status%3Drunning%26name%3Dtest'); }); it('should handle undefined and null parameter values', () => { const result = testBuildUrl(jobResources, '/api/v2/jobs/', { name: 'test', status: undefined, filter: null }); expect(result).toContain('name=test'); expect(result).not.toContain('status='); expect(result).not.toContain('filter='); }); }); }); //# sourceMappingURL=JobResources.test.js.map