import { BaseE2ETest } from '../../lib/base-test'; import { testData } from '../../config/test-data-helpers'; class DirectoryE2ETest extends BaseE2ETest { // Directory list commands async runListCommand(appId?: string, options?: { allStatuses?: boolean; availability?: string; useShortFlags?: boolean }) { const args = ['directory', 'list']; if (appId) { args.push(appId); } if (options?.allStatuses) { args.push('--allStatuses'); } if (options?.availability) { // Test both short and long forms based on option if (options.useShortFlags) { args.push(`-a=${options.availability}`); } else { args.push(`--availability=${options.availability}`); } } return this.execute(args); } async runInfoCommand(appId: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'info', appId]; if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } async runStatusCommand(appId?: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'status']; if (appId) { args.push(appId); } if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } async runListFunctionsCommand(appId: string, trackerId: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'list-functions', appId, trackerId]; if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } async runListGlobalFunctionsCommand(appId: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'list-global-functions', appId]; if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } async runListInstallsCommand(appVersion: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'list-installs', appVersion]; if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } async runListSourceFunctionsCommand(appId: string, trackerId: string, availability?: string, useShortFlags?: boolean) { const args = ['directory', 'list-source-functions', appId, trackerId]; if (availability) { if (useShortFlags) { args.push(`-a=${availability}`); } else { args.push(`--availability=${availability}`); } } return this.execute(args); } // Public wrapper methods to access protected assertions public checkSuccess(result: any) { this.assertSuccess(result); } public checkFailure(result: any) { this.assertFailure(result); } public checkOutputContains(result: any, text: string) { this.assertOutputContains(result, text); } public checkOutputMatchesBaseline(result: any, baselinePath: string, maxLines?: number) { this.assertOutputMatchesBaseline(result, baselinePath, maxLines); } public clearHistory() { this.cliExecutor.clearProcessHistory(); } public executePublic(args: string[], options?: any) { return this.execute(args, options); } } describe('Directory Commands E2E Tests', () => { let testInstance: DirectoryE2ETest; beforeAll(() => { testInstance = new DirectoryE2ETest(); }); afterAll(async () => { if (testInstance) { await testInstance.cleanup(); } }); afterEach(() => { // Clean up process history after each test if (testInstance) { testInstance.clearHistory(); } }); describe('directory list', () => { it('should list all directory entries successfully', async () => { const result = await testInstance.runListCommand(); if (result.exitCode !== 0) { // only allow failure if the user is not allowed to list all directory entries expect(result.stderr).toContain('Could not authenticate'); } else { // Check baseline format (first 6 lines only - header + 1 entry) testInstance.checkOutputMatchesBaseline(result, 'directory/list.txt', 4); } }, 15000); it('should filter by specific app ID', async () => { const result = await testInstance.runListCommand(testData.appId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); expect(result.stdout).toContain(testData.appId); }); // Temporarily skipped: allStatuses flag is supported but the command doesn't work in staging environment it.skip('should include all statuses when flag is set', async () => { const result = await testInstance.runListCommand(undefined, { allStatuses: true }); // The command might succeed or fail depending on the data, but it should run expect([0, 1]).toContain(result.exitCode); if (result.exitCode === 0) { expect(result.stdout).toBeTruthy(); } }); it('should work with availability zone parameter', async () => { const result = await testInstance.runListCommand(undefined, { availability: 'us' }); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runListCommand(undefined, { availability: 'us', useShortFlags: true }); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runListCommand(undefined, { availability: 'us', useShortFlags: false }); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); // Temporarily skipped: allStatuses flag is supported but the command doesn't work in staging environment it.skip('should work with multiple flags (allStatuses + availability)', async () => { const result = await testInstance.runListCommand(undefined, { allStatuses: true, availability: 'us' }); // The command might succeed or fail depending on the data, but it should run expect([0, 1]).toContain(result.exitCode); if (result.exitCode === 0) { expect(result.stdout).toBeTruthy(); } }); // Temporarily skipped: allStatuses flag is supported but the command doesn't work in staging environment it.skip('should work with multiple flags using short form for availability', async () => { const result = await testInstance.runListCommand(undefined, { allStatuses: true, availability: 'us', useShortFlags: true }); // The command might succeed or fail depending on the data, but it should run expect([0, 1]).toContain(result.exitCode); if (result.exitCode === 0) { expect(result.stdout).toBeTruthy(); } }); it('should complete within reasonable time', async () => { const result = await testInstance.runListCommand(testData.appId); expect(result.executionTime).toBeLessThan(15000); // 15 seconds expect(result.timedOut).toBe(false); }); }); describe('directory info', () => { it('should return app information for valid app ID', async () => { const result = await testInstance.runInfoCommand(testData.appId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); // Check baseline format (first 12 lines only - header + General section + first version) testInstance.checkOutputMatchesBaseline(result, 'directory/info.txt', 12); }, 15000); it('should work with availability zone parameter', async () => { const result = await testInstance.runInfoCommand(testData.appId, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runInfoCommand(testData.appId, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runInfoCommand(testData.appId, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should handle non-existent app ID gracefully', async () => { const result = await testInstance.runInfoCommand('nonexistent-app-id'); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should fail when app ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'info']); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); }); describe('directory status', () => { it('should return status for valid app ID and version', async () => { const result = await testInstance.runStatusCommand(testData.appVersionString); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); // Check for status information expect(result.stdout).toContain('Version state:'); }); it('should work with availability zone parameter', async () => { const result = await testInstance.runStatusCommand(testData.appVersionString, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runStatusCommand(testData.appVersionString, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runStatusCommand(testData.appVersionString, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should fail when app ID and version are missing', async () => { const result = await testInstance.runStatusCommand(); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); // The error could be about missing app.yaml or missing parameters expect(result.stderr).toMatch(/App ID and version are required|app manifest|app\.yaml/); }); it('should handle invalid app version format', async () => { const result = await testInstance.runStatusCommand('invalid-format'); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); }); describe('directory list-functions', () => { it('should list functions for valid app and tracker ID', async () => { const result = await testInstance.runListFunctionsCommand(testData.appId, testData.trackerId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter', async () => { const result = await testInstance.runListFunctionsCommand(testData.appId, testData.trackerId, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runListFunctionsCommand(testData.appId, testData.trackerId, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runListFunctionsCommand(testData.appId, testData.trackerId, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should fail when app ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-functions']); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should fail when tracker ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-functions', testData.appId]); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should handle non-existent app installation gracefully', async () => { const result = await testInstance.runListFunctionsCommand('nonexistent-app', 'nonexistent-tracker'); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); }); describe('directory list-global-functions', () => { it('should list global functions for valid app ID', async () => { const result = await testInstance.runListGlobalFunctionsCommand(testData.appId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter', async () => { const result = await testInstance.runListGlobalFunctionsCommand(testData.appId, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runListGlobalFunctionsCommand(testData.appId, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runListGlobalFunctionsCommand(testData.appId, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should fail when app ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-global-functions']); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should handle non-existent app ID gracefully', async () => { const result = await testInstance.runListGlobalFunctionsCommand('nonexistent-app-id'); // The command may succeed with empty results or fail - both are acceptable expect(result.exitCode).toBeDefined(); expect(result.stdout).toBeDefined(); }); }); describe('directory list-installs', () => { it('should list installations for valid app version', async () => { const result = await testInstance.runListInstallsCommand(testData.appVersionString); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); // Check for table headers - use the actual headers from output expect(result.stdout).toMatch(/Tracker/); expect(result.stdout).toContain('Created At'); expect(result.stdout).toContain('Updated At'); }); it('should list installations for app without version', async () => { const result = await testInstance.runListInstallsCommand(testData.appId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter', async () => { const result = await testInstance.runListInstallsCommand(testData.appVersionString, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runListInstallsCommand(testData.appVersionString, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runListInstallsCommand(testData.appVersionString, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should fail when app version parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-installs']); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should handle non-existent app gracefully', async () => { const result = await testInstance.runListInstallsCommand('nonexistent-app@1.0.0'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); // Should return empty results or appropriate message }); }); describe('directory list-source-functions', () => { it('should list source functions for valid app and tracker ID', async () => { const result = await testInstance.runListSourceFunctionsCommand(testData.appId, testData.trackerId); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter', async () => { const result = await testInstance.runListSourceFunctionsCommand(testData.appId, testData.trackerId, 'us'); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (short form)', async () => { const result = await testInstance.runListSourceFunctionsCommand(testData.appId, testData.trackerId, 'us', true); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should work with availability zone parameter (long form)', async () => { const result = await testInstance.runListSourceFunctionsCommand(testData.appId, testData.trackerId, 'us', false); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should fail when app ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-source-functions']); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should fail when tracker ID parameter is missing', async () => { const result = await testInstance.executePublic(['directory', 'list-source-functions', testData.appId]); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); it('should handle non-existent app installation gracefully', async () => { const result = await testInstance.runListSourceFunctionsCommand('nonexistent-app', 'nonexistent-tracker'); expect(result.exitCode).not.toBe(0); expect(result.stderr).toBeTruthy(); }); }); describe('Flag Variations', () => { describe('availability flag variations', () => { it('should accept availability flag in various formats (short form with =)', async () => { const result = await testInstance.executePublic(['directory', 'list', '-a=us']); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should accept availability flag in various formats (long form with =)', async () => { const result = await testInstance.executePublic(['directory', 'list', '--availability=us']); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); }); // Temporarily skipped: allStatuses flag is supported but the command doesn't work in staging environment describe.skip('allStatuses flag variations', () => { it('should accept allStatuses flag (long form)', async () => { const result = await testInstance.executePublic(['directory', 'list', '--allStatuses']); // The command might succeed or fail depending on the data, but it should run expect([0, 1]).toContain(result.exitCode); }); it('should work with combined flags (allStatuses + availability short form)', async () => { const result = await testInstance.executePublic(['directory', 'list', '--allStatuses', '-a=us']); expect([0, 1]).toContain(result.exitCode); }); it('should work with combined flags (allStatuses + availability long form)', async () => { const result = await testInstance.executePublic(['directory', 'list', '--allStatuses', '--availability=us']); expect([0, 1]).toContain(result.exitCode); }); it('should work with combined flags in different order', async () => { const result = await testInstance.executePublic(['directory', 'list', '--availability=us', '--allStatuses']); expect([0, 1]).toContain(result.exitCode); }); }); describe('flag validation and error handling', () => { it('should handle invalid availability values gracefully', async () => { const result = await testInstance.executePublic(['directory', 'list', '--availability=invalid']); // Should either succeed with default behavior or fail gracefully expect(result.exitCode).toBeDefined(); }); it('should handle duplicate flags gracefully (last one wins)', async () => { const result = await testInstance.executePublic(['directory', 'list', '--availability=eu', '--availability=us']); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); it('should handle mixed short and long forms of same flag', async () => { const result = await testInstance.executePublic(['directory', 'list', '-a=eu', '--availability=us']); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); }); }); describe('comprehensive flag testing across directory commands', () => { it('should test info command with all flag variations', async () => { const flagVariations = [ ['directory', 'info', testData.appId, '-a=us'], ['directory', 'info', testData.appId, '--availability=us'] ]; for (const args of flagVariations) { const result = await testInstance.executePublic(args); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); } }); it('should test status command with all flag variations', async () => { const flagVariations = [ ['directory', 'status', testData.appVersionString, '-a=us'], ['directory', 'status', testData.appVersionString, '--availability=us'] ]; for (const args of flagVariations) { const result = await testInstance.executePublic(args); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); } }); it('should test list-installs command with all flag variations', async () => { const flagVariations = [ ['directory', 'list-installs', testData.appVersionString, '-a=us'], ['directory', 'list-installs', testData.appVersionString, '--availability=us'] ]; for (const args of flagVariations) { const result = await testInstance.executePublic(args); expect(result.exitCode).toBe(0); expect(result.stdout).toBeTruthy(); } }); }); }); describe('Error Scenarios', () => { it('should handle malformed availability zone parameter', async () => { const result = await testInstance.runListCommand(undefined, { availability: 'invalid-zone' }); // The command might still succeed but with default zone behavior // Or it might fail - depends on API validation expect(result.exitCode).toBeDefined(); }); }); describe('Performance Tests', () => { it('should complete directory list within reasonable time', async () => { const result = await testInstance.runListCommand(); expect(result.executionTime).toBeLessThan(20000); // 20 seconds expect(result.executionTime).toBeGreaterThan(0); }, 25000); it('should complete directory info within reasonable time', async () => { const result = await testInstance.runInfoCommand(testData.appId); expect(result.executionTime).toBeLessThan(10000); // 10 seconds expect(result.timedOut).toBe(false); }, 15000); it('should complete function listings within reasonable time', async () => { const result = await testInstance.runListGlobalFunctionsCommand(testData.appId); expect(result.executionTime).toBeLessThan(10000); // 10 seconds expect(result.timedOut).toBe(false); }, 15000); }); });