Skip to content

Commit

Permalink
refactor: use expect.toMatchSnapshot to test conplex frames
Browse files Browse the repository at this point in the history
  • Loading branch information
Mist3rBru committed Dec 13, 2023
1 parent 03a69fa commit 852ac71
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 197 deletions.
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ export default {
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
testRegex: ['__tests__/.+(spec|test).ts'],
testRegex: ['__tests__/.+(spec|test).ts$'],
setupFiles: ['<rootDir>/setup.tests.ts'],
};
6 changes: 0 additions & 6 deletions packages/core/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ import { readdirSync } from 'node:fs';
import { join } from 'node:path';
import * as packageExports from '../src/index';

function pascalCase(input: string): string {
const words = input.split('-');
const pascalCaseWords = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1));
return pascalCaseWords.join('');
}

describe('Package', () => {
const exportedKeys = Object.keys(packageExports);

Expand Down
6 changes: 0 additions & 6 deletions packages/prompts/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ function camelCase(input: string): string {
return input.replace(/[-_]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''));
}

function pascalCase(input: string): string {
const words = input.split('-');
const pascalCaseWords = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1));
return pascalCaseWords.join('');
}

describe('Package', () => {
const exportedKeys = Object.keys(packageExports);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`groupMultiselect should render error 1`] = `
"│
▲ test message
│ ◻ changed packages
│ │ ◻ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└ Please select at least one option.
- Press  space  to select,  enter  to submit
"
`;

exports[`groupMultiselect should render initial state 1`] = `
"│
◆ test message
│ ◻ changed packages
│ │ ◻ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;

exports[`groupMultiselect should render initial state with option active 1`] = `
"│
◆ test message
│ ◻ changed packages
│ │ ◻ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;

exports[`groupMultiselect should render initial state with option active and selected 1`] = `
"│
◆ test message
│ ◻ changed packages
│ │ ◼ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;

exports[`groupMultiselect should render initial state with option not active and selected 1`] = `
"│
◆ test message
│ ◻ changed packages
│ │ ◼ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;

exports[`groupMultiselect should render initial with group active 1`] = `
"│
◆ test message
│ ◻ changed packages
│ │ ◻ @scope/a
│ │ ◻ @scope/b
│ └ ◻ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;

exports[`groupMultiselect should render initial with group selected 1`] = `
"│
◆ test message
│ ◼ changed packages
│ │ ◼ @scope/a
│ │ ◼ @scope/b
│ └ ◼ @scope/c
│ ◻ unchanged packages
│ │ ◻ @scope/x
│ │ ◻ @scope/y
│ └ ◻ @scope/z
└
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`multiselect should render error 1`] = `
"│
▲ test message
│ ◻ foo
│ ◻ bar
│ ◻ baz
└ Please select at least one option.
- Press  space  to select,  enter  to submit
"
`;

exports[`multiselect should render initial state 1`] = `
"│
◆ test message
│ ◻ foo
│ ◻ bar
│ ◻ baz
└
"
`;

exports[`multiselect should render initial state with initialValue 1`] = `
"│
◆ test message
│ ◼ foo
│ ◼ bar
│ ◻ baz
└
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`selectKey should render initial state 1`] = `
"│
◆ test message
│  a  a
│  b  b
│  c  c
└
"
`;

exports[`selectKey should render initial state with initialValue 1`] = `
"│
◆ test message
│  a  a
│  b  b
│  c  c
└
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`select should render initial state 1`] = `
"│
◆ test message
│ ● foo
│ ○ bar
│ ○ baz
└
"
`;

exports[`select should render initial state with initialValue 1`] = `
"│
◆ test message
│ ○ foo
│ ● bar
│ ○ baz
└
"
`;
92 changes: 8 additions & 84 deletions packages/prompts/__tests__/prompts/group-multiselect.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mockPrompt, SelectPrompt, State } from '@clack/core';
import { mockPrompt, SelectPrompt } from '@clack/core';
import color from 'picocolors';
import { groupMultiselect } from '../../src';
import { opt } from '../../src/prompts/group-multiselect';
Expand All @@ -17,51 +17,6 @@ const options = {
'unchanged packages': [{ value: '@scope/x' }, { value: '@scope/y' }, { value: '@scope/z' }],
} satisfies Record<string, Option<string>[]>;

