Skip to content

chore: add unit tests on ci for Windows #7539

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 2 commits into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,13 @@ jobs:
test-unit:
name: Unit Tests
if: always() && needs.changes.outputs.build-unit == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
settings:
- host: ubuntu-latest
- host: windows-latest

runs-on: ${{ matrix.settings.host }}
needs:
- changes
- build-other-packages
Expand Down
66 changes: 37 additions & 29 deletions packages/qwik/src/cli/add/update-files.unit.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
import { fs } from 'memfs';
import { join } from 'path';
import { describe, expect, test, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
import { normalizePath } from '../../testing/util';
import type { FsUpdates, UpdateAppOptions } from '../types';
import { mergeIntegrationDir } from './update-files';

vi.mock('node:fs', () => ({
default: fs,
}));

function setup() {
const fakeSrcDir = 'srcDir/subSrcDir';
let fakeSrcDir: string;
let fakeDestDir: string;
let fakeFileUpdates: FsUpdates;
let fakeOpts: UpdateAppOptions;

beforeEach(() => {
// Reset the mock filesystem before each test
fs.mkdirSync(join('srcDir', 'subSrcDir'), { recursive: true });
fs.mkdirSync(join('destDir', 'subDestDir'), { recursive: true });

fakeSrcDir = join('srcDir', 'subSrcDir');
createFakeFiles(fakeSrcDir);

const fakeDestDir = 'destDir/subDestDir';
fakeDestDir = join('destDir', 'subDestDir');

const fakeFileUpdates: FsUpdates = {
fakeFileUpdates = {
files: [],
installedDeps: {},
installedScripts: [],
};

const fakeOpts: UpdateAppOptions = {
fakeOpts = {
rootDir: fakeDestDir,
integration: 'integration',
};
});

return {
fakeSrcDir,
fakeDestDir,
fakeFileUpdates,
fakeOpts,
};
}
afterEach(() => {
vi.clearAllMocks();
// Clean up the mock filesystem
fs.rmSync(join('srcDir'), { recursive: true, force: true });
fs.rmSync(join('destDir'), { recursive: true, force: true });
});

function createFakeFiles(dir: string) {
// Create fake src files
Expand All @@ -43,23 +53,19 @@ function createFakeFiles(dir: string) {

describe('mergeIntegrationDir', () => {
test('should merge integration directory', async () => {
const { fakeSrcDir, fakeDestDir, fakeFileUpdates, fakeOpts } = setup();

await mergeIntegrationDir(fakeFileUpdates, fakeOpts, fakeSrcDir, fakeDestDir);

const actualResults = fakeFileUpdates.files.map((f) => f.path);
const actualResults = fakeFileUpdates.files.map((f) => normalizePath(f.path));
const expectedResults = [
'destDir/subDestDir/fake.ts',
'destDir/subDestDir/package.json',
'destDir/subDestDir/src/global.css',
normalizePath(join('destDir', 'subDestDir', 'fake.ts')),
normalizePath(join('destDir', 'subDestDir', 'package.json')),
normalizePath(join('destDir', 'subDestDir', 'src', 'global.css')),
];

expect(actualResults).toEqual(expectedResults);
});

test('should merge integration directory in a monorepo', async () => {
const { fakeSrcDir, fakeDestDir, fakeFileUpdates, fakeOpts } = setup();

// Create a global file in the destination director
const monorepoSubDir = join(fakeDestDir, 'apps', 'subpackage', 'src');
fs.mkdirSync(monorepoSubDir, { recursive: true });
Expand All @@ -72,25 +78,27 @@ describe('mergeIntegrationDir', () => {
fs.mkdirSync(join(fakeSrcDir, 'should-stay'), { recursive: true });
fs.writeFileSync(join(fakeSrcDir, 'should-stay', 'should-also-stay.ts'), 'fake file');

fakeOpts.projectDir = 'apps/subpackage';
fakeOpts.projectDir = join('apps', 'subpackage');
fakeOpts.installDeps = true;
const fakeAlwaysInRoot = ['should-stay-in-root.ts', 'should-stay'];

await mergeIntegrationDir(fakeFileUpdates, fakeOpts, fakeSrcDir, fakeDestDir, fakeAlwaysInRoot);

const actualResults = fakeFileUpdates.files.map((f) => f.path);
const actualResults = fakeFileUpdates.files.map((f) => normalizePath(f.path));
const expectedResults = [
`destDir/subDestDir/apps/subpackage/fake.ts`,
`destDir/subDestDir/should-stay-in-root.ts`,
`destDir/subDestDir/package.json`,
`destDir/subDestDir/should-stay/should-also-stay.ts`,
`destDir/subDestDir/apps/subpackage/src/global.css`,
normalizePath(join('destDir', 'subDestDir', 'apps', 'subpackage', 'fake.ts')),
normalizePath(join('destDir', 'subDestDir', 'should-stay-in-root.ts')),
normalizePath(join('destDir', 'subDestDir', 'package.json')),
normalizePath(join('destDir', 'subDestDir', 'should-stay', 'should-also-stay.ts')),
normalizePath(join('destDir', 'subDestDir', 'apps', 'subpackage', 'src', 'global.css')),
];

expect(actualResults).toEqual(expectedResults);

const actualGlobalCssContent = fakeFileUpdates.files.find(
(f) => f.path === `destDir/subDestDir/apps/subpackage/src/global.css`
(f) =>
normalizePath(f.path) ===
normalizePath(join('destDir', 'subDestDir', 'apps', 'subpackage', 'src', 'global.css'))
)?.content;

expect(actualGlobalCssContent).toBe('p{color: red}\n\n/* CSS */\n');
Expand Down
16 changes: 12 additions & 4 deletions packages/qwik/src/optimizer/src/plugins/plugin.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ test('defaults', async () => {
assert.deepEqual(opts.debug, false);
assert.deepEqual(opts.rootDir, normalizePath(cwd));
assert.deepEqual(opts.tsconfigFileNames, ['./tsconfig.json']);
assert.deepEqual(opts.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((opts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);
assert.deepEqual(opts.outDir, normalizePath(resolve(cwd, 'dist')));
assert.deepEqual(opts.manifestInput, null);
assert.deepEqual(opts.manifestOutput, null);
Expand All @@ -39,7 +41,9 @@ test('defaults (buildMode: production)', async () => {
assert.deepEqual(opts.debug, false);
assert.deepEqual(opts.rootDir, normalizePath(cwd));
assert.deepEqual(opts.tsconfigFileNames, ['./tsconfig.json']);
assert.deepEqual(opts.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((opts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);
assert.deepEqual(opts.outDir, normalizePath(resolve(cwd, 'dist')));
assert.deepEqual(opts.manifestInput, null);
assert.deepEqual(opts.manifestOutput, null);
Expand All @@ -57,7 +61,9 @@ test('defaults (target: ssr)', async () => {
assert.deepEqual(opts.debug, false);
assert.deepEqual(opts.rootDir, normalizePath(cwd));
assert.deepEqual(opts.tsconfigFileNames, ['./tsconfig.json']);
assert.deepEqual(opts.input, [normalizePath(resolve(cwd, 'src', 'entry.ssr'))]);
assert.deepEqual((opts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'entry.ssr')),
]);
assert.deepEqual(opts.outDir, normalizePath(resolve(cwd, 'server')));
assert.deepEqual(opts.manifestInput, null);
assert.deepEqual(opts.manifestOutput, null);
Expand All @@ -74,7 +80,9 @@ test('defaults (buildMode: production, target: ssr)', async () => {
assert.deepEqual(opts.debug, false);
assert.deepEqual(opts.rootDir, normalizePath(cwd));
assert.deepEqual(opts.tsconfigFileNames, ['./tsconfig.json']);
assert.deepEqual(opts.input, [normalizePath(resolve(cwd, 'src', 'entry.ssr'))]);
assert.deepEqual((opts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'entry.ssr')),
]);
assert.deepEqual(opts.outDir, normalizePath(resolve(cwd, 'server')));
assert.deepEqual(opts.manifestInput, null);
assert.deepEqual(opts.manifestOutput, null);
Expand Down
12 changes: 9 additions & 3 deletions packages/qwik/src/optimizer/src/plugins/rollup.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ test('rollup default input options, client', async () => {
const rollupInputOpts: Rollup.InputOptions = await plugin.options!({});

assert.deepEqual(typeof rollupInputOpts.onwarn, 'function');
assert.deepEqual(rollupInputOpts.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((rollupInputOpts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);
});

test('rollup default input options, ssr', async () => {
Expand All @@ -44,8 +46,12 @@ test('rollup default input options, ssr', async () => {

assert.deepEqual(typeof rollupInputOpts.onwarn, 'function');
assert.deepEqual(rollupInputOpts.treeshake, undefined);
assert.deepEqual(rollupInputOpts.input, [normalizePath(resolve(cwd, 'src', 'entry.ssr'))]);
assert.deepEqual(opts.input, [normalizePath(resolve(cwd, 'src', 'entry.ssr'))]);
assert.deepEqual((rollupInputOpts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'entry.ssr')),
]);
assert.deepEqual((opts.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'entry.ssr')),
]);
});

test('rollup default set input options, ssr', async () => {
Expand Down
44 changes: 34 additions & 10 deletions packages/qwik/src/optimizer/src/plugins/vite.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,14 @@ test('command: serve, mode: development', async () => {
assert.deepEqual(outputOptions.assetFileNames, 'assets/[hash]-[name].[ext]');
assert.deepEqual(chunkFileNames(chunkInfoMocks[0]), `build/chunk.tsx.js`);
assert.deepEqual(entryFileNames(chunkInfoMocks[0]), `build/chunk.tsx.js`);
assert.deepEqual(chunkFileNames(chunkInfoMocks[1]), 'build/app-chunk.tsx.js');
assert.deepEqual(entryFileNames(chunkInfoMocks[1]), 'build/app-chunk.tsx.js');
const relDev = path.relative(cwd, chunkInfoMocks[1].name);
const sanitizedDev = relDev
.replace(/^\(\.\.\/\)+/, '')
.replace(/^\/+/, '')
.replace(/\//g, '-');
const expectedDevChunk = `build/${sanitizedDev}.js`;
assert.deepEqual(chunkFileNames(chunkInfoMocks[1]), expectedDevChunk);
assert.deepEqual(entryFileNames(chunkInfoMocks[1]), expectedDevChunk);
assert.deepEqual(outputOptions.format, 'es');

assert.deepEqual(build.dynamicImportVarsOptions?.exclude, [/./]);
Expand Down Expand Up @@ -180,13 +186,21 @@ test('command: build, mode: development', async () => {
assert.deepEqual(plugin.enforce, 'pre');
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'dist')));
assert.deepEqual(build.emptyOutDir, undefined);
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);

assert.deepEqual(outputOptions.assetFileNames, 'assets/[hash]-[name].[ext]');
assert.deepEqual(chunkFileNames(chunkInfoMocks[0]), `build/chunk.tsx.js`);
assert.deepEqual(entryFileNames(chunkInfoMocks[0]), `build/chunk.tsx.js`);
assert.deepEqual(chunkFileNames(chunkInfoMocks[1]), 'build/app-chunk.tsx.js');
assert.deepEqual(entryFileNames(chunkInfoMocks[1]), 'build/app-chunk.tsx.js');
const relBuildDev = path.relative(cwd, chunkInfoMocks[1].name);
const sanitizedBuildDev = relBuildDev
.replace(/^\(\.\.\/\)+/, '')
.replace(/^\/+/, '')
.replace(/\//g, '-');
const expectedBuildDevChunk = `build/${sanitizedBuildDev}.js`;
assert.deepEqual(chunkFileNames(chunkInfoMocks[1]), expectedBuildDevChunk);
assert.deepEqual(entryFileNames(chunkInfoMocks[1]), expectedBuildDevChunk);

assert.deepEqual(build.dynamicImportVarsOptions?.exclude, [/./]);
assert.deepEqual(build.ssr, undefined);
Expand Down Expand Up @@ -225,7 +239,9 @@ test('command: build, mode: production', async () => {
assert.deepEqual(plugin.enforce, 'pre');
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'dist')));
assert.deepEqual(build.emptyOutDir, undefined);
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);

assert.deepEqual(outputOptions.assetFileNames, 'assets/[hash]-[name].[ext]');
assert.deepEqual(outputOptions.chunkFileNames, 'build/q-[hash].js');
Expand Down Expand Up @@ -267,7 +283,9 @@ test('command: build, --mode production (client)', async () => {

assert.deepEqual(opts.target, 'client');
assert.deepEqual(opts.buildMode, 'production');
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'root'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'root')),
]);
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'client-dist')));
assert.deepEqual(build.emptyOutDir, undefined);
});
Expand Down Expand Up @@ -296,7 +314,9 @@ test('command: build, --ssr entry.server.tsx', async () => {
assert.deepEqual(plugin.enforce, 'pre');
assert.deepEqual(build.outDir, normalizePath(resolve(cwd, 'server')));
assert.deepEqual(build.emptyOutDir, undefined);
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'entry.server.tsx'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'entry.server.tsx')),
]);

assert.deepEqual(outputOptions.assetFileNames, 'assets/[hash]-[name].[ext]');
assert.isFunction(outputOptions.chunkFileNames);
Expand Down Expand Up @@ -337,7 +357,9 @@ test('command: serve, --mode ssr', async () => {
assert.deepEqual(opts.buildMode, 'development');
assert.deepEqual(build.minify, undefined);
assert.deepEqual(build.ssr, undefined);
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'renderz.tsx'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'renderz.tsx')),
]);
assert.deepEqual(c.build.outDir, normalizePath(resolve(cwd, 'ssr-dist')));
assert.deepEqual(build.emptyOutDir, undefined);
assert.deepEqual(c.publicDir, undefined);
Expand Down Expand Up @@ -366,7 +388,9 @@ test('command: serve, --mode ssr with build.assetsDir', async () => {
assert.deepEqual(opts.buildMode, 'development');
assert.deepEqual(build.minify, undefined);
assert.deepEqual(build.ssr, undefined);
assert.deepEqual(rollupOptions.input, [normalizePath(resolve(cwd, 'src', 'renderz.tsx'))]);
assert.deepEqual((rollupOptions.input as string[]).map(normalizePath), [
normalizePath(resolve(cwd, 'src', 'renderz.tsx')),
]);
assert.deepEqual(c.build.outDir, normalizePath(resolve(cwd, 'ssr-dist')));
assert.deepEqual(build.emptyOutDir, undefined);
assert.deepEqual(c.publicDir, undefined);
Expand Down
Loading