Skip to content

Commit f77b6ba

Browse files
committed
updated tests, and moved readme to root dir
1 parent e3f28f3 commit f77b6ba

File tree

21 files changed

+436
-57
lines changed

21 files changed

+436
-57
lines changed
File renamed without changes.

init-react-zero-ui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "create-zero-ui",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"type": "module",
55
"main": "./bin.js",
66
"bin": {
@@ -16,4 +16,4 @@
1616
"tailwindcss": "^4.0.0",
1717
"@tailwindcss/postcss": "^4.1.8"
1818
}
19-
}
19+
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/__tests__/config/playwright.next.config.js

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
11
import { defineConfig } from "@playwright/test";
22
import path from "node:path";
33
import { fileURLToPath } from "node:url";
4+
import net from "node:net";
45

56
const __dirname = path.dirname(fileURLToPath(import.meta.url));
67
console.log(__dirname);
78

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
28+
const PORT = 3000;
29+
const BASE_URL = `http://localhost:${PORT}`;
30+
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+
}
38+
839
export default defineConfig({
940
testDir: "../e2e", // all E2E specs live here
1041
workers: 2,
@@ -13,9 +44,11 @@ export default defineConfig({
1344

1445
use: {
1546
headless: true,
16-
baseURL: "http://localhost:3000",
47+
baseURL: BASE_URL,
48+
1749
},
1850

51+
1952
// One project = one fixture app (Next, Vite, etc.)
2053
projects: [
2154
{
@@ -27,14 +60,14 @@ export default defineConfig({
2760
name: "next-e2e",
2861
testMatch: /.*next\.spec\.js/,
2962
use: {
30-
baseURL: "http://localhost:3000",
63+
baseURL: BASE_URL,
3164
},
3265
},
3366
],
3467
webServer: {
3568
command: "npm run dev",
3669
cwd: path.resolve(__dirname, "../fixtures/next"),
37-
url: "http://localhost:3000",
70+
url: BASE_URL,
3871
reuseExistingServer: !process.env.CI, // speeds local runs
3972
},
4073
});

runtime/__tests__/config/playwright.vite.config.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,43 @@
11
import { defineConfig } from "@playwright/test";
22
import path from "node:path";
33
import { fileURLToPath } from "node:url";
4+
import net from "node:net";
45

56
const __dirname = path.dirname(fileURLToPath(import.meta.url));
67
console.log(__dirname);
78

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
29+
const PORT = 5173;
30+
const BASE_URL = `http://localhost:${PORT}`;
31+
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+
40+
841
export default defineConfig({
942
testDir: "../e2e", // all E2E specs live here
1043
workers: 2,

runtime/__tests__/e2e/next.spec.js

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ test.describe('Zero-UI Next.js Integration', () => {
99

1010
test('Browser loads initial theme on body', async ({ page }) => {
1111

12-
await page.goto('/', { waitUntil: 'domcontentloaded' });
12+
await page.goto('/', { waitUntil: 'networkidle' });
1313

1414
// body attribute check + theme = initial theme
1515
const theme = await page.getAttribute('body', 'data-theme');
@@ -43,4 +43,61 @@ test.describe('Zero-UI Next.js Integration', () => {
4343
expect(before).toBe('light');
4444
expect(after).toBe('dark');
4545
});
46+
47+
test('theme2 toggles on button click', async ({ page }) => {
48+
await page.goto('/');
49+
50+
// Wait for hydration and button
51+
const button = page.getByTestId('theme-toggle-secondary');
52+
await expect(button).toBeVisible();
53+
54+
// Wait for container to ensure styles are applied
55+
const container = page.getByTestId('theme-container-secondary');
56+
await expect(container).toHaveClass(/theme-2-light:/); // initially light
57+
58+
// Read initial theme attribute
59+
const before = await page.getAttribute('body', 'data-theme-2');
60+
console.log('🌞 before:', before);
61+
62+
// Click to toggle
63+
await button.click();
64+
65+
// Wait for DOM to reflect change
66+
await page.waitForTimeout(100); // Optional: add debounce if needed
67+
const after = await page.getAttribute('body', 'data-theme-2');
68+
console.log('🌙 after:', after);
69+
70+
// Assertion
71+
expect(before).toBe('light');
72+
expect(after).toBe('dark');
73+
});
74+
75+
test('theme3 toggles on button click', async ({ page }) => {
76+
await page.goto('/');
77+
78+
// Wait for hydration and button
79+
const button = page.getByTestId('theme-toggle-3');
80+
await expect(button).toBeVisible();
81+
82+
// Wait for container to ensure styles are applied
83+
const container = page.getByTestId('theme-container-3');
84+
await expect(container).toHaveClass(/theme-three-light:/); // initially light
85+
86+
// Read initial theme attribute
87+
const before = await page.getAttribute('body', 'data-theme-three');
88+
console.log('🌞 before:', before);
89+
90+
// Click to toggle
91+
await button.click();
92+
93+
// Wait for DOM to reflect change
94+
await page.waitForTimeout(100); // Optional: add debounce if needed
95+
const after = await page.getAttribute('body', 'data-theme-three');
96+
console.log('🌙 after:', after);
97+
98+
// Assertion
99+
expect(before).toBe('light');
100+
expect(after).toBe('dark');
101+
});
102+
46103
});

runtime/__tests__/e2e/vite.spec.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,60 @@ test.describe('Zero-UI Vite Integration', () => {
4040
expect(before).toBe('light');
4141
expect(after).toBe('dark');
4242
});
43+
44+
test('theme2 toggles on button click', async ({ page }) => {
45+
await page.goto('/');
46+
47+
// Wait for hydration and button
48+
const button = page.getByTestId('theme-toggle-secondary');
49+
await expect(button).toBeVisible();
50+
51+
// Wait for container to ensure styles are applied
52+
const container = page.getByTestId('theme-container-secondary');
53+
await expect(container).toHaveClass(/theme-2-light:/); // initially light
54+
55+
// Read initial theme attribute
56+
const before = await page.getAttribute('body', 'data-theme-2');
57+
console.log('🌞 before:', before);
58+
59+
// Click to toggle
60+
await button.click();
61+
62+
// Wait for DOM to reflect change
63+
await page.waitForTimeout(100); // Optional: add debounce if needed
64+
const after = await page.getAttribute('body', 'data-theme-2');
65+
console.log('🌙 after:', after);
66+
67+
// Assertion
68+
expect(before).toBe('light');
69+
expect(after).toBe('dark');
70+
});
71+
72+
test('theme3 toggles on button click', async ({ page }) => {
73+
await page.goto('/');
74+
75+
// Wait for hydration and button
76+
const button = page.getByTestId('theme-toggle-3');
77+
await expect(button).toBeVisible();
78+
79+
// Wait for container to ensure styles are applied
80+
const container = page.getByTestId('theme-container-3');
81+
await expect(container).toHaveClass(/theme-three-light:/); // initially light
82+
83+
// Read initial theme attribute
84+
const before = await page.getAttribute('body', 'data-theme-three');
85+
console.log('🌞 before:', before);
86+
87+
// Click to toggle
88+
await button.click();
89+
90+
// Wait for DOM to reflect change
91+
await page.waitForTimeout(100); // Optional: add debounce if needed
92+
const after = await page.getAttribute('body', 'data-theme-three');
93+
console.log('🌙 after:', after);
94+
95+
// Assertion
96+
expect(before).toBe('light');
97+
expect(after).toBe('dark');
98+
});
4399
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* AUTO-GENERATED - DO NOT EDIT */
22
export declare const bodyAttributes: {
33
"data-theme": "dark" | "light";
4+
"data-theme-2": "dark" | "light";
5+
"data-theme-three": "dark" | "light";
46
};
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/* AUTO-GENERATED - DO NOT EDIT */
22
export const bodyAttributes = {
3-
"data-theme": "light"
3+
"data-theme": "light",
4+
"data-theme-2": "light",
5+
"data-theme-three": "light"
46
};

runtime/__tests__/fixtures/next/app/page.tsx

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,64 @@ import useUI from "@austinserb/react-zero-ui";
44

55
export default function Page() {
66
const [, setTheme] = useUI<"light" | "dark">("theme", "light");
7-
7+
const [, setTheme2] = useUI<"light" | "dark">("theme-2", "light");
8+
const [, setThemeThree] = useUI<"light" | "dark">("themeThree", "light");
89
return (
9-
<div
10-
className="theme-light:bg-gray-100 theme-dark:bg-gray-900 text-blue-900"
11-
data-testid="theme-container"
12-
>
13-
<button
14-
type="button"
15-
onClick={() => setTheme((prev) => (prev === "light" ? "dark" : "light"))}
16-
className="border-2 border-red-500"
17-
data-testid="theme-toggle"
10+
<>
11+
<div
12+
className="theme-light:bg-gray-100 theme-dark:bg-gray-900 text-blue-900"
13+
data-testid="theme-container"
14+
>
15+
<button
16+
type="button"
17+
onClick={() => setTheme((prev) => (prev === "light" ? "dark" : "light"))}
18+
className="border-2 border-red-500"
19+
data-testid="theme-toggle"
20+
>
21+
Toggle Theme
22+
</button>
23+
<div className="theme-light:bg-gray-100 theme-dark:bg-gray-900">
24+
Theme: <span className="theme-dark:block hidden">Dark</span> <span className="theme-light:block hidden">Light</span>
25+
</div>
26+
</div>
27+
28+
<hr />
29+
30+
<div
31+
className="theme-2-light:bg-gray-100 theme-2-dark:bg-gray-900"
32+
data-testid="theme-container-secondary"
33+
>
34+
<button
35+
type="button"
36+
onClick={() => setTheme2((prev) => (prev === "light" ? "dark" : "light"))}
37+
className="border-2 border-red-500"
38+
data-testid="theme-toggle-secondary"
39+
>
40+
Toggle Theme Secondary
41+
</button>
42+
<div className="theme-2-light:bg-gray-100 theme-2-dark:bg-gray-900">
43+
Theme: <span className="theme-2-dark:block hidden">Dark</span> <span className="theme-2-light:block hidden">Light</span>
44+
</div>
45+
</div>
46+
47+
<hr />
48+
49+
<div
50+
className="theme-three-light:bg-gray-100 theme-three-dark:bg-gray-900"
51+
data-testid="theme-container-3"
1852
>
19-
Toggle Theme
20-
</button>
21-
<div className="theme-light:bg-gray-100 theme-dark:bg-gray-900">
22-
Theme: <span className="theme-dark:block hidden">Dark</span> <span className="theme-light:block hidden">Light</span>
53+
<button
54+
type="button"
55+
onClick={() => setThemeThree((prev) => (prev === "light" ? "dark" : "light"))}
56+
className="border-2 border-red-500"
57+
data-testid="theme-toggle-3"
58+
>
59+
Toggle Theme 3
60+
</button>
61+
<div className="theme-three-light:bg-gray-100 theme-three-dark:bg-gray-900">
62+
Theme: <span className="theme-three-dark:block hidden">Dark</span> <span className="theme-three-light:block hidden">Light</span>
63+
</div>
2364
</div>
24-
</div>
65+
</>
2566
);
2667
}

0 commit comments

Comments
 (0)