@plumbus/ui 0.1.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/dist/.tsbuildinfo +1 -0
- package/dist/generators/__tests__/auth-generator.test.d.ts +2 -0
- package/dist/generators/__tests__/auth-generator.test.d.ts.map +1 -0
- package/dist/generators/__tests__/auth-generator.test.js +222 -0
- package/dist/generators/__tests__/auth-generator.test.js.map +1 -0
- package/dist/generators/__tests__/client-generator.test.d.ts +2 -0
- package/dist/generators/__tests__/client-generator.test.d.ts.map +1 -0
- package/dist/generators/__tests__/client-generator.test.js +224 -0
- package/dist/generators/__tests__/client-generator.test.js.map +1 -0
- package/dist/generators/__tests__/form-generator.test.d.ts +2 -0
- package/dist/generators/__tests__/form-generator.test.d.ts.map +1 -0
- package/dist/generators/__tests__/form-generator.test.js +192 -0
- package/dist/generators/__tests__/form-generator.test.js.map +1 -0
- package/dist/generators/__tests__/nextjs-template.test.d.ts +2 -0
- package/dist/generators/__tests__/nextjs-template.test.d.ts.map +1 -0
- package/dist/generators/__tests__/nextjs-template.test.js +214 -0
- package/dist/generators/__tests__/nextjs-template.test.js.map +1 -0
- package/dist/generators/auth-generator.d.ts +31 -0
- package/dist/generators/auth-generator.d.ts.map +1 -0
- package/dist/generators/auth-generator.js +292 -0
- package/dist/generators/auth-generator.js.map +1 -0
- package/dist/generators/client-generator.d.ts +31 -0
- package/dist/generators/client-generator.d.ts.map +1 -0
- package/dist/generators/client-generator.js +336 -0
- package/dist/generators/client-generator.js.map +1 -0
- package/dist/generators/form-generator.d.ts +47 -0
- package/dist/generators/form-generator.d.ts.map +1 -0
- package/dist/generators/form-generator.js +189 -0
- package/dist/generators/form-generator.js.map +1 -0
- package/dist/generators/index.d.ts +9 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +6 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/nextjs-template.d.ts +44 -0
- package/dist/generators/nextjs-template.d.ts.map +1 -0
- package/dist/generators/nextjs-template.js +444 -0
- package/dist/generators/nextjs-template.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/instructions/auth-generator.md +154 -0
- package/instructions/client-generator.md +149 -0
- package/instructions/form-generator.md +157 -0
- package/instructions/framework.md +108 -0
- package/instructions/nextjs-template.md +160 -0
- package/instructions/patterns.md +109 -0
- package/instructions/testing.md +211 -0
- package/package.json +52 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
The UI package uses Vitest for unit tests and optionally Playwright via `@vitest/browser` for browser-based tests.
|
|
4
|
+
|
|
5
|
+
## Test Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Unit tests (Node)
|
|
9
|
+
pnpm --filter @plumbus/ui test
|
|
10
|
+
|
|
11
|
+
# Browser tests (Playwright + Chromium)
|
|
12
|
+
pnpm --filter @plumbus/ui test:browser
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Config files:
|
|
16
|
+
- Unit tests: uses default Vitest config from workspace root
|
|
17
|
+
- Browser tests: `vitest.config.browser.ts` — runs in Chromium via `@vitest/browser`
|
|
18
|
+
|
|
19
|
+
## Test Files
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/generators/__tests__/
|
|
23
|
+
client-generator.test.ts # 200+ lines — client/hook/flow generation
|
|
24
|
+
auth-generator.test.ts # 160+ lines — auth types/functions/hooks
|
|
25
|
+
form-generator.test.ts # 220+ lines — Zod schema introspection
|
|
26
|
+
nextjs-template.test.ts # 180+ lines — project scaffold
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Testing Strategy
|
|
30
|
+
|
|
31
|
+
All generators produce **strings of source code**. Tests verify the generated code by:
|
|
32
|
+
1. Checking string contents with `toContain()` for expected patterns.
|
|
33
|
+
2. Validating JSON outputs with `JSON.parse()` (e.g. package.json).
|
|
34
|
+
3. Verifying structural properties (function names, type names, imports).
|
|
35
|
+
|
|
36
|
+
## Writing Tests for Generators
|
|
37
|
+
|
|
38
|
+
### Test a Capability-Based Generator
|
|
39
|
+
|
|
40
|
+
Create a mock `CapabilityContract` and pass it to the generator:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { describe, it, expect } from "vitest";
|
|
44
|
+
import { generateTypedClient } from "../client-generator.js";
|
|
45
|
+
import type { CapabilityContract } from "@plumbus/core";
|
|
46
|
+
|
|
47
|
+
const mockCap: CapabilityContract = {
|
|
48
|
+
name: "getUser",
|
|
49
|
+
kind: "query",
|
|
50
|
+
domain: "users",
|
|
51
|
+
description: "Get a user by ID",
|
|
52
|
+
input: {} as any,
|
|
53
|
+
output: {} as any,
|
|
54
|
+
access: { roles: ["admin"] },
|
|
55
|
+
effects: [],
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
describe("generateTypedClient", () => {
|
|
59
|
+
it("generates a GET client for query capabilities", () => {
|
|
60
|
+
const code = generateTypedClient(mockCap);
|
|
61
|
+
expect(code).toContain("export async function getUser");
|
|
62
|
+
expect(code).toContain('method: "GET"');
|
|
63
|
+
expect(code).toContain("/api/users/get-user");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("includes JSDoc when configured", () => {
|
|
67
|
+
const code = generateTypedClient(mockCap, { includeJsDoc: true });
|
|
68
|
+
expect(code).toContain("/** Get a user by ID */");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("uses custom base URL", () => {
|
|
72
|
+
const code = generateTypedClient(mockCap, { baseUrl: "https://api.example.com" });
|
|
73
|
+
expect(code).toContain("https://api.example.com/api/users/get-user");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Test a Config-Based Generator
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { generateAuthModule } from "../auth-generator.js";
|
|
82
|
+
|
|
83
|
+
describe("generateAuthModule", () => {
|
|
84
|
+
it("includes all auth sections", () => {
|
|
85
|
+
const code = generateAuthModule({ provider: "jwt" });
|
|
86
|
+
expect(code).toContain("interface AuthUser");
|
|
87
|
+
expect(code).toContain("function login");
|
|
88
|
+
expect(code).toContain("function useAuth");
|
|
89
|
+
expect(code).toContain("function RouteGuard");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("includes tenant context when multiTenant enabled", () => {
|
|
93
|
+
const code = generateAuthModule({ provider: "jwt", multiTenant: true });
|
|
94
|
+
expect(code).toContain("function useTenant");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("excludes tenant context by default", () => {
|
|
98
|
+
const code = generateAuthModule({ provider: "jwt" });
|
|
99
|
+
expect(code).not.toContain("useTenant");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Test Form Hint Extraction with Zod
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { z } from "zod";
|
|
108
|
+
import { extractFieldHint, extractFormHints } from "../form-generator.js";
|
|
109
|
+
import type { CapabilityContract } from "@plumbus/core";
|
|
110
|
+
|
|
111
|
+
describe("extractFieldHint", () => {
|
|
112
|
+
it("extracts string field", () => {
|
|
113
|
+
const hint = extractFieldHint("name", z.string().min(1).max(100));
|
|
114
|
+
expect(hint.fieldType).toBe("text");
|
|
115
|
+
expect(hint.required).toBe(true);
|
|
116
|
+
expect(hint.validation.minLength).toBe(1);
|
|
117
|
+
expect(hint.validation.maxLength).toBe(100);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("extracts enum field with options", () => {
|
|
121
|
+
const hint = extractFieldHint("role", z.enum(["admin", "user", "guest"]));
|
|
122
|
+
expect(hint.fieldType).toBe("select");
|
|
123
|
+
expect(hint.options).toEqual(["admin", "user", "guest"]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("handles optional fields", () => {
|
|
127
|
+
const hint = extractFieldHint("nickname", z.string().optional());
|
|
128
|
+
expect(hint.required).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("extracts default values", () => {
|
|
132
|
+
const hint = extractFieldHint("active", z.boolean().default(true));
|
|
133
|
+
expect(hint.required).toBe(false);
|
|
134
|
+
expect(hint.defaultValue).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("extractFormHints", () => {
|
|
139
|
+
it("extracts all fields from a capability", () => {
|
|
140
|
+
const cap = {
|
|
141
|
+
name: "createUser",
|
|
142
|
+
kind: "action",
|
|
143
|
+
domain: "users",
|
|
144
|
+
input: z.object({
|
|
145
|
+
name: z.string(),
|
|
146
|
+
email: z.string().email(),
|
|
147
|
+
role: z.enum(["admin", "user"]),
|
|
148
|
+
}),
|
|
149
|
+
} as unknown as CapabilityContract;
|
|
150
|
+
|
|
151
|
+
const hints = extractFormHints(cap);
|
|
152
|
+
expect(hints.fields).toHaveLength(3);
|
|
153
|
+
expect(hints.fields[0]!.name).toBe("name");
|
|
154
|
+
expect(hints.fields[1]!.validation.pattern).toBe("email");
|
|
155
|
+
expect(hints.fields[2]!.fieldType).toBe("select");
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Test Next.js Template Generation
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { generateNextjsTemplate, generatePackageJson } from "../nextjs-template.js";
|
|
164
|
+
|
|
165
|
+
describe("generateNextjsTemplate", () => {
|
|
166
|
+
it("generates valid package.json", () => {
|
|
167
|
+
const file = generatePackageJson({ appName: "My App" });
|
|
168
|
+
const parsed = JSON.parse(file.content);
|
|
169
|
+
expect(parsed.name).toBe("my-app");
|
|
170
|
+
expect(parsed.dependencies.next).toBeDefined();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("includes auth files when auth enabled", () => {
|
|
174
|
+
const files = generateNextjsTemplate({ appName: "Test", auth: true });
|
|
175
|
+
const paths = files.map((f) => f.path);
|
|
176
|
+
expect(paths).toContain("components/AuthProvider.tsx");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("generates capability pages", () => {
|
|
180
|
+
const cap = { name: "getUser", kind: "query", domain: "users" } as any;
|
|
181
|
+
const files = generateNextjsTemplate({ appName: "Test" }, [cap]);
|
|
182
|
+
const paths = files.map((f) => f.path);
|
|
183
|
+
expect(paths).toContain("app/get-user/page.tsx");
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Test Patterns Summary
|
|
189
|
+
|
|
190
|
+
| Pattern | When to Use |
|
|
191
|
+
|---------|-------------|
|
|
192
|
+
| `toContain(string)` | Verify specific code appears in output |
|
|
193
|
+
| `not.toContain(string)` | Verify code is excluded (e.g. optional features) |
|
|
194
|
+
| `JSON.parse(output)` | Validate JSON file content (package.json, tsconfig) |
|
|
195
|
+
| `files.map(f => f.path)` | Check generated file paths in multi-file output |
|
|
196
|
+
| Mock `CapabilityContract` | Any generator that takes a capability |
|
|
197
|
+
| Mock Zod schemas | Form hint extraction tests |
|
|
198
|
+
| Config variations | Test generator options (auth, baseUrl, multiTenant) |
|
|
199
|
+
|
|
200
|
+
## Running Specific Tests
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Run all UI tests
|
|
204
|
+
pnpm --filter @plumbus/ui test
|
|
205
|
+
|
|
206
|
+
# Run a specific test file
|
|
207
|
+
pnpm --filter @plumbus/ui test -- client-generator
|
|
208
|
+
|
|
209
|
+
# Run with watch mode
|
|
210
|
+
pnpm --filter @plumbus/ui test -- --watch
|
|
211
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plumbus/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plumbus UI — client generation and frontend templates",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"instructions"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"plumbus",
|
|
20
|
+
"ui",
|
|
21
|
+
"frontend"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/plumbus-framework/plumbus.git",
|
|
27
|
+
"directory": "packages/ui"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"zod": "^3.24.0",
|
|
34
|
+
"@plumbus/core": "0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@vitest/browser": "^3.0.0",
|
|
38
|
+
"playwright": "^1.52.0",
|
|
39
|
+
"typescript": "^5.7.0",
|
|
40
|
+
"vitest": "^3.0.0"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -b",
|
|
44
|
+
"dev": "tsc -b --watch",
|
|
45
|
+
"test": "vitest run --passWithNoTests",
|
|
46
|
+
"test:browser": "vitest run --config vitest.config.browser.ts --passWithNoTests",
|
|
47
|
+
"lint": "biome lint ./src",
|
|
48
|
+
"format": "biome format --write ./src",
|
|
49
|
+
"format:check": "biome format ./src",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|