Skip to content

Commit

Permalink
fix: add test for confirm to process
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherPHolder authored Mar 5, 2024
2 parents 92bde76 + 9ab7c09 commit d54c355
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {mkdirSync, readdirSync} from 'fs';
import {RcJson} from '../../../types';
import {get as interactive} from '../../../global/options/interactive';
import {promptParam} from '../../../core/prompt';
import {promptParam} from '../../../core/prompt/prompt';
import {applyValidations, hasError, VALIDATORS} from '../../../core/validation';
import {
DEFAULT_PERSIST_OUT_PATH,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/lib/commands/init/options/ufPath.setup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { get as interactive } from '../../../global/options/interactive';
import { promptParam } from '../../../core/prompt';
import { promptParam } from '../../../core/prompt/prompt';
import { applyValidations, hasError, VALIDATORS } from '../../../core/validation';
import { DEFAULT_COLLECT_UF_PATH, ERROR_COLLECT_UF_PATH_REQUIRED, PROMPT_COLLECT_UF_PATH } from '../../collect/options/ufPath.constant';
import { RcJson } from '../../../types';
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/lib/commands/init/options/url.setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { get as interactive } from '../../../global/options/interactive';
import { DEFAULT_COLLECT_URL, ERROR_COLLECT_URL_REQUIRED, PROMPT_COLLECT_URL } from '../../collect/options/url.constant';
import { promptParam } from '../../../core/prompt';
import { promptParam } from '../../../core/prompt/prompt';
import { applyValidations, hasError, VALIDATORS } from '../../../core/validation';
import { RcJson } from '../../../types';

Expand Down
27 changes: 16 additions & 11 deletions packages/cli/src/lib/commands/init/processes/generate-userflow.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { RcJson } from '../../../types';
import { join } from 'node:path';
import { readFile, writeFile } from '../../../core/file';
import { log } from '../../../core/loggin';
import { log, logVerbose } from '../../../core/loggin';
import { mkdirSync, readdirSync } from 'node:fs';
import { FlowExampleMap } from '../constants';
import { FlowExamples } from '../types';
import { ifThenElse } from '../../../core/processing/behaviors';
import { askToSkip } from '../../../core/prompt';
import { CLIProcess } from '../../../core/processing/types';
import { logVerbose } from '../../../core/loggin';
import { PROMPT_INIT_GENERATE_FLOW } from '../options/generateFlow.constants';
import { confirmToProcess } from '../../../core/prompt/confirm-to-process';

const exampleName = 'basic-navigation';

Expand All @@ -18,9 +17,11 @@ export function getExamplePathDest(flowExample: FlowExamples, folder: string): s
return join(folder, fileName);
}

export const userflowIsNotCreated = (cfg?: RcJson) => Promise.resolve(cfg ? readFile(getExamplePathDest(exampleName, cfg.collect.ufPath)) === '' : false);
export const userflowIsNotCreated = (cfg: RcJson) => {
return readFile(getExamplePathDest(exampleName, cfg.collect.ufPath)) === '';
};

