Skip to content

chore: moved setup.ts to src/setup and written tests for it #3568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
13 changes: 13 additions & 0 deletions docs/docs/auto-docs/setup/setup/functions/askAndSetRecaptcha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Admin Docs](/)

***

# Function: askAndSetRecaptcha()

> **askAndSetRecaptcha**(): `Promise`\<`void`\>

Defined in: [src/setup/setup.ts:12](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/setup/setup.ts#L12)

## Returns

`Promise`\<`void`\>
13 changes: 13 additions & 0 deletions docs/docs/auto-docs/setup/setup/functions/main.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Admin Docs](/)

***

# Function: main()

> **main**(): `Promise`\<`void`\>

Defined in: [src/setup/setup.ts:62](https://github.com/PalisadoesFoundation/talawa-admin/blob/main/src/setup/setup.ts#L62)

## Returns

`Promise`\<`void`\>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"jest-preview": "jest-preview",
"update:toc": "node scripts/githooks/update-toc.js",
"lint-staged": "lint-staged --concurrent false",
"setup": "tsx setup.ts",
"setup": "tsx src/setup/setup.ts",
"check-localstorage": "tsx scripts/githooks/check-localstorage-usage.ts",
"postgenerate-docs": "find docs/docs/auto-docs -name 'README.md' -delete && node fix-repo-url.js",
"generate-docs": "typedoc && npm run postgenerate-docs && node fix-readme-links.js"
Expand Down
180 changes: 180 additions & 0 deletions src/setup/setup.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import type { MockInstance } from 'vitest';
import dotenv from 'dotenv';
import fs from 'fs';
import { main, askAndSetRecaptcha } from './setup';
import { checkEnvFile, modifyEnvFile } from './checkEnvFile/checkEnvFile';
import { validateRecaptcha } from './validateRecaptcha/validateRecaptcha';
import askAndSetDockerOption from './askAndSetDockerOption/askAndSetDockerOption';
import updateEnvFile from './updateEnvFile/updateEnvFile';
import askAndUpdatePort from './askAndUpdatePort/askAndUpdatePort';
import { askAndUpdateTalawaApiUrl } from './askForDocker/askForDocker';
import inquirer from 'inquirer';

vi.mock('inquirer');
vi.mock('dotenv');
vi.mock('fs');
vi.mock('./checkEnvFile/checkEnvFile');
vi.mock('./validateRecaptcha/validateRecaptcha');
vi.mock('./askAndSetDockerOption/askAndSetDockerOption');
vi.mock('./updateEnvFile/updateEnvFile');
vi.mock('./askAndUpdatePort/askAndUpdatePort');
vi.mock('./askForDocker/askForDocker');

describe('Talawa Admin Setup', () => {
let processExitSpy: MockInstance;
let consoleErrorSpy: MockInstance;
beforeEach(() => {
vi.clearAllMocks();

vi.mocked(checkEnvFile).mockReturnValue(true);

vi.mocked(fs.readFileSync).mockReturnValue('USE_DOCKER=NO');

vi.mocked(dotenv.parse).mockReturnValue({ USE_DOCKER: 'NO' });

processExitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => {
throw new Error(`process.exit called with code ${code}`);
});
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
});

afterEach(() => {
vi.resetAllMocks();
processExitSpy.mockRestore();
consoleErrorSpy.mockRestore();
});

it('should successfully complete setup with default options', async () => {
vi.mocked(inquirer.prompt)
.mockResolvedValueOnce({ shouldUseRecaptcha: false })
.mockResolvedValueOnce({ shouldLogErrors: false });

await main();

expect(checkEnvFile).toHaveBeenCalled();
expect(modifyEnvFile).toHaveBeenCalled();
expect(askAndSetDockerOption).toHaveBeenCalled();
expect(askAndUpdatePort).toHaveBeenCalled();
expect(askAndUpdateTalawaApiUrl).toHaveBeenCalled();
});

it('should skip port and API URL setup when Docker is used', async () => {
vi.mocked(fs.readFileSync).mockReturnValue('USE_DOCKER=YES');
vi.mocked(dotenv.parse).mockReturnValue({ USE_DOCKER: 'YES' });

vi.mocked(inquirer.prompt)
.mockResolvedValueOnce({ shouldUseRecaptcha: false })
.mockResolvedValueOnce({ shouldLogErrors: false });

await main();

expect(askAndUpdatePort).not.toHaveBeenCalled();
expect(askAndUpdateTalawaApiUrl).not.toHaveBeenCalled();
});

it('should handle error logging setup when user opts in', async () => {
vi.mocked(inquirer.prompt)
.mockResolvedValueOnce({ shouldUseRecaptcha: false })
.mockResolvedValueOnce({ shouldLogErrors: true });

await main();

expect(updateEnvFile).toHaveBeenCalledWith('ALLOW_LOGS', 'YES');
});

it('should exit if env file check fails', async () => {
vi.mocked(checkEnvFile).mockReturnValue(false);
const consoleSpy = vi.spyOn(console, 'error');

await main();

expect(modifyEnvFile).not.toHaveBeenCalled();
expect(askAndSetDockerOption).not.toHaveBeenCalled();
expect(consoleSpy).not.toHaveBeenCalled();
});

it('should handle errors during setup process', async () => {
const mockError = new Error('Setup failed');

vi.mocked(askAndSetDockerOption).mockRejectedValue(mockError);

const consoleSpy = vi.spyOn(console, 'error');

const processExitSpy = vi
.spyOn(process, 'exit')
.mockImplementation(() => undefined as never);

await main();

expect(consoleSpy).toHaveBeenCalledWith('\n❌ Setup failed:', mockError);
expect(processExitSpy).toHaveBeenCalledWith(1);
});

it('should handle file system operations correctly', async () => {
vi.mocked(inquirer.prompt)
.mockResolvedValueOnce({ shouldUseRecaptcha: false })
.mockResolvedValueOnce({ shouldLogErrors: false });

const mockEnvContent = 'MOCK_ENV_CONTENT';

vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);

await main();

expect(fs.readFileSync).toHaveBeenCalledWith('.env', 'utf8');
expect(dotenv.parse).toHaveBeenCalledWith(mockEnvContent);
});
it('should handle user opting out of reCAPTCHA setup', async () => {
vi.mocked(inquirer.prompt).mockResolvedValueOnce({
shouldUseRecaptcha: false,
});

await askAndSetRecaptcha();

expect(inquirer.prompt).toHaveBeenCalledTimes(1);
expect(updateEnvFile).not.toHaveBeenCalled();
expect(validateRecaptcha).not.toHaveBeenCalled();
});

it('should validate reCAPTCHA key input', async () => {
const mockInvalidKey = 'invalid-key';

vi.mocked(inquirer.prompt)
.mockResolvedValueOnce({ shouldUseRecaptcha: true })
.mockImplementationOnce((questions) => {
const question = Array.isArray(questions) ? questions[0] : questions;

const validationResult = question.validate(mockInvalidKey);

expect(validationResult).toBe(
'Invalid reCAPTCHA site key. Please try again.',
);
return Object.assign(
Promise.resolve({ recaptchaSiteKeyInput: mockInvalidKey }),
);
});

vi.mocked(validateRecaptcha).mockReturnValue(false);

await askAndSetRecaptcha();

expect(validateRecaptcha).toHaveBeenCalledWith(mockInvalidKey);
});

it('should handle errors during reCAPTCHA setup', async () => {
const mockError = new Error('ReCAPTCHA setup failed');

vi.mocked(inquirer.prompt).mockRejectedValue(mockError);

await expect(askAndSetRecaptcha()).rejects.toThrow(
'Failed to set up reCAPTCHA: ReCAPTCHA setup failed',
);

expect(consoleErrorSpy).toHaveBeenCalledWith(
'Error setting up reCAPTCHA:',
mockError,
);
expect(updateEnvFile).not.toHaveBeenCalled();
});
});
17 changes: 7 additions & 10 deletions setup.ts → src/setup/setup.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import dotenv from 'dotenv';
import fs from 'fs';
import inquirer from 'inquirer';
import {
checkEnvFile,
modifyEnvFile,
} from './src/setup/checkEnvFile/checkEnvFile';
import { validateRecaptcha } from './src/setup/validateRecaptcha/validateRecaptcha';
import askAndSetDockerOption from './src/setup/askAndSetDockerOption/askAndSetDockerOption';
import updateEnvFile from './src/setup/updateEnvFile/updateEnvFile';
import askAndUpdatePort from './src/setup/askAndUpdatePort/askAndUpdatePort';
import { askAndUpdateTalawaApiUrl } from './src/setup/askForDocker/askForDocker';
import { checkEnvFile, modifyEnvFile } from './checkEnvFile/checkEnvFile';
import { validateRecaptcha } from './validateRecaptcha/validateRecaptcha';
import askAndSetDockerOption from './askAndSetDockerOption/askAndSetDockerOption';
import updateEnvFile from './updateEnvFile/updateEnvFile';
import askAndUpdatePort from './askAndUpdatePort/askAndUpdatePort';
import { askAndUpdateTalawaApiUrl } from './askForDocker/askForDocker';

// Ask and set up reCAPTCHA
const askAndSetRecaptcha = async (): Promise<void> => {
export const askAndSetRecaptcha = async (): Promise<void> => {
try {
const { shouldUseRecaptcha } = await inquirer.prompt([
{
Expand Down
Loading