const formatOptions = (
opts: Record<string, Option<string>[]> = options,
value: string[] = [],
cursor: number = 0,
state: State = 'initial'
): string => {
const stateColor = state === 'error' ? color.yellow : color.cyan;
return `${stateColor(S_BAR)} ${Object.entries(opts)
.map(([group, children], i, tuples) => {
const skip = tuples.slice(0, i).flat(3).length;
const isGroupActive = i + skip === cursor;
const isGroupSelected = !tuples[i][1]
.map((option) => value.includes(option.value))
.includes(false);
const CHECKBOX = isGroupSelected
? color.green(S_CHECKBOX_SELECTED)
: isGroupActive
? color.cyan(S_CHECKBOX_ACTIVE)
: color.dim(S_CHECKBOX_INACTIVE);
const label = isGroupActive ? group : color.dim(group);
return [
`${color.dim('')}${CHECKBOX} ${label}`,
children.map((child, j, ar) => {
const isActive = i + j + skip + 1 === cursor;
const isSelected = value.includes(child.value);
const isLast = j === ar.length - 1;
const BAR = isLast ? S_BAR_END : S_BAR;
const CHECKBOX = isSelected
? color.green(S_CHECKBOX_SELECTED)
: isGroupActive || isActive
? color.cyan(S_CHECKBOX_ACTIVE)
: color.dim(S_CHECKBOX_INACTIVE);
const prefix = isGroupActive ? `${BAR} ` : color.dim(`${BAR} `);
const label = child.label ?? child.value;
return `${stateColor(S_BAR)} ${prefix}${CHECKBOX} ${
isActive ? label : color.dim(label)
}`;
}),
]
.flat(2)
.join('\n');
})
.join(`\n${stateColor(S_BAR)} `)}`;
};

describe('groupMultiselect', () => {
const mock = mockPrompt<SelectPrompt<{ value: string }>>();
const message = 'test message';
Expand Down Expand Up @@ -178,52 +133,38 @@ describe('groupMultiselect', () => {
});

it('should render initial state', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}`;

groupMultiselect({ message, options });

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(`${title}\n${formatOptions()}\n${color.cyan(S_BAR_END)}\n`);
expect(mock.frame).toMatchSnapshot();
});

it('should render initial with group active', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}`;

groupMultiselect({ message, options });

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(`${title}\n${formatOptions()}\n${color.cyan(S_BAR_END)}\n`);
expect(mock.frame).toMatchSnapshot();
});

it('should render initial with group selected', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}`;

groupMultiselect({ message, options, initialValues: ['changed packages'] });

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(
`${title}\n${formatOptions(options, mock.value)}\n${color.cyan(S_BAR_END)}\n`
);
expect(mock.frame).toMatchSnapshot();
});

it('should render initial state with option active', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}\n`;

groupMultiselect({
message,
options,
cursorAt: options['changed packages'][0].value,
});

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(
`${title}${formatOptions(options, mock.value, 1)}\n${color.cyan(S_BAR_END)}\n`
);
expect(mock.frame).toMatchSnapshot();
});

it('should render initial state with option active and selected', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}\n`;

groupMultiselect({
message,
options,
Expand All @@ -232,14 +173,10 @@ describe('groupMultiselect', () => {
});

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(
`${title}${formatOptions(options, mock.value, 1)}\n${color.cyan(S_BAR_END)}\n`
);
expect(mock.frame).toMatchSnapshot();
});

it('should render initial state with option not active and selected', () => {
const title = `${color.gray(S_BAR)}\n${symbol('initial')} ${message}\n`;

groupMultiselect({
message,
options,
Expand All @@ -248,28 +185,15 @@ describe('groupMultiselect', () => {
});

expect(mock.state).toBe('initial');
expect(mock.frame).toBe(
`${title}${formatOptions(options, mock.value, 2)}\n${color.cyan(S_BAR_END)}\n`
);
expect(mock.frame).toMatchSnapshot();
});

it('should render error', () => {
const title = `${color.gray(S_BAR)}\n${symbol('error')} ${message}`;

groupMultiselect({ message, options });
mock.submit();
const errorLines = mock.error.split('\n');

expect(mock.state).toBe('error');
expect(mock.frame).toBe(
[
title,
formatOptions(options, mock.value, 0, 'error'),
`${color.yellow(S_BAR_END)} ${color.yellow(errorLines[0])}`,
`${color.hidden('-')} ${errorLines[1]}`,
'',
].join('\n')
);
expect(mock.frame).toMatchSnapshot();
});

// Implement when `groupMultiselect.validate` be exposed
Expand Down
Loading

0 comments on commit 852ac71

Please sign in to comment.