diff --git a/AGENTS.md b/AGENTS.md index d9d125e..b7c3b97 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,4 +5,6 @@ - For the happy path, can we have a single unit test where all the top level if conditions are executed? This might help with reducing the number of total unit tests created and still give same test coverage. - For the tests for edge cases do not create separate describe blocks, keep the hierarchy flat. - For the tests for edge cases, do not skip assertions, its still worth adding all assertions similar to the happy paths tests. +- Use only jest for writing test cases and refer existing unit test under the /src folder. +- Do not create code comments for any changes. diff --git a/src/adapters/file-upload.test.ts b/src/adapters/file-upload.test.ts new file mode 100644 index 00000000..37d9304 --- /dev/null +++ b/src/adapters/file-upload.test.ts @@ -0,0 +1,319 @@ +import FileUpload from './file-upload'; +import BaseClass from './base-class'; +import { cliux } from '@contentstack/cli-utilities'; +import { DeploymentStatus } from '../types/launch'; + +jest.mock('@contentstack/cli-utilities', () => ({ + ...jest.requireActual('@contentstack/cli-utilities'), + cliux: { + inquire: jest.fn(), + loader: jest.fn(), + print: jest.fn(), + }, + configHandler: { + get: jest.fn(), + }, + HttpClient: jest.fn(), +})); + +describe('FileUpload Adapter', () => { + let logMock: jest.Mock; + let exitMock: jest.Mock; + + beforeEach(() => { + logMock = jest.fn(); + exitMock = jest.fn().mockImplementation(() => { + throw new Error('1'); + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('runFileUploadFlow', () => { + let getEnvironmentMock: jest.SpyInstance; + let handleExistingProjectMock: jest.SpyInstance; + let handleNewProjectMock: jest.SpyInstance; + let prepareLaunchConfigMock: jest.SpyInstance; + let showLogsMock: jest.SpyInstance; + let showDeploymentUrlMock: jest.SpyInstance; + let showSuggestionMock: jest.SpyInstance; + + beforeEach(() => { + getEnvironmentMock = jest + .spyOn(BaseClass.prototype, 'getEnvironment') + .mockResolvedValue({ uid: 'env-123', name: 'Default', frameworkPreset: 'OTHER' }); + handleExistingProjectMock = jest + .spyOn(FileUpload.prototype as any, 'handleExistingProject') + .mockResolvedValue(undefined); + handleNewProjectMock = jest + .spyOn(FileUpload.prototype as any, 'handleNewProject') + .mockResolvedValue(undefined); + prepareLaunchConfigMock = jest.spyOn(BaseClass.prototype, 'prepareLaunchConfig').mockImplementation(() => {}); + showLogsMock = jest.spyOn(BaseClass.prototype, 'showLogs').mockResolvedValue(true); + showDeploymentUrlMock = jest.spyOn(BaseClass.prototype, 'showDeploymentUrl').mockImplementation(() => {}); + showSuggestionMock = jest.spyOn(BaseClass.prototype, 'showSuggestion').mockImplementation(() => {}); + }); + + afterEach(() => { + getEnvironmentMock.mockRestore(); + handleExistingProjectMock.mockRestore(); + handleNewProjectMock.mockRestore(); + prepareLaunchConfigMock.mockRestore(); + showLogsMock.mockRestore(); + showDeploymentUrlMock.mockRestore(); + showSuggestionMock.mockRestore(); + }); + + it('should exit with code 1 when deployment status is FAILED for existing project', async () => { + const fileUploadInstance = new FileUpload({ + config: { + isExistingProject: true, + currentDeploymentStatus: DeploymentStatus.FAILED, + }, + log: logMock, + exit: exitMock, + } as any); + + try { + await fileUploadInstance.run(); + } catch (error: any) { + expect(error.message).toBe('1'); + } + + expect(getEnvironmentMock).toHaveBeenCalled(); + expect(handleExistingProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).toHaveBeenCalledWith(1); + expect(showDeploymentUrlMock).not.toHaveBeenCalled(); + expect(showSuggestionMock).not.toHaveBeenCalled(); + }); + + it('should exit with code 1 when deployment status is FAILED for new project', async () => { + const fileUploadInstance = new FileUpload({ + config: { + isExistingProject: false, + currentDeploymentStatus: DeploymentStatus.FAILED, + }, + log: logMock, + exit: exitMock, + } as any); + + try { + await fileUploadInstance.run(); + } catch (error: any) { + expect(error.message).toBe('1'); + } + + expect(handleNewProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).toHaveBeenCalledWith(1); + expect(showDeploymentUrlMock).not.toHaveBeenCalled(); + expect(showSuggestionMock).not.toHaveBeenCalled(); + }); + + it('should continue normally when deployment status is not FAILED', async () => { + const fileUploadInstance = new FileUpload({ + config: { + isExistingProject: true, + currentDeploymentStatus: DeploymentStatus.LIVE, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.run(); + + expect(getEnvironmentMock).toHaveBeenCalled(); + expect(handleExistingProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).not.toHaveBeenCalled(); + expect(showDeploymentUrlMock).toHaveBeenCalled(); + expect(showSuggestionMock).toHaveBeenCalled(); + }); + }); + + describe('prepareAndUploadNewProjectFile', () => { + let selectOrgMock: jest.SpyInstance; + let createSignedUploadUrlMock: jest.SpyInstance; + let archiveMock: jest.SpyInstance; + let uploadFileMock: jest.SpyInstance; + let detectFrameworkMock: jest.SpyInstance; + let handleEnvImportFlowMock: jest.SpyInstance; + + beforeEach(() => { + selectOrgMock = jest.spyOn(BaseClass.prototype, 'selectOrg').mockResolvedValue(); + createSignedUploadUrlMock = jest.spyOn(FileUpload.prototype, 'createSignedUploadUrl').mockResolvedValue({ + uploadUid: 'upload-123', + uploadUrl: 'https://example.com/upload', + fields: [], + headers: [], + method: 'PUT', + }); + archiveMock = jest.spyOn(FileUpload.prototype, 'archive').mockResolvedValue({ + zipName: 'test.zip', + zipPath: '/path/to/test.zip', + projectName: 'test-project', + }); + uploadFileMock = jest.spyOn(FileUpload.prototype, 'uploadFile').mockResolvedValue(); + detectFrameworkMock = jest.spyOn(BaseClass.prototype, 'detectFramework').mockResolvedValue(); + handleEnvImportFlowMock = jest.spyOn(BaseClass.prototype, 'handleEnvImportFlow').mockResolvedValue(); + }); + + afterEach(() => { + selectOrgMock.mockRestore(); + createSignedUploadUrlMock.mockRestore(); + archiveMock.mockRestore(); + uploadFileMock.mockRestore(); + detectFrameworkMock.mockRestore(); + handleEnvImportFlowMock.mockRestore(); + }); + + it('should prompt for server command when framework supports it and serverCommand is not provided', async () => { + (cliux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); // projectName + (cliux.inquire as jest.Mock).mockResolvedValueOnce('Default'); // environmentName + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); // buildCommand + (cliux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); // outputDirectory + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm start'); // serverCommand + + const fileUploadInstance = new FileUpload({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'OTHER', + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.prepareAndUploadNewProjectFile(); + + expect(cliux.inquire).toHaveBeenCalledWith({ + type: 'input', + name: 'serverCommand', + message: 'Server Command', + }); + expect(fileUploadInstance.config.serverCommand).toBe('npm start'); + }); + + it('should not prompt for server command when framework does not support it', async () => { + (cliux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + + const fileUploadInstance = new FileUpload({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'GATSBY', + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { GATSBY: './public' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.prepareAndUploadNewProjectFile(); + + const serverCommandCalls = (cliux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + }); + + it('should not prompt for server command when serverCommand is already provided in flags', async () => { + (cliux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + + const fileUploadInstance = new FileUpload({ + config: { + flags: { + 'server-command': 'npm run serve', + }, + framework: 'OTHER', + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.prepareAndUploadNewProjectFile(); + + const serverCommandCalls = (cliux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + expect(fileUploadInstance.config.flags['server-command']).toBe('npm run serve'); + }); + + it('should not set serverCommand when user provides empty input', async () => { + (cliux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce(''); + + const fileUploadInstance = new FileUpload({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'OTHER', + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.prepareAndUploadNewProjectFile(); + + expect(cliux.inquire).toHaveBeenCalledWith({ + type: 'input', + name: 'serverCommand', + message: 'Server Command', + }); + expect(fileUploadInstance.config.serverCommand).toBeUndefined(); + }); + + it('should not prompt for server command when framework is not set', async () => { + (cliux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (cliux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + + const fileUploadInstance = new FileUpload({ + config: { + flags: { + 'server-command': undefined, + }, + framework: undefined, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await fileUploadInstance.prepareAndUploadNewProjectFile(); + + const serverCommandCalls = (cliux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + }); + }); +}); + diff --git a/src/adapters/file-upload.ts b/src/adapters/file-upload.ts index 297e0f8..e571736 100755 --- a/src/adapters/file-upload.ts +++ b/src/adapters/file-upload.ts @@ -129,7 +129,7 @@ export default class FileUpload extends BaseClass { name: environmentName || 'Default', environmentVariables: map(this.envVariables, ({ key, value }) => ({ key, value })), buildCommand: buildCommand === undefined || buildCommand === null ? 'npm run build' : buildCommand, - serverCommand: serverCommand === undefined || serverCommand === null ? 'npm run start' : serverCommand, + ...(serverCommand && serverCommand.trim() !== '' ? { serverCommand } : {}), }, }, skipGitData: true, @@ -226,13 +226,18 @@ export default class FileUpload extends BaseClass { default: (this.config.outputDirectories as Record)[this.config?.framework || 'OTHER'], })); if (this.config.framework && this.config.supportedFrameworksForServerCommands.includes(this.config.framework)) { - this.config.serverCommand = - serverCommand || - (await cliux.inquire({ + if (!serverCommand) { + const serverCommandInput = await cliux.inquire({ type: 'input', name: 'serverCommand', message: 'Server Command', - })); + }); + if (serverCommandInput) { + this.config.serverCommand = serverCommandInput; + } + } else { + this.config.serverCommand = serverCommand; + } } this.config.variableType = variableType as unknown as string; this.config.envVariables = envVariables; diff --git a/src/adapters/github.test.ts b/src/adapters/github.test.ts index 6fa2171..13058e5 100644 --- a/src/adapters/github.test.ts +++ b/src/adapters/github.test.ts @@ -3,6 +3,19 @@ import { getRemoteUrls } from '../util/create-git-meta'; import { repositoriesQuery, userConnectionsQuery } from '../graphql'; import BaseClass from './base-class'; import { existsSync } from 'fs'; +import { DeploymentStatus } from '../types'; +import { cliux as ux } from '@contentstack/cli-utilities'; + +jest.mock('@contentstack/cli-utilities', () => ({ + ...jest.requireActual('@contentstack/cli-utilities'), + cliux: { + inquire: jest.fn(), + print: jest.fn(), + }, + configHandler: { + get: jest.fn(), + }, +})); jest.mock('../util/create-git-meta'); jest.mock('fs', () => ({ @@ -286,4 +299,278 @@ describe('GitHub Adapter', () => { expect(githubAdapterInstance.config.repository).toBeUndefined(); }); }); + + describe('runGitHubFlow', () => { + let getEnvironmentMock: jest.SpyInstance; + let handleExistingProjectMock: jest.SpyInstance; + let handleNewProjectMock: jest.SpyInstance; + let prepareLaunchConfigMock: jest.SpyInstance; + let showLogsMock: jest.SpyInstance; + let showDeploymentUrlMock: jest.SpyInstance; + let showSuggestionMock: jest.SpyInstance; + + beforeEach(() => { + getEnvironmentMock = jest + .spyOn(BaseClass.prototype, 'getEnvironment') + .mockResolvedValue({ uid: 'env-123', name: 'Default', frameworkPreset: 'OTHER' }); + handleExistingProjectMock = jest + .spyOn(GitHub.prototype as any, 'handleExistingProject') + .mockResolvedValue(undefined); + handleNewProjectMock = jest + .spyOn(GitHub.prototype as any, 'handleNewProject') + .mockResolvedValue(undefined); + prepareLaunchConfigMock = jest.spyOn(BaseClass.prototype, 'prepareLaunchConfig').mockImplementation(() => {}); + showLogsMock = jest.spyOn(BaseClass.prototype, 'showLogs').mockResolvedValue(true); + showDeploymentUrlMock = jest.spyOn(BaseClass.prototype, 'showDeploymentUrl').mockImplementation(() => {}); + showSuggestionMock = jest.spyOn(BaseClass.prototype, 'showSuggestion').mockImplementation(() => {}); + }); + + afterEach(() => { + getEnvironmentMock.mockRestore(); + handleExistingProjectMock.mockRestore(); + handleNewProjectMock.mockRestore(); + prepareLaunchConfigMock.mockRestore(); + showLogsMock.mockRestore(); + showDeploymentUrlMock.mockRestore(); + showSuggestionMock.mockRestore(); + }); + + it('should exit with code 1 when deployment status is FAILED for existing project', async () => { + const githubInstance = new GitHub({ + config: { + isExistingProject: true, + currentDeploymentStatus: DeploymentStatus.FAILED, + }, + log: logMock, + exit: exitMock, + } as any); + + try { + await githubInstance.run(); + } catch (error: any) { + expect(error.message).toBe('1'); + } + + expect(getEnvironmentMock).toHaveBeenCalled(); + expect(handleExistingProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).toHaveBeenCalledWith(1); + expect(showDeploymentUrlMock).not.toHaveBeenCalled(); + expect(showSuggestionMock).not.toHaveBeenCalled(); + }); + + it('should exit with code 1 when deployment status is FAILED for new project', async () => { + const githubInstance = new GitHub({ + config: { + isExistingProject: false, + currentDeploymentStatus: DeploymentStatus.FAILED, + }, + log: logMock, + exit: exitMock, + } as any); + + try { + await githubInstance.run(); + } catch (error: any) { + expect(error.message).toBe('1'); + } + + expect(handleNewProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).toHaveBeenCalledWith(1); + expect(showDeploymentUrlMock).not.toHaveBeenCalled(); + expect(showSuggestionMock).not.toHaveBeenCalled(); + }); + + it('should continue normally when deployment status is not FAILED', async () => { + const githubInstance = new GitHub({ + config: { + isExistingProject: true, + currentDeploymentStatus: DeploymentStatus.LIVE, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.run(); + + expect(getEnvironmentMock).toHaveBeenCalled(); + expect(handleExistingProjectMock).toHaveBeenCalled(); + expect(prepareLaunchConfigMock).toHaveBeenCalled(); + expect(showLogsMock).toHaveBeenCalled(); + expect(exitMock).not.toHaveBeenCalled(); + expect(showDeploymentUrlMock).toHaveBeenCalled(); + expect(showSuggestionMock).toHaveBeenCalled(); + }); + }); + + describe('prepareForNewProjectCreation', () => { + let selectOrgMock: jest.SpyInstance; + let selectBranchMock: jest.SpyInstance; + let detectFrameworkMock: jest.SpyInstance; + let handleEnvImportFlowMock: jest.SpyInstance; + + beforeEach(() => { + selectOrgMock = jest.spyOn(BaseClass.prototype, 'selectOrg').mockResolvedValue(); + selectBranchMock = jest.spyOn(BaseClass.prototype, 'selectBranch').mockResolvedValue(); + detectFrameworkMock = jest.spyOn(BaseClass.prototype, 'detectFramework').mockResolvedValue(); + handleEnvImportFlowMock = jest.spyOn(BaseClass.prototype, 'handleEnvImportFlow').mockResolvedValue(); + }); + + afterEach(() => { + selectOrgMock.mockRestore(); + selectBranchMock.mockRestore(); + detectFrameworkMock.mockRestore(); + handleEnvImportFlowMock.mockRestore(); + }); + + it('should prompt for server command when framework supports it and serverCommand is not provided', async () => { + (ux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm start'); + + const githubInstance = new GitHub({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'OTHER', + repository: { fullName: 'test-user/repo', name: 'repo' }, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.prepareForNewProjectCreation(); + + expect(ux.inquire).toHaveBeenCalledWith({ + type: 'input', + name: 'serverCommand', + message: 'Server Command', + }); + expect(githubInstance.config.serverCommand).toBe('npm start'); + }); + + it('should not prompt for server command when framework does not support it', async () => { + (ux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('./public'); + + const githubInstance = new GitHub({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'GATSBY', + repository: { fullName: 'test-user/repo', name: 'repo' }, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { GATSBY: './public' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.prepareForNewProjectCreation(); + + const serverCommandCalls = (ux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + }); + + it('should not prompt for server command when serverCommand is already provided in flags', async () => { + (ux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + + const githubInstance = new GitHub({ + config: { + flags: { + 'server-command': 'npm run serve', + }, + framework: 'OTHER', + repository: { fullName: 'test-user/repo', name: 'repo' }, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.prepareForNewProjectCreation(); + + const serverCommandCalls = (ux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + expect(githubInstance.config.flags['server-command']).toBe('npm run serve'); + }); + + it('should not set serverCommand when user provides empty input', async () => { + (ux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + (ux.inquire as jest.Mock).mockResolvedValueOnce(''); + + const githubInstance = new GitHub({ + config: { + flags: { + 'server-command': undefined, + }, + framework: 'OTHER', + repository: { fullName: 'test-user/repo', name: 'repo' }, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.prepareForNewProjectCreation(); + + expect(ux.inquire).toHaveBeenCalledWith({ + type: 'input', + name: 'serverCommand', + message: 'Server Command', + }); + expect(githubInstance.config.serverCommand).toBeUndefined(); + }); + + it('should not prompt for server command when framework is not set', async () => { + (ux.inquire as jest.Mock).mockResolvedValueOnce('test-project'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('Default'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('npm run build'); + (ux.inquire as jest.Mock).mockResolvedValueOnce('./dist'); + + const githubInstance = new GitHub({ + config: { + flags: { + 'server-command': undefined, + }, + framework: undefined, + repository: { fullName: 'test-user/repo', name: 'repo' }, + supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX', 'NUXT'], + outputDirectories: { OTHER: './dist' }, + }, + log: logMock, + exit: exitMock, + } as any); + + await githubInstance.prepareForNewProjectCreation(); + + const serverCommandCalls = (ux.inquire as jest.Mock).mock.calls.filter( + (call) => call[0]?.name === 'serverCommand', + ); + expect(serverCommandCalls.length).toBe(0); + }); + }); }); diff --git a/src/adapters/github.ts b/src/adapters/github.ts index afe0af7..a1032dc 100755 --- a/src/adapters/github.ts +++ b/src/adapters/github.ts @@ -123,7 +123,7 @@ export default class GitHub extends BaseClass { name: environmentName || 'Default', environmentVariables: map(this.envVariables, ({ key, value }) => ({ key, value })), buildCommand: buildCommand === undefined || buildCommand === null ? 'npm run build' : buildCommand, - serverCommand: serverCommand === undefined || serverCommand === null ? 'npm run start' : serverCommand, + ...(serverCommand && serverCommand.trim() !== '' ? { serverCommand } : {}), }, }, }, @@ -221,13 +221,18 @@ export default class GitHub extends BaseClass { default: (this.config.outputDirectories as Record)[this.config?.framework || 'OTHER'], })); if (this.config.framework && this.config.supportedFrameworksForServerCommands.includes(this.config.framework)) { - this.config.serverCommand = - serverCommand || - (await ux.inquire({ + if (!serverCommand) { + const serverCommandInput = await ux.inquire({ type: 'input', name: 'serverCommand', message: 'Server Command', - })); + }); + if (serverCommandInput) { + this.config.serverCommand = serverCommandInput; + } + } else { + this.config.serverCommand = serverCommand; + } } this.config.variableType = variableType as unknown as string; this.config.envVariables = envVariables;