@openedx/paragon 23.5.1 → 23.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/paragon-scripts.js +5 -1
- package/dist/light.css +2 -2
- package/dist/light.css.map +1 -1
- package/dist/light.min.css +1 -1
- package/lib/__tests__/build-scss.test.js +146 -0
- package/lib/__tests__/build-tokens.test.js +106 -0
- package/lib/__tests__/help.test.js +301 -0
- package/lib/__tests__/install-theme.test.js +66 -0
- package/lib/__tests__/migrate-to-openedx-scope.test.js +106 -0
- package/lib/__tests__/replace-variables.test.js +79 -0
- package/lib/__tests__/utils.test.js +87 -0
- package/lib/__tests__/version.test.js +20 -0
- package/lib/build-scss.js +1 -0
- package/lib/help.js +4 -1
- package/package.json +2 -1
- package/styles/css/themes/light/variables.css +2 -2
- package/tokens/__mocks__/style-dictionary.js +24 -0
- package/tokens/src/themes/light/components/Menu.json +2 -2
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const sass = require('sass');
|
|
3
|
+
|
|
4
|
+
const buildScssCommand = require('../build-scss');
|
|
5
|
+
const { updateParagonThemeOutput } = require('../build-scss');
|
|
6
|
+
|
|
7
|
+
jest.mock('fs');
|
|
8
|
+
jest.mock('sass');
|
|
9
|
+
jest.mock('postcss', () => jest.fn().mockReturnValue({
|
|
10
|
+
process: jest.fn().mockResolvedValue({
|
|
11
|
+
css: '.processed { color: black; }',
|
|
12
|
+
map: {
|
|
13
|
+
toString: () => 'minified sourcemap content',
|
|
14
|
+
},
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
jest.mock('ora', () => jest.fn(() => ({
|
|
18
|
+
start: jest.fn().mockReturnThis(),
|
|
19
|
+
succeed: jest.fn().mockReturnThis(),
|
|
20
|
+
fail: jest.fn().mockReturnThis(),
|
|
21
|
+
})));
|
|
22
|
+
|
|
23
|
+
describe('updateParagonThemeOutput', () => {
|
|
24
|
+
it('should add core theme correctly', () => {
|
|
25
|
+
const input = {
|
|
26
|
+
paragonThemeOutput: { themeUrls: {} },
|
|
27
|
+
name: 'core',
|
|
28
|
+
isThemeVariant: false,
|
|
29
|
+
isDefaultThemeVariant: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const expected = {
|
|
33
|
+
themeUrls: {
|
|
34
|
+
core: {
|
|
35
|
+
paths: {
|
|
36
|
+
default: './core.css',
|
|
37
|
+
minified: './core.min.css',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const result = updateParagonThemeOutput(input);
|
|
44
|
+
expect(result).toEqual(expected);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should add theme variant correctly', () => {
|
|
48
|
+
const input = {
|
|
49
|
+
paragonThemeOutput: { themeUrls: {} },
|
|
50
|
+
name: 'light',
|
|
51
|
+
isThemeVariant: true,
|
|
52
|
+
isDefaultThemeVariant: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const expected = {
|
|
56
|
+
themeUrls: {
|
|
57
|
+
variants: {
|
|
58
|
+
light: {
|
|
59
|
+
paths: {
|
|
60
|
+
default: './light.css',
|
|
61
|
+
minified: './light.min.css',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = updateParagonThemeOutput(input);
|
|
69
|
+
expect(result).toEqual(expected);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should add default theme variant correctly', () => {
|
|
73
|
+
const input = {
|
|
74
|
+
paragonThemeOutput: { themeUrls: {} },
|
|
75
|
+
name: 'light',
|
|
76
|
+
isThemeVariant: true,
|
|
77
|
+
isDefaultThemeVariant: true,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const expected = {
|
|
81
|
+
themeUrls: {
|
|
82
|
+
defaults: {
|
|
83
|
+
light: 'light',
|
|
84
|
+
},
|
|
85
|
+
variants: {
|
|
86
|
+
light: {
|
|
87
|
+
paths: {
|
|
88
|
+
default: './light.css',
|
|
89
|
+
minified: './light.min.css',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const result = updateParagonThemeOutput(input);
|
|
97
|
+
expect(result).toEqual(expected);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('buildScssCommand', () => {
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
jest.clearAllMocks();
|
|
104
|
+
fs.existsSync.mockReturnValue(false);
|
|
105
|
+
fs.readdirSync.mockReturnValue([
|
|
106
|
+
{ name: 'light', isDirectory: () => true },
|
|
107
|
+
{ name: 'dark', isDirectory: () => true },
|
|
108
|
+
]);
|
|
109
|
+
sass.compile.mockReturnValue({
|
|
110
|
+
css: '.test { color: black; }',
|
|
111
|
+
map: {
|
|
112
|
+
toString: () => 'sourcemap content',
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should compile core and theme stylesheets', () => {
|
|
118
|
+
const args = [
|
|
119
|
+
'--corePath=styles/core.scss',
|
|
120
|
+
'--themesPath=styles/themes',
|
|
121
|
+
'--outDir=dist',
|
|
122
|
+
'--defaultThemeVariants=light',
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
buildScssCommand(args);
|
|
126
|
+
|
|
127
|
+
expect(sass.compile).toHaveBeenCalledWith(
|
|
128
|
+
expect.stringContaining('core.scss'),
|
|
129
|
+
expect.any(Object),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(fs.readdirSync).toHaveBeenCalledWith(
|
|
133
|
+
expect.stringContaining('themes'),
|
|
134
|
+
expect.objectContaining({ withFileTypes: true }),
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should use default arguments when none provided', () => {
|
|
139
|
+
buildScssCommand([]);
|
|
140
|
+
|
|
141
|
+
expect(sass.compile).toHaveBeenCalledWith(
|
|
142
|
+
expect.stringContaining('core.scss'),
|
|
143
|
+
expect.any(Object),
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const buildTokensCommand = require('../build-tokens');
|
|
2
|
+
const {
|
|
3
|
+
initializeStyleDictionary,
|
|
4
|
+
__mockClass: StyleDictionary,
|
|
5
|
+
__mockInstance: styleDictionaryInstance,
|
|
6
|
+
} = require('../../tokens/style-dictionary');
|
|
7
|
+
const { createIndexCssFile } = require('../../tokens/utils');
|
|
8
|
+
|
|
9
|
+
jest.mock('../../tokens/style-dictionary');
|
|
10
|
+
jest.mock('../../tokens/utils');
|
|
11
|
+
|
|
12
|
+
describe('buildTokensCommand', () => {
|
|
13
|
+
const defaultBuildDir = './build/';
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should use default parameters when no arguments provided', async () => {
|
|
20
|
+
await buildTokensCommand([]);
|
|
21
|
+
|
|
22
|
+
expect(initializeStyleDictionary).toHaveBeenCalledWith(
|
|
23
|
+
expect.objectContaining({
|
|
24
|
+
themes: ['light'],
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should handle multiple themes correctly', async () => {
|
|
30
|
+
await buildTokensCommand(['--themes', 'light,dark']);
|
|
31
|
+
|
|
32
|
+
expect(StyleDictionary).toHaveBeenCalledTimes(3); // 1 for core + 2 for themes
|
|
33
|
+
expect(createIndexCssFile).toHaveBeenCalledTimes(3);
|
|
34
|
+
|
|
35
|
+
// Verify index files creation for core and each theme
|
|
36
|
+
const expectedCalls = [
|
|
37
|
+
{ isThemeVariant: false, themeVariant: undefined },
|
|
38
|
+
{ isThemeVariant: true, themeVariant: 'light' },
|
|
39
|
+
{ isThemeVariant: true, themeVariant: 'dark' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
expectedCalls.forEach(params => {
|
|
43
|
+
expect(createIndexCssFile).toHaveBeenCalledWith(expect.objectContaining({
|
|
44
|
+
buildDir: defaultBuildDir,
|
|
45
|
+
...params,
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle source-tokens-only flag', async () => {
|
|
51
|
+
await buildTokensCommand(['--source-tokens-only']);
|
|
52
|
+
|
|
53
|
+
expect(StyleDictionary).toHaveBeenCalledWith(expect.objectContaining({
|
|
54
|
+
platforms: expect.objectContaining({
|
|
55
|
+
css: expect.objectContaining({
|
|
56
|
+
files: expect.arrayContaining([
|
|
57
|
+
expect.objectContaining({
|
|
58
|
+
filter: 'isSource',
|
|
59
|
+
}),
|
|
60
|
+
]),
|
|
61
|
+
}),
|
|
62
|
+
}),
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should use custom build path', async () => {
|
|
67
|
+
const customBuildDir = './custom-build/';
|
|
68
|
+
await buildTokensCommand(['--build-dir', customBuildDir]);
|
|
69
|
+
|
|
70
|
+
expect(StyleDictionary).toHaveBeenCalledWith(expect.objectContaining({
|
|
71
|
+
platforms: expect.objectContaining({
|
|
72
|
+
css: expect.objectContaining({
|
|
73
|
+
buildPath: customBuildDir,
|
|
74
|
+
}),
|
|
75
|
+
}),
|
|
76
|
+
}));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should handle custom token source', async () => {
|
|
80
|
+
const customSource = './custom-tokens';
|
|
81
|
+
await buildTokensCommand(['--source', customSource]);
|
|
82
|
+
|
|
83
|
+
expect(StyleDictionary).toHaveBeenCalledWith(expect.objectContaining({
|
|
84
|
+
source: expect.arrayContaining([
|
|
85
|
+
expect.stringContaining(customSource),
|
|
86
|
+
]),
|
|
87
|
+
}));
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should handle build errors', async () => {
|
|
91
|
+
const errorMessage = 'Clean error';
|
|
92
|
+
styleDictionaryInstance.cleanAllPlatforms.mockRejectedValueOnce(new Error(errorMessage));
|
|
93
|
+
|
|
94
|
+
await expect(buildTokensCommand([])).rejects.toThrow(errorMessage);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should handle verbose flag', async () => {
|
|
98
|
+
await buildTokensCommand(['--verbose']);
|
|
99
|
+
|
|
100
|
+
expect(StyleDictionary).toHaveBeenCalledWith(expect.objectContaining({
|
|
101
|
+
log: {
|
|
102
|
+
verbosity: 'verbose',
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
const { COMMANDS } = require('../../bin/paragon-scripts');
|
|
4
|
+
const { helpCommand, findCommandByName } = require('../help');
|
|
5
|
+
|
|
6
|
+
/* eslint-disable no-console */
|
|
7
|
+
console.log = jest.fn();
|
|
8
|
+
console.error = jest.fn();
|
|
9
|
+
/* eslint-enable no-console */
|
|
10
|
+
|
|
11
|
+
describe('helpCommand', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
/* eslint-disable no-console */
|
|
14
|
+
console.log.mockClear();
|
|
15
|
+
console.error.mockClear();
|
|
16
|
+
/* eslint-enable no-console */
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('displays all commands when no specific command is provided', () => {
|
|
20
|
+
helpCommand(COMMANDS, []);
|
|
21
|
+
/* eslint-disable no-console */
|
|
22
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
23
|
+
expect(console.log).toHaveBeenCalledWith('Available commands:');
|
|
24
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('install-theme'));
|
|
25
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('build-tokens'));
|
|
26
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('help'));
|
|
27
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('version'));
|
|
28
|
+
/* eslint-enable no-console */
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('displays specific command details when command name is provided', () => {
|
|
32
|
+
helpCommand(COMMANDS, ['install-theme']);
|
|
33
|
+
/* eslint-disable no-console */
|
|
34
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
35
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('install-theme'));
|
|
36
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('The @edx/brand package to install.'));
|
|
37
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Installs the specific @edx/brand package'));
|
|
38
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('theme'));
|
|
39
|
+
/* eslint-enable no-console */
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('displays error for unknown command', () => {
|
|
43
|
+
helpCommand(COMMANDS, ['unknown']);
|
|
44
|
+
|
|
45
|
+
expect(console.error).toHaveBeenCalledWith(/* eslint-disable-line no-console */
|
|
46
|
+
chalk.red.bold('Unknown command. Usage: paragon help <command>.'),
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('handles commands without parameters or options', () => {
|
|
51
|
+
helpCommand(COMMANDS, ['version']);
|
|
52
|
+
/* eslint-disable no-console */
|
|
53
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
54
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('version'));
|
|
55
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Displays the current version of Paragon CLI'));
|
|
56
|
+
/* eslint-enable no-console */
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('handles parameters with choices', () => {
|
|
60
|
+
helpCommand(COMMANDS, ['help']);
|
|
61
|
+
expect(console.log).toHaveBeenCalledWith(/* eslint-disable-line no-console */
|
|
62
|
+
expect.stringContaining(
|
|
63
|
+
`${chalk.yellow.bold('command')} ${chalk.grey('[install-theme|build-tokens|replace-variables|build-scss], Default: \'\'')}`,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('handles options with choices', () => {
|
|
69
|
+
helpCommand(COMMANDS, ['replace-variables']);
|
|
70
|
+
/* eslint-disable no-console */
|
|
71
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
72
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('replace-variables'));
|
|
73
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining(
|
|
74
|
+
'CLI to replace SCSS variables usages or definitions to CSS variables and vice versa in .scss files.',
|
|
75
|
+
));
|
|
76
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
77
|
+
expect.stringContaining(
|
|
78
|
+
`${chalk.yellow.bold('-t, --replacementType')} ${chalk.grey('[usage|definition], Default: definition')}`,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
82
|
+
expect.stringContaining(
|
|
83
|
+
`${chalk.yellow.bold('-d, --direction')} ${chalk.grey('[scss-to-css|css-to-scss], Default: scss-to-css')}`,
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
/* eslint-enable no-console */
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('handles commands with both parameters and options with choices', () => {
|
|
90
|
+
helpCommand(COMMANDS, ['build-scss']);
|
|
91
|
+
/* eslint-disable no-console */
|
|
92
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
93
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('build-scss'));
|
|
94
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
95
|
+
expect.stringContaining('CLI to compile Paragon\'s core and themes SCSS into CSS.'),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
99
|
+
expect.stringContaining(`${chalk.yellow.bold('--corePath')} ${chalk.grey('Default: styles/scss/core/core.scss')}`),
|
|
100
|
+
);
|
|
101
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Path to the theme\'s core SCSS file'));
|
|
102
|
+
|
|
103
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
104
|
+
expect.stringContaining(`${chalk.yellow.bold('--themesPath')} ${chalk.grey('Default: styles/css/themes')}`),
|
|
105
|
+
);
|
|
106
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
107
|
+
expect.stringContaining('Path to the directory that contains themes\' files'),
|
|
108
|
+
);
|
|
109
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('themes/'));
|
|
110
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('light/'));
|
|
111
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('dark/'));
|
|
112
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('some_other_custom_theme/'));
|
|
113
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
114
|
+
expect.stringContaining('where index.css has imported all other CSS files in the theme\'s subdirectory'),
|
|
115
|
+
);
|
|
116
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('The script will output'));
|
|
117
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('You can provide any amount of themes'));
|
|
118
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
119
|
+
expect.stringContaining('light.css, dark.css and some_other_custom_theme.css files'),
|
|
120
|
+
);
|
|
121
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
122
|
+
expect.stringContaining('(together with maps and minified versions).'),
|
|
123
|
+
);
|
|
124
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
125
|
+
expect.stringContaining('You can provide any amount of themes. Default to paragon\'s themes.'),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
129
|
+
expect.stringContaining(`${chalk.yellow.bold('--outDir')} ${chalk.grey('Default: ./dist')}`),
|
|
130
|
+
);
|
|
131
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
132
|
+
expect.stringContaining('Specifies directory where to out resulting CSS files.'),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
136
|
+
expect.stringContaining(`${chalk.yellow.bold('--defaultThemeVariants')} ${chalk.grey('Default: light')}`),
|
|
137
|
+
);
|
|
138
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Specifies default theme variants'));
|
|
139
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('You can provide multiple default theme variants'));
|
|
140
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('example: `--defaultThemeVariants light dark`'));
|
|
141
|
+
/* eslint-enable no-console */
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('handles commands with multiple options including list choices', () => {
|
|
145
|
+
helpCommand(COMMANDS, ['build-tokens']);
|
|
146
|
+
/* eslint-disable no-console */
|
|
147
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
148
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('build-tokens'));
|
|
149
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
150
|
+
expect.stringContaining('CLI to build Paragon design tokens.'),
|
|
151
|
+
);
|
|
152
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
153
|
+
expect.stringContaining(`${chalk.yellow.bold('-s, --source')} ${chalk.grey('Default: \'\'')}`),
|
|
154
|
+
);
|
|
155
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
156
|
+
expect.stringContaining(`${chalk.yellow.bold('-t, --themes')} ${chalk.grey('Default: light')}`),
|
|
157
|
+
);
|
|
158
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Can be provided as a comma-separated list'));
|
|
159
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
160
|
+
expect.stringContaining(`${chalk.yellow.bold('-v, --verbose')} ${chalk.grey('Default: false')}`),
|
|
161
|
+
);
|
|
162
|
+
/* eslint-enable no-console */
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('handles replace-variables command with parameters and options', () => {
|
|
166
|
+
helpCommand(COMMANDS, ['replace-variables']);
|
|
167
|
+
/* eslint-disable no-console */
|
|
168
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
169
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('replace-variables'));
|
|
170
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
171
|
+
expect.stringContaining(
|
|
172
|
+
'CLI to replace SCSS variables usages or definitions to CSS variables and vice versa in .scss files.',
|
|
173
|
+
),
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
177
|
+
expect.stringContaining(`${chalk.yellow.bold('-p, --filePath')} ${chalk.grey('Default: \'\'')}`),
|
|
178
|
+
);
|
|
179
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
180
|
+
expect.stringContaining('Path to the file or directory where to replace variables.'),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
184
|
+
expect.stringContaining(`${chalk.yellow.bold('-s, --source')} ${chalk.grey('Default: \'\'')}`),
|
|
185
|
+
);
|
|
186
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
187
|
+
expect.stringContaining('Type of replacement: usage or definition'),
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
191
|
+
expect.stringContaining(
|
|
192
|
+
`${chalk.yellow.bold('-t, --replacementType')} ${chalk.grey('[usage|definition], Default: definition')}`,
|
|
193
|
+
),
|
|
194
|
+
);
|
|
195
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Type of replacement: usage or definition'));
|
|
196
|
+
|
|
197
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
198
|
+
expect.stringContaining(
|
|
199
|
+
`${chalk.yellow.bold('-d, --direction')} ${chalk.grey('[scss-to-css|css-to-scss], Default: scss-to-css')}`,
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Map direction: css-to-scss or scss-to-css'));
|
|
203
|
+
/* eslint-enable no-console */
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('handles build-tokens command with options', () => {
|
|
207
|
+
helpCommand(COMMANDS, ['build-tokens']);
|
|
208
|
+
/* eslint-disable no-console */
|
|
209
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
210
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('build-tokens'));
|
|
211
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('CLI to build Paragon design tokens.'));
|
|
212
|
+
|
|
213
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
214
|
+
expect.stringContaining(`${chalk.yellow.bold('-s, --source')} ${chalk.grey('Default: \'\'')}`),
|
|
215
|
+
);
|
|
216
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
217
|
+
expect.stringContaining('Specify the source directory for design tokens.'),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
221
|
+
expect.stringContaining(`${chalk.yellow.bold('-b, --build-dir')} ${chalk.grey('Default: ./build/')}`),
|
|
222
|
+
);
|
|
223
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
224
|
+
expect.stringContaining('Specify the build directory for the generated tokens.'),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
228
|
+
expect.stringContaining(`${chalk.yellow.bold('--source-tokens-only')} ${chalk.grey('Default: false')}`),
|
|
229
|
+
);
|
|
230
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
231
|
+
expect.stringContaining('Include only source design tokens in the build.'),
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
235
|
+
expect.stringContaining(`${chalk.yellow.bold('--output-token-references')} ${chalk.grey('Default: true')}`),
|
|
236
|
+
);
|
|
237
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
238
|
+
expect.stringContaining('Include references for tokens with aliases to other tokens in the build output.'),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
242
|
+
expect.stringContaining(`${chalk.yellow.bold('-t, --themes')} ${chalk.grey('Default: light')}`),
|
|
243
|
+
);
|
|
244
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Specify themes to include in the token build.'));
|
|
245
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Can be provided as a comma-separated list'));
|
|
246
|
+
|
|
247
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
248
|
+
expect.stringContaining(`${chalk.yellow.bold('-v, --verbose')} ${chalk.grey('Default: false')}`),
|
|
249
|
+
);
|
|
250
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Enable verbose logging.'));
|
|
251
|
+
/* eslint-enable no-console */
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('handles migrate-to-openedx-scope command with parameters', () => {
|
|
255
|
+
helpCommand(COMMANDS, ['migrate-to-openedx-scope']);
|
|
256
|
+
/* eslint-disable no-console */
|
|
257
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
258
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('migrate-to-openedx-scope'));
|
|
259
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
260
|
+
expect.stringContaining('CLI for migrate from "@edx/paragon" to "@openedx/paragon".'),
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
264
|
+
expect.stringContaining(`${chalk.yellow.bold('path')} ${chalk.grey('Default: None')}`),
|
|
265
|
+
);
|
|
266
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
267
|
+
expect.stringContaining(
|
|
268
|
+
'Path to the directory where to replace Paragon package name, default to root of the repository',
|
|
269
|
+
),
|
|
270
|
+
);
|
|
271
|
+
/* eslint-enable no-console */
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('handles help command with parameters', () => {
|
|
275
|
+
helpCommand(COMMANDS, ['help']);
|
|
276
|
+
/* eslint-disable no-console */
|
|
277
|
+
expect(console.log).toHaveBeenCalledWith(chalk.yellow.bold('Paragon Help'));
|
|
278
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('help'));
|
|
279
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Displays help for available commands.'));
|
|
280
|
+
|
|
281
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
282
|
+
expect.stringContaining(
|
|
283
|
+
`${chalk.yellow.bold('command')} ${chalk.grey('[install-theme|build-tokens|replace-variables|build-scss], Default: \'\'')}`,
|
|
284
|
+
),
|
|
285
|
+
);
|
|
286
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Specifies command name.'));
|
|
287
|
+
/* eslint-enable no-console */
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
describe('findCommandByName', () => {
|
|
292
|
+
it('returns command object when command exists', () => {
|
|
293
|
+
const result = findCommandByName('help', COMMANDS);
|
|
294
|
+
expect(result).toEqual({ help: COMMANDS.help });
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('returns null when command does not exist', () => {
|
|
298
|
+
const result = findCommandByName('unknown', COMMANDS);
|
|
299
|
+
expect(result).toBeNull();
|
|
300
|
+
});
|
|
301
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const childProcess = require('child_process');
|
|
3
|
+
|
|
4
|
+
const themeCommand = require('../install-theme');
|
|
5
|
+
|
|
6
|
+
jest.mock('inquirer');
|
|
7
|
+
jest.mock('child_process');
|
|
8
|
+
|
|
9
|
+
describe('install-theme', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
process.argv = ['node', 'script'];
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('promptUserForTheme', () => {
|
|
16
|
+
it('should prompt user with correct default theme', async () => {
|
|
17
|
+
inquirer.prompt.mockResolvedValueOnce({ theme: '@openedx/brand-openedx@latest' });
|
|
18
|
+
|
|
19
|
+
await themeCommand();
|
|
20
|
+
|
|
21
|
+
expect(inquirer.prompt).toHaveBeenCalledWith([
|
|
22
|
+
expect.objectContaining({
|
|
23
|
+
type: 'input',
|
|
24
|
+
name: 'theme',
|
|
25
|
+
message: 'What @edx/brand package do you want to install?',
|
|
26
|
+
default: '@openedx/brand-openedx@latest',
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('installTheme', () => {
|
|
33
|
+
it('should install theme when provided via command line', async () => {
|
|
34
|
+
process.argv = ['node', 'script', 'install-theme', '@edx/custom-theme@1.0.0'];
|
|
35
|
+
|
|
36
|
+
await themeCommand();
|
|
37
|
+
|
|
38
|
+
expect(childProcess.execSync).toHaveBeenCalledWith(
|
|
39
|
+
'npm install "@edx/brand@npm:@edx/custom-theme@1.0.0" --no-save',
|
|
40
|
+
expect.any(Object),
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should install theme when provided via prompt', async () => {
|
|
45
|
+
inquirer.prompt.mockResolvedValueOnce({ theme: '@edx/custom-theme@2.0.0' });
|
|
46
|
+
|
|
47
|
+
await themeCommand();
|
|
48
|
+
|
|
49
|
+
expect(childProcess.execSync).toHaveBeenCalledWith(
|
|
50
|
+
'npm install "@edx/brand@npm:@edx/custom-theme@2.0.0" --no-save',
|
|
51
|
+
expect.any(Object),
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle empty theme input correctly', async () => {
|
|
56
|
+
inquirer.prompt.mockResolvedValueOnce({ theme: '' });
|
|
57
|
+
|
|
58
|
+
await themeCommand();
|
|
59
|
+
|
|
60
|
+
expect(childProcess.execSync).toHaveBeenCalledWith(
|
|
61
|
+
'npm install "@edx/brand@" --no-save',
|
|
62
|
+
expect.any(Object),
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|