export async function generateUserFlow(cliCfg: RcJson): Promise<RcJson> {
async function generateUserFlow(cliCfg: RcJson): Promise<RcJson> {
const ufPath = cliCfg.collect.ufPath;
// DX create directory if it does ot exist
try {
Expand All @@ -44,14 +45,18 @@ export async function generateUserFlow(cliCfg: RcJson): Promise<RcJson> {
return Promise.resolve(cliCfg);
}

const interactiveAndGenerateFlowNotPassed = (interactive: boolean, generateFlow?: boolean) => {
return () => interactive && generateFlow === undefined;
}

export function handleFlowGeneration({ generateFlow, interactive }: {interactive: boolean, generateFlow?: boolean}): CLIProcess {
return ifThenElse(
// if `withFlow` is not used in the CLI is in interactive mode
() => interactive == true && generateFlow === undefined,
// Prompt for flow generation
askToSkip(PROMPT_INIT_GENERATE_FLOW, generateUserFlow,
// if the flow is not created already, otherwise skip creation
{ precondition: userflowIsNotCreated }),
interactiveAndGenerateFlowNotPassed(interactive, generateFlow),
confirmToProcess({
prompt: PROMPT_INIT_GENERATE_FLOW,
process: generateUserFlow,
precondition: userflowIsNotCreated
}),
// else `withFlow` is used and true
ifThenElse(() => !!generateFlow,
// generate the file => else do nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jest.mock('enquirer', () => ({
prompt: jest.fn().mockResolvedValue(false),
}));

describe('generate userflow', () => {
describe('handleFlowGeneration', () => {

afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
})

it('should prompt if not passed generateFlow and has interactive true and file does not already exist', async () => {
Expand Down
56 changes: 0 additions & 56 deletions packages/cli/src/lib/core/prompt.ts

This file was deleted.

42 changes: 42 additions & 0 deletions packages/cli/src/lib/core/prompt/confirm-to-process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { promptParam } from './prompt';
import { CLIProcess } from '../processing/types';
import { RcJson } from '../../types';

type Precondition = (context: RcJson) => Promise<boolean> | boolean;

type ConfirmProcess = {
prompt: string,
process: CLIProcess,
denied?: CLIProcess
precondition?: Precondition,
}

const confirmedPrompt = async (prompt: string): Promise<boolean> => {
return await promptParam({
type: 'confirm',
message: prompt,
initial: true,
});
}


const isPreconditionMet = async (context: RcJson, precondition?: Precondition): Promise<boolean> => {
return precondition === undefined ? true : precondition(context);
}

export function confirmToProcess({ prompt, process, precondition }: ConfirmProcess): CLIProcess {
return async (context: RcJson): Promise<RcJson> => {

const shouldPrompt = await isPreconditionMet(context, precondition);
if (!shouldPrompt) {
return context;
}

const shouldProcess = await confirmedPrompt(prompt);
if (!shouldProcess) {
return context;
}

return process(context);
}
}
71 changes: 71 additions & 0 deletions packages/cli/src/lib/core/prompt/confirm-to-process.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { confirmToProcess } from './confirm-to-process';
import { RcJson } from '../../types';
import prompt = require('./prompt');

jest.mock('./prompt');

describe('confirmToProcess', () => {

beforeEach(() => {
jest.clearAllMocks();
})

it('should check if precondition is met if one is given', async () => {
const mockPrecondition = jest.fn();
await confirmToProcess({
prompt: 'Confirm should process?',
process: jest.fn(),
precondition: mockPrecondition,
})({} as RcJson);
expect(mockPrecondition).toHaveBeenCalled();
});

it('should not prompt if precondition is not met', async () => {
const promptParamSpy = jest.spyOn(prompt, 'promptParam');
await confirmToProcess({
prompt: 'Confirm should process?',
process: jest.fn(),
precondition: () => false,
})({} as RcJson);
expect(promptParamSpy).not.toHaveBeenCalled();
});

it('should prompt if precondition is met', async () => {
const promptParamSpy = jest.spyOn(prompt, 'promptParam');
await confirmToProcess({
prompt: 'Confirm should process?',
process: jest.fn(),
precondition: () => true,
})({} as RcJson);
expect(promptParamSpy).toHaveBeenCalled();
});

it('should prompt if no precondition is passed', async () => {
const promptParamSpy = jest.spyOn(prompt, 'promptParam');
await confirmToProcess({
prompt: 'Confirm should process?',
process: jest.fn(),
})({} as RcJson);
expect(promptParamSpy).toHaveBeenCalled();
});

it('should not process if prompt is denied', async () => {
jest.spyOn(prompt, 'promptParam').mockResolvedValue(false);
const processSpy = jest.fn();
await confirmToProcess({
prompt: 'Confirm should process?',
process: processSpy,
})({} as RcJson);
expect(processSpy).not.toHaveBeenCalled();
});

it('should process if prompt is accepted', async () => {
jest.spyOn(prompt, 'promptParam').mockResolvedValue(true);
const processSpy = jest.fn();
await confirmToProcess({
prompt: 'Confirm should process?',
process: processSpy,
})({} as RcJson);
expect(processSpy).toHaveBeenCalled();
});
})
16 changes: 16 additions & 0 deletions packages/cli/src/lib/core/prompt/prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { prompt } from 'enquirer';

export async function promptParam<T>(cfg: {initial?: T, skip?: boolean, message: string, type?: any, [key: string]: any}): Promise<T> {
const { type, initial, message, skip, result } = cfg;

const { param } = await prompt<{ param: T }>([{
name: 'param',
type: type || 'input',
initial,
message,
skip,
result
}]);

return param;
}

0 comments on commit d54c355

Please sign in to comment.