Skip to content

Commit 2cd8d7c

Browse files
committed
fix: updated tests, added vite config cli auto-gen.
1 parent 2f877da commit 2cd8d7c

24 files changed

+2237
-270
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[![npm version](https://img.shields.io/npm/v/@austinserb/react-zero-ui)](https://www.npmjs.com/package/@austinserb/react-zero-ui)
66
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7-
![CI](https://github.com/austin1serb/react-zero-ui/actions/workflows/ci.yaml/badge.svg)
7+
![CI](https://github.com/austin1serb/react-zero-ui/actions/workflows/ci.yml/badge.svg?branch=main)
88

99
## Why Zero-UI?
1010

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"preinstall": "npx only-allow pnpm",
1111
"test": "pnpm -r test",
1212
"prepack:core": "pnpm -F @austinserb/react-zero-ui pack --pack-destination ./dist",
13-
"prepack:cli": "pnpm -F create-zero-ui pack --pack-destination ./dist",
1413
"i-tarball": "node scripts/install-local-tarball.js",
1514
"lint": "eslint .",
1615
"lint:fix": "eslint . --fix"

packages/cli/bin.js

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,34 @@ import { existsSync } from 'node:fs';
33
import { spawnSync } from 'node:child_process';
44
import { resolve } from 'node:path';
55

6-
(async () => {
7-
const cwd = process.cwd();
8-
const targetDir = process.argv[2] ?? '.';
9-
const full = resolve(cwd, targetDir);
6+
const cwd = process.cwd();
7+
const target = resolve(cwd, process.argv[2] ?? '.');
108

11-
/* 1️⃣ ensure package.json */
12-
if (!existsSync(resolve(full, 'package.json'))) {
13-
spawnSync('npm', ['init', '-y'], { cwd: full, stdio: 'inherit' });
14-
}
9+
/* 🔍 pick the package manager */
10+
const pm =
11+
existsSync(resolve(target, 'pnpm-lock.yaml')) ? 'pnpm' :
12+
existsSync(resolve(target, 'yarn.lock')) ? 'yarn' :
13+
'npm';
1514

16-
/* 2️⃣ install runtime lib as production dependency */
17-
spawnSync(
18-
'npm',
19-
['install', '@austinserb/react-zero-ui'],
20-
{ cwd: full, stdio: 'inherit' }
21-
);
15+
const exec = (cmd, args) =>
16+
spawnSync(pm, [cmd, ...args], { cwd: target, stdio: 'inherit' });
2217

23-
/* 3️⃣ install build tools as dev dependencies */
24-
spawnSync(
25-
'npm',
26-
[
27-
'install', '--save-dev',
28-
'postcss', 'tailwindcss', '@tailwindcss/postcss'
29-
],
30-
{ cwd: full, stdio: 'inherit' }
31-
);
18+
/* 1️⃣ ensure package.json */
19+
if (!existsSync(resolve(target, 'package.json'))) exec('init', ['-y']);
3220

33-
/* 4️⃣ run the real CLI exported by the runtime */
34-
const mod = await import('@austinserb/react-zero-ui/cli');
35-
const cli = typeof mod.default === 'function' ? mod.default : mod;
36-
if (typeof cli === 'function') {
37-
cli(process.argv.slice(3)); // pass any extra args
38-
console.log('\n🎉 Zero-UI installed. Run `npm run dev`!\n');
39-
} else {
40-
console.error('[Zero-UI] CLI entry is not a function.');
41-
process.exit(1);
42-
}
43-
})();
21+
/* 2️⃣ runtime dependency */
22+
exec(pm === 'yarn' ? 'add' : 'install', ['@austinserb/react-zero-ui']);
23+
24+
/* 3️⃣ dev deps */
25+
exec(pm === 'yarn' ? 'add' : 'install',
26+
['postcss', 'tailwindcss', '@tailwindcss/postcss', '--save-dev']);
27+
28+
/* 4️⃣ handoff */
29+
const { default: zeroUiCli } = await import('@austinserb/react-zero-ui/cli');
30+
if (typeof zeroUiCli === 'function') {
31+
zeroUiCli(process.argv.slice(3));
32+
console.log(`\n🎉 Zero-UI installed. Run \`${pm} run dev\`!\n`);
33+
} else {
34+
console.error('[Zero-UI] CLI entry is not a function.');
35+
process.exit(1);
36+
}
Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,29 @@
11
import { defineConfig } from "@playwright/test";
22
import path from "node:path";
33
import { fileURLToPath } from "node:url";
4-
import net from "node:net";
54

65
const __dirname = path.dirname(fileURLToPath(import.meta.url));
7-
console.log(__dirname);
86

9-
// Utility function to check if a port is in use
10-
const checkPortAvailability = (port, host = 'localhost') => {
11-
return new Promise((resolve) => {
12-
const server = net.createServer();
13-
14-
server.listen(port, host, () => {
15-
server.once('close', () => {
16-
resolve(false); // Port is available
17-
});
18-
server.close();
19-
});
20-
21-
server.on('error', () => {
22-
resolve(true); // Port is in use
23-
});
24-
});
25-
};
26-
27-
// Check port and show warning if needed
287
const PORT = 3000;
298
const BASE_URL = `http://localhost:${PORT}`;
309

31-
const portInUse = await checkPortAvailability(PORT);
32-
if (portInUse && !process.env.CI) {
33-
console.warn(`⚠️ WARNING: Port ${PORT} is already in use!`);
34-
console.warn(` This might interfere with your tests if it's not your Next.js dev server.`);
35-
console.warn(` Make sure your Next.js app is running on ${BASE_URL} or stop other services using this port.`);
36-
console.warn(` Tests will attempt to reuse the existing server.`);
37-
}
3810

3911
export default defineConfig({
4012
testDir: "../e2e", // all E2E specs live here
4113
workers: 2,
4214
timeout: 10000,
4315
reporter: "null",
16+
globalSetup: path.resolve(__dirname, "../helpers/globalSetup.next.js"),
4417

4518
use: {
4619
headless: true,
4720
baseURL: BASE_URL,
4821

4922
},
5023

51-
5224
// One project = one fixture app (Next, Vite, etc.)
5325
projects: [
5426
{
55-
name: "cli-setup",
56-
testMatch: /.*cli-next\.spec\.js/,
57-
},
58-
{
59-
dependencies: ["cli-setup"],
6027
name: "next-e2e",
6128
testMatch: /.*next\.spec\.js/,
6229
use: {
@@ -65,9 +32,8 @@ export default defineConfig({
6532
},
6633
],
6734
webServer: {
68-
command: "npm run dev",
35+
command: "pnpm run dev",
6936
cwd: path.resolve(__dirname, "../fixtures/next"),
7037
url: BASE_URL,
71-
reuseExistingServer: !process.env.CI, // speeds local runs
7238
},
7339
});
Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,39 @@
11
import { defineConfig } from "@playwright/test";
22
import path from "node:path";
33
import { fileURLToPath } from "node:url";
4-
import net from "node:net";
54

65
const __dirname = path.dirname(fileURLToPath(import.meta.url));
7-
console.log(__dirname);
86

9-
10-
// Utility function to check if a port is in use
11-
const checkPortAvailability = (port, host = 'localhost') => {
12-
return new Promise((resolve) => {
13-
const server = net.createServer();
14-
15-
server.listen(port, host, () => {
16-
server.once('close', () => {
17-
resolve(false); // Port is available
18-
});
19-
server.close();
20-
});
21-
22-
server.on('error', () => {
23-
resolve(true); // Port is in use
24-
});
25-
});
26-
};
27-
28-
// Check port and show warning if needed
297
const PORT = 5173;
308
const BASE_URL = `http://localhost:${PORT}`;
319

32-
const portInUse = await checkPortAvailability(PORT);
33-
if (portInUse && !process.env.CI) {
34-
console.warn(`⚠️ WARNING: Port ${PORT} is already in use!`);
35-
console.warn(` This might interfere with your tests if it's not your Vite dev server.`);
36-
console.warn(` Make sure your Vite app is running on ${BASE_URL} or stop other services using this port.`);
37-
console.warn(` Tests will attempt to reuse the existing server.`);
38-
}
39-
4010

4111
export default defineConfig({
4212
testDir: "../e2e", // all E2E specs live here
4313
workers: 2,
4414
timeout: 10000,
4515
reporter: "null",
16+
globalSetup: path.resolve(__dirname, "../helpers/globalSetup.vite.js"),
4617

4718
use: {
4819
headless: true,
49-
baseURL: "http://localhost:5173",
20+
baseURL: BASE_URL,
21+
5022
},
5123

5224
// One project = one fixture app (Next, Vite, etc.)
5325
projects: [
54-
5526
{
56-
5727
name: "vite-e2e",
5828
testMatch: /.*vite\.spec\.js/,
5929
use: {
60-
baseURL: "http://localhost:5173",
30+
baseURL: BASE_URL,
6131
},
6232
},
6333
],
6434
webServer: {
65-
command: "npm run dev",
35+
command: "pnpm run dev",
6636
cwd: path.resolve(__dirname, "../fixtures/vite"),
67-
url: "http://localhost:5173",
68-
reuseExistingServer: !process.env.CI, // speeds local runs
37+
url: BASE_URL,
6938
},
7039
});
Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,30 @@
1-
import { test as base, expect } from '@playwright/test';
2-
import { resetZeroUiState } from './resetProjectState';
1+
import { test, expect } from '@playwright/test';
32
import path from 'node:path';
4-
import { fileURLToPath } from 'node:url';
5-
import { spawnSync } from 'node:child_process';
63
import { existsSync, readFileSync } from 'node:fs';
4+
import { fileURLToPath } from 'node:url';
75

8-
const test = base.extend({});
96
const __dirname = path.dirname(fileURLToPath(import.meta.url));
10-
console.log('__dirname: ', __dirname);
11-
const projectDir = path.resolve(__dirname, '../fixtures/next');
12-
13-
const zeroUiBin = path.resolve(__dirname, '../../src/cli/init.cjs'); // library CLI
14-
15-
16-
test.beforeAll(() => resetZeroUiState(projectDir));
17-
18-
19-
test.describe('Zero-UI Next.js CLI', () => {
20-
21-
test('init CLI scaffolds project', () => {
22-
// run zero-ui init
23-
spawnSync('node', [zeroUiBin], { cwd: projectDir, stdio: 'inherit' });
24-
25-
const attrsPath = path.join(projectDir, '.zero-ui/attributes.js');
26-
const tsconfPath = path.join(projectDir, 'tsconfig.json');
27-
28-
// assert attributes.js
29-
expect(existsSync(attrsPath), '.zero-ui/attributes.js should exist').toBeTruthy();
30-
const attrsContent = readFileSync(attrsPath, 'utf8');
31-
expect(attrsContent).toContain('export const bodyAttributes');
32-
33-
// assert tsconfig.json
34-
const tsconf = JSON.parse(readFileSync(tsconfPath, 'utf8'));
35-
expect(tsconf.compilerOptions.paths['@zero-ui/attributes']).toEqual(
36-
['./.zero-ui/attributes.js']
37-
);
38-
});
397

8+
const projectDir = path.resolve(__dirname, '../fixtures/next');
409

41-
});
10+
test('Next CLI scaffolds .zero-ui + tsconfig + postcss', async () => {
11+
// CLI setup is handled by global setup, just verify the results
12+
const attrs = path.join(projectDir, '.zero-ui/attributes.js');
13+
const tsc = path.join(projectDir, 'tsconfig.json');
14+
const post = path.join(projectDir, 'postcss.config.mjs');
15+
16+
await expect.poll(() => existsSync(attrs)).toBeTruthy();
17+
await expect.poll(() => readFileSync(attrs, 'utf8'))
18+
.toContain('export const bodyAttributes');
19+
20+
await expect.poll(() => {
21+
if (!existsSync(tsc)) return false;
22+
const conf = JSON.parse(readFileSync(tsc, 'utf8'));
23+
return conf.compilerOptions?.paths?.['@zero-ui/attributes']?.[0] === './.zero-ui/attributes.js';
24+
}).toBeTruthy();
25+
26+
await expect.poll(() => {
27+
if (!existsSync(post)) return false;
28+
return readFileSync(post, 'utf8').includes('@austinserb/react-zero-ui/postcss');
29+
}).toBeTruthy();
30+
});
Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,25 @@
1-
import { test as base, expect } from '@playwright/test';
2-
import { resetZeroUiState } from './resetProjectState';
1+
import { test, expect } from '@playwright/test';
32
import path from 'node:path';
4-
import { fileURLToPath } from 'node:url';
5-
import { spawnSync } from 'node:child_process';
63
import { existsSync, readFileSync } from 'node:fs';
4+
import { fileURLToPath } from 'node:url';
75

8-
const test = base.extend({});
96
const __dirname = path.dirname(fileURLToPath(import.meta.url));
10-
const projectDir = path.resolve(__dirname, '../fixtures/vite');
11-
12-
const zeroUiBin = path.resolve(__dirname, '../../src/cli/init.cjs'); // library CLI
13-
14-
15-
test.beforeAll(() => resetZeroUiState(projectDir));
16-
17-
18-
test.describe('Zero-UI Vite CLI', () => {
19-
20-
test('init CLI scaffolds project', () => {
21-
// run zero-ui init
22-
spawnSync('node', [zeroUiBin], { cwd: projectDir, stdio: 'inherit' });
23-
24-
const attrsPath = path.join(projectDir, '.zero-ui/attributes.js');
25-
26-
// assert attributes.js exists and has correct exports
27-
expect(existsSync(attrsPath), '.zero-ui/attributes.js should exist').toBeTruthy();
28-
const attrsContent = readFileSync(attrsPath, 'utf8');
29-
expect(attrsContent).toContain('export const bodyAttributes');
30-
31-
// Vite apps use direct imports, no tsconfig modification needed
32-
// Users import from './.zero-ui/attributes.js' directly
33-
});
347

8+
const projectDir = path.resolve(__dirname, '../fixtures/vite');
359

36-
});
10+
test('Vite CLI scaffolds .zero-ui + vite.config', async () => {
11+
// CLI setup is handled by global setup, just verify the results
12+
const attrs = path.join(projectDir, '.zero-ui/attributes.js');
13+
const vite = path.join(projectDir, 'vite.config.ts');
14+
15+
await expect.poll(() => existsSync(attrs)).toBeTruthy();
16+
await expect.poll(() => readFileSync(attrs, 'utf8'))
17+
.toContain('export const bodyAttributes');
18+
19+
await expect.poll(() => {
20+
if (!existsSync(vite)) return false;
21+
const src = readFileSync(vite, 'utf8');
22+
return /from ['"]@austinserb\/react-zero-ui\/vite['"]/.test(src) &&
23+
/\bplugins:\s*\[.*zeroUI\(\).*]/s.test(src);
24+
}).toBeTruthy();
25+
});

packages/core/__tests__/e2e/resetProjectState.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

packages/core/__tests__/fixtures/next/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"clean": "rm -rf .next node_modules package-lock.json"
99
},
1010
"dependencies": {
11-
"@austinserb/react-zero-ui": "file:/Users/austinserb/Desktop/React-Zero/react-zero-ui/dist/austinserb-react-zero-ui-1.0.18.tgz",
1211
"next": "^15.0.0",
1312
"react": "^18.2.0",
1413
"react-dom": "^18.2.0"

0 commit comments

Comments
 (0)