ReviewOS

also looking at this

loghqorg/loghq

refactor(ui): use shared auth submit buttons

#13
Merged glennmichael123 wants to merge refactor/loghq-shared-controls into main
4 files +74 -3
tests/unit/shared-controls.test.tsadded+63-0
Changes to tests/unit/shared-controls.test.ts
@@ -0,0 +1,63 @@
1import { describe, expect, test } from 'bun:test'
2import { readFileSync } from 'node:fs'
3import { resolve } from 'node:path'
4import theme from '../../config/crosswind'
5import { processComponents } from '../../node_modules/@stacksjs/stx/dist/component-renderer.js'
6import { loadCssEngine } from '../../node_modules/@stacksjs/stx/dist/dev-server/ts-css.js'
7import { mergeCssConfig } from '../../node_modules/@stacksjs/stx/dist/ts-css-config.js'
8
9const root = resolve(import.meta.dir, '../..')
10
11describe('shared auth submit controls', () => {
12 for (const [page, labels] of [
13 ['login', ['Sign in', 'Verify and sign in']],
14 ['register', ['Create account']],
15 ] as const) {
16 test(`${page} renders real submit buttons with initial names and live parent bindings`, async () => {
17 const file = resolve(root, `resources/views/${page}.stx`)
18 const source = readFileSync(file, 'utf8')
19 const controls = source.match(/<Button\b[^]*?<\/Button>/g) || []
20 expect(controls).toHaveLength(labels.length)
21 expect(source).not.toMatch(/<button\b[^>]*type="submit"/)
22
23 for (const [index, control] of controls.entries()) {
24 const dependencies = new Set<string>()
25 const html = await processComponents(control, {
26 __stx_client_signal_names: ['loading'],
27 __importedComponents: new Map([['button', resolve(root, 'node_modules/@stacksjs/components/src/ui/button/Button.stx')]]),
28 }, file, {
29 componentsDir: resolve(root, 'resources/components'),
30 }, dependencies)
31 expect([...dependencies].some(path => path.endsWith('/Button.stx'))).toBe(true)
32 expect(html).not.toContain('<Button')
33 expect(html).not.toContain('[Component Error')
34 expect(html).toContain('type="submit"')
35 expect(html).toContain(labels[index])
36 expect(html).toContain('auth-submit')
37 expect(html).toContain('w-full')
38 expect(html).toContain('text-sm')
39 expect(html).toContain('data-stx-parent-bindings')
40 expect(html).toContain('loading()')
41 // A label binding belongs to Button, not :text on its root, which
42 // would destroy its accessible slot and internal state elements.
43 expect(control).toContain(':label=')
44 expect(control).toContain(':disabled="loading()"')
45 expect(control).not.toContain(':text=')
46 }
47 })
48 }
49
50 test('the auth sizing and appearance overrides compile with explicit precedence', async () => {
51 const engine = await loadCssEngine()
52 if (!engine) throw new Error('The installed STX CSS engine is required')
53 const generator = new engine.CSSGenerator(mergeCssConfig(engine.defaultConfig || engine.config, theme).config)
54 generator.generate('auth-submit')
55 const css = generator.toCSS(false, false)
56 expect(css).toContain('.auth-submit')
57 expect(css).toContain('!important')
58 expect(css).toContain('0.625rem')
59 expect(css).toContain('color-mix(in srgb,var(--accent) 88%,#000)')
60 expect(css).toContain('opacity: 0.6 !important')
61 expect(css).toContain('cursor: default !important')
62 })
63})