Skip to content

Commit 22d0a62

Browse files
add tests
1 parent a8321c9 commit 22d0a62

2 files changed

Lines changed: 182 additions & 4 deletions

File tree

Lines changed: 179 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,182 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
import executor from './executor';
4+
import { ScssBuildExecutorSchema } from './schema';
5+
import { createMockContext, createTempDir, cleanupTempDir } from '../../utils/test-utils';
6+
import { writeFileText, writeJson, readFileText } from '../../utils';
7+
8+
function createMockModules(workspaceRoot: string, projectRoot: string): void {
9+
const projectNodeModules = path.join(projectRoot, 'node_modules', 'sass-embedded');
10+
fs.mkdirSync(projectNodeModules, { recursive: true });
11+
fs.writeFileSync(
12+
path.join(projectNodeModules, 'index.js'),
13+
[
14+
'class SassString {',
15+
' constructor(value) { this.value = value; }',
16+
'}',
17+
'module.exports = {',
18+
' SassString,',
19+
" compile: () => ({ css: '@charset \"UTF-8\"; .a{display:flex}' })",
20+
'};',
21+
'',
22+
].join('\n'),
23+
'utf8',
24+
);
25+
26+
const workspaceNodeModules = path.join(workspaceRoot, 'node_modules');
27+
fs.mkdirSync(workspaceNodeModules, { recursive: true });
28+
29+
const postcssDir = path.join(workspaceNodeModules, 'postcss');
30+
fs.mkdirSync(postcssDir, { recursive: true });
31+
fs.writeFileSync(
32+
path.join(postcssDir, 'index.js'),
33+
[
34+
'module.exports = function postcss() {',
35+
' return {',
36+
' process: async (css) => ({ css: css + "/*prefixed*/" })',
37+
' };',
38+
'};',
39+
'',
40+
].join('\n'),
41+
'utf8',
42+
);
43+
44+
const autoprefixerDir = path.join(workspaceNodeModules, 'autoprefixer');
45+
fs.mkdirSync(autoprefixerDir, { recursive: true });
46+
fs.writeFileSync(
47+
path.join(autoprefixerDir, 'index.js'),
48+
'module.exports = function autoprefixer() { return { postcssPlugin: "autoprefixer" }; };',
49+
'utf8',
50+
);
51+
52+
const cleanCssDir = path.join(workspaceNodeModules, 'clean-css');
53+
fs.mkdirSync(cleanCssDir, { recursive: true });
54+
fs.writeFileSync(
55+
path.join(cleanCssDir, 'index.js'),
56+
[
57+
'module.exports = class CleanCss {',
58+
' constructor(options) { this.options = options || {}; }',
59+
' minify(css) {',
60+
' return { styles: css + "/*min:" + (this.options.profile || "none") + "*/" };',
61+
' }',
62+
'};',
63+
'',
64+
].join('\n'),
65+
'utf8',
66+
);
67+
}
68+
69+
async function setupProjectStructure(workspaceRoot: string): Promise<string> {
70+
const projectRoot = path.join(workspaceRoot, 'packages', 'devextreme-scss');
71+
const buildDir = path.join(projectRoot, 'build');
72+
fs.mkdirSync(buildDir, { recursive: true });
73+
74+
await writeJson(path.join(workspaceRoot, 'package.json'), { name: 'workspace' });
75+
await writeJson(path.join(projectRoot, 'package.json'), { name: 'devextreme-scss' });
76+
77+
await writeJson(path.join(projectRoot, 'build', 'clean-css-options.json'), { profile: 'all' });
78+
79+
const themebuilderDataDir = path.join(
80+
workspaceRoot,
81+
'packages',
82+
'devextreme-themebuilder',
83+
'src',
84+
'data',
85+
);
86+
fs.mkdirSync(themebuilderDataDir, { recursive: true });
87+
await writeJson(path.join(themebuilderDataDir, 'clean-css-options.json'), { profile: 'ci' });
88+
89+
const devextremeDir = path.join(workspaceRoot, 'packages', 'devextreme');
90+
fs.mkdirSync(devextremeDir, { recursive: true });
91+
await writeJson(path.join(devextremeDir, 'package.json'), { version: '26.1.0-test' });
92+
93+
await writeFileText(
94+
path.join(buildDir, 'theme-options.cjs'),
95+
[
96+
'module.exports = {',
97+
' getThemes: () => [',
98+
" ['generic', 'default', 'light'],",
99+
' ],',
100+
'};',
101+
'',
102+
].join('\n'),
103+
);
104+
105+
await writeFileText(path.join(buildDir, 'bundle-template.common.scss'), '.common { color: red; }');
106+
await writeFileText(path.join(buildDir, 'bundle-template.generic.scss'), '.generic-$COLOR { color: red; }');
107+
108+
createMockModules(workspaceRoot, projectRoot);
109+
return projectRoot;
110+
}
111+
1112
describe('ScssBuildExecutor E2E', () => {
2-
it('has test placeholder for native pipeline', () => {
3-
expect(true).toBe(true);
113+
let tempDir: string;
114+
115+
beforeEach(() => {
116+
tempDir = createTempDir('nx-scss-build-e2e-');
117+
});
118+
119+
afterEach(() => {
120+
cleanupTempDir(tempDir);
121+
});
122+
123+
it('builds all mode bundles and applies license/minification profile', async () => {
124+
const projectRoot = await setupProjectStructure(tempDir);
125+
const context = createMockContext({
126+
root: tempDir,
127+
projectName: 'devextreme-scss',
128+
projectRoot: 'packages/devextreme-scss',
129+
});
130+
131+
const options: ScssBuildExecutorSchema = { mode: 'all', cssOutputDir: './artifacts/css' };
132+
const result = await executor(options, context);
133+
134+
expect(result.success).toBe(true);
135+
expect(fs.existsSync(path.join(projectRoot, 'scss', 'bundles', 'dx.light.scss'))).toBe(true);
136+
expect(fs.existsSync(path.join(projectRoot, 'scss', 'bundles', 'dx.common.scss'))).toBe(true);
137+
138+
const cssDir = path.join(projectRoot, 'artifacts', 'css');
139+
const generatedCssFiles = fs
140+
.readdirSync(cssDir)
141+
.filter((name) => name.endsWith('.css'))
142+
.sort();
143+
expect(generatedCssFiles.length).toBeGreaterThan(0);
144+
expect(generatedCssFiles).toContain('dx.common.css');
145+
146+
const commonCss = await readFileText(path.join(cssDir, 'dx.common.css'));
147+
148+
expect(commonCss).toContain('Version: 26.1.0-test');
149+
expect(commonCss).toContain('/*min:all*/');
150+
expect(commonCss).toContain('DevExtreme (dx.common.css)');
151+
});
152+
153+
it('builds ci mode only for selected dev bundles and uses ci profile', async () => {
154+
const projectRoot = await setupProjectStructure(tempDir);
155+
const context = createMockContext({
156+
root: tempDir,
157+
projectName: 'devextreme-scss',
158+
projectRoot: 'packages/devextreme-scss',
159+
});
160+
161+
const options: ScssBuildExecutorSchema = {
162+
mode: 'ci',
163+
devBundles: ['light'],
164+
cssOutputDir: './artifacts/css',
165+
};
166+
const result = await executor(options, context);
167+
168+
expect(result.success).toBe(true);
169+
170+
const cssDir = path.join(projectRoot, 'artifacts', 'css');
171+
const generatedCssFiles = fs
172+
.readdirSync(cssDir)
173+
.filter((name) => name.endsWith('.css'))
174+
.sort();
175+
176+
expect(generatedCssFiles).toEqual(['dx.light.css']);
177+
const lightCss = await readFileText(path.join(cssDir, 'dx.light.css'));
178+
expect(lightCss).toContain('/*min:ci*/');
179+
180+
expect(fs.existsSync(path.join(projectRoot, 'scss', 'bundles', 'dx.common.scss'))).toBe(true);
4181
});
5182
});

packages/nx-infra-plugin/src/executors/scss-build/executor.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as path from 'path';
44
import { createRequire } from 'module';
55
import { glob } from 'glob';
66
import { ScssBuildExecutorSchema } from './schema';
7-
import { resolveProjectPath } from '../../utils/path-resolver';
7+
import { normalizeGlobPathForWindows, resolveProjectPath } from '../../utils/path-resolver';
88
import { ensureDir, readFileText, writeFileText } from '../../utils/file-operations';
99

1010
const DEFAULT_BUNDLES_DIR = './scss/bundles';
@@ -155,7 +155,8 @@ function resolveSourceFiles(
155155
return Promise.resolve(bundleNames.map((name) => path.join(bundlesDir, `dx.${name}.scss`)));
156156
}
157157

158-
return glob(path.join(bundlesDir, 'dx.*.scss'), { nodir: true });
158+
const pattern = normalizeGlobPathForWindows(path.join(bundlesDir, 'dx.*.scss'));
159+
return glob(pattern, { nodir: true });
159160
}
160161

161162
function createDataUriFunction(projectRoot: string, sass: any): (args: any[]) => any {

0 commit comments

Comments
 (0)