mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
* [feat] Add Storybook setup and NodePreview story - Install and configure Storybook v9.1.1 for Vue 3 - Set up Storybook configuration with Vite integration - Add Pinia store support for Storybook environment - Create comprehensive NodePreview.stories.ts with multiple node examples: - KSampler node (complex node with multiple inputs/outputs) - CLIP Text Encode node (simple text input node) - VAE Decode node (image processing node) - Example with long markdown description - Configure project paths and aliases for Storybook - Stories demonstrate various ComfyUI node types with realistic mock data - Update tsconfig.eslint.json to include Storybook files - Fix ESLint issues with imports and number precision - Add Storybook ESLint plugin configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [feat] Improve Storybook configuration and setup - Add comprehensive PrimeVue theme setup with ComfyUI preset - Configure proper Vue app setup with Pinia stores, i18n, and services - Remove unused onboarding addon from Storybook dependencies - Improve Vite configuration with better chunking and alias resolution - Add proper CSS imports and styling for ComfyUI components 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [docs] Add comprehensive Storybook documentation - Add README.md explaining Storybook usage, benefits, and comparison with other tools - Add CLAUDE.md with development guidelines for working with Storybook - Include best practices, troubleshooting tips, and integration notes - Address PR review feedback for better developer onboarding 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [refactor] Remove ts-expect-error comment from Storybook preview 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [bugfix] Fix TypeScript errors in Load3D components and GLTF test - Fix type mismatches in Load3DScene eventConfig by casting string values to proper enum types (MaterialMode, CameraType, UpDirection) - Fix Uint8Array vs ArrayBuffer type issues in GLTF test by using .buffer property - Remove unused @ts-expect-error comment in Rectangle.ts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [feat] Add Chromatic GitHub Action for Storybook visual testing - Add automated visual regression testing for Storybook components - Configure workflow to run on main branch and PRs - Auto-accept changes on main branch for baseline updates - Uses build-storybook script for optimized builds 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [docs] Add Chromatic documentation to Storybook README - Document Chromatic visual testing integration - Add information about automated testing workflow - Include best practices for visual regression testing - Explain how to view and manage test results 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore(chromatic.yaml): restrict push branches to main only for better workflow management * [feat] Rebase branch onto main and update Storybook configuration - Rebase sno-storybook branch onto origin/main with latest changes - Update .storybook/main.ts with additional plugins and component configuration - Add icons and component resolvers for Storybook support - Update .gitignore with new entries - Regenerate package-lock.json after rebase conflicts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * [bugfix] Fix TypeScript errors in SubgraphNode type checking Add proper type validation for subgraph node selection before calling SubgraphNode-specific methods. This prevents undefined values from being passed to functions expecting SubgraphNode parameters. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(vite.config.mts): correct path alias for src directory to ensure proper resolution in the project refactor(vite.config.mts): adjust templates proxy configuration for better readability and maintainability * [feat] Remove bun.lock as it's now ignored * [bugfix] Fix Storybook builder require() error by converting main.ts to main.mjs - Convert .storybook/main.ts to main.mjs to resolve ES module compatibility - Use dynamic imports instead of static imports to avoid require() errors - Add .storybook directory to tsconfig.json includes - Storybook build and dev server now work correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore(storybook): replace main.mjs with main.ts for improved type safety and maintainability fix(storybook): remove unused import map plugins in Storybook configuration to prevent potential issues fix(storybook): update color palette store initialization to streamline code and improve readability * [feat] Optimize Chromatic workflow with automated PR status comments - Replace complex GitHub Script actions with edumserrano/find-create-or-update-comment@v3 - Add comprehensive PR comments showing Storybook build progress and results - Include build metrics: components, stories, visual changes, and errors - Add direct links to Chromatic builds and Storybook previews - Reduce workflow complexity by ~60 lines while maintaining functionality - Use native GitHub Actions expressions for cleaner maintainability 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * chore(chromatic.yaml): move permissions section inside the chromatic-deployment job for better organization and clarity * [fix] Resolve Vite CJS deprecation warning in Storybook config - Use dynamic import for mergeConfig to avoid CJS build warning - Replace static import with dynamic import in viteFinal function - Maintain type safety with separate type import - Fixes "The CJS build of Vite's Node API is deprecated" warning 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(chromatic.yaml): change edit-mode from replace to append to preserve existing comments in pull request * [fix] Replace __dirname with process.cwd() in Storybook config __dirname is not available in all environments. Using process.cwd() provides better compatibility and resolves path issues in Storybook. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feature: storybook-setting (#5088) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jin Yi <jin12cc@gmail.com>
164 lines
4.5 KiB
TypeScript
164 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { ASCII, GltfSizeBytes } from '@/types/metadataTypes'
|
|
|
|
import { getGltfBinaryMetadata } from '../../../../src/scripts/metadata/gltf'
|
|
|
|
describe('GLTF binary metadata parser', () => {
|
|
const createGLTFFileStructure = () => {
|
|
const header = new ArrayBuffer(GltfSizeBytes.HEADER)
|
|
const headerView = new DataView(header)
|
|
return { header, headerView }
|
|
}
|
|
|
|
const jsonToBinary = (json: object) => {
|
|
const jsonString = JSON.stringify(json)
|
|
const jsonData = new TextEncoder().encode(jsonString)
|
|
return jsonData
|
|
}
|
|
|
|
const createJSONChunk = (jsonData: ArrayBuffer) => {
|
|
const chunkHeader = new ArrayBuffer(GltfSizeBytes.CHUNK_HEADER)
|
|
const chunkView = new DataView(chunkHeader)
|
|
chunkView.setUint32(0, jsonData.byteLength, true)
|
|
chunkView.setUint32(4, ASCII.JSON, true)
|
|
return chunkHeader
|
|
}
|
|
|
|
const setVersionHeader = (headerView: DataView, version: number) => {
|
|
headerView.setUint32(4, version, true)
|
|
}
|
|
|
|
const setTypeHeader = (headerView: DataView, type: number) => {
|
|
headerView.setUint32(0, type, true)
|
|
}
|
|
|
|
const setTotalLengthHeader = (headerView: DataView, length: number) => {
|
|
headerView.setUint32(8, length, true)
|
|
}
|
|
|
|
const setHeaders = (headerView: DataView, jsonData: ArrayBuffer) => {
|
|
setTypeHeader(headerView, ASCII.GLTF)
|
|
setVersionHeader(headerView, 2)
|
|
setTotalLengthHeader(
|
|
headerView,
|
|
GltfSizeBytes.HEADER + GltfSizeBytes.CHUNK_HEADER + jsonData.byteLength
|
|
)
|
|
}
|
|
|
|
function createMockGltfFile(jsonContent: object): File {
|
|
const jsonData = jsonToBinary(jsonContent)
|
|
const { header, headerView } = createGLTFFileStructure()
|
|
|
|
setHeaders(headerView, jsonData.buffer)
|
|
|
|
const chunkHeader = createJSONChunk(jsonData.buffer)
|
|
|
|
const fileContent = new Uint8Array(
|
|
header.byteLength + chunkHeader.byteLength + jsonData.byteLength
|
|
)
|
|
fileContent.set(new Uint8Array(header), 0)
|
|
fileContent.set(new Uint8Array(chunkHeader), header.byteLength)
|
|
fileContent.set(jsonData, header.byteLength + chunkHeader.byteLength)
|
|
|
|
return new File([fileContent], 'test.glb', { type: 'model/gltf-binary' })
|
|
}
|
|
|
|
it('should extract workflow metadata from GLTF binary file', async () => {
|
|
const testWorkflow = {
|
|
nodes: [
|
|
{
|
|
id: 1,
|
|
type: 'TestNode',
|
|
pos: [100, 100]
|
|
}
|
|
],
|
|
links: []
|
|
}
|
|
|
|
const mockFile = createMockGltfFile({
|
|
asset: {
|
|
version: '2.0',
|
|
generator: 'ComfyUI GLTF Test',
|
|
extras: {
|
|
workflow: testWorkflow
|
|
}
|
|
},
|
|
scenes: []
|
|
})
|
|
|
|
const metadata = await getGltfBinaryMetadata(mockFile)
|
|
|
|
expect(metadata).toBeDefined()
|
|
expect(metadata.workflow).toBeDefined()
|
|
|
|
const workflow = metadata.workflow as {
|
|
nodes: Array<{ id: number; type: string }>
|
|
}
|
|
expect(workflow.nodes[0].id).toBe(1)
|
|
expect(workflow.nodes[0].type).toBe('TestNode')
|
|
})
|
|
|
|
it('should extract prompt metadata from GLTF binary file', async () => {
|
|
const testPrompt = {
|
|
node1: {
|
|
class_type: 'TestNode',
|
|
inputs: {
|
|
seed: 123456
|
|
}
|
|
}
|
|
}
|
|
|
|
const mockFile = createMockGltfFile({
|
|
asset: {
|
|
version: '2.0',
|
|
generator: 'ComfyUI GLTF Test',
|
|
extras: {
|
|
prompt: testPrompt
|
|
}
|
|
},
|
|
scenes: []
|
|
})
|
|
|
|
const metadata = await getGltfBinaryMetadata(mockFile)
|
|
expect(metadata).toBeDefined()
|
|
expect(metadata.prompt).toBeDefined()
|
|
|
|
const prompt = metadata.prompt as Record<string, any>
|
|
expect(prompt.node1.class_type).toBe('TestNode')
|
|
expect(prompt.node1.inputs.seed).toBe(123456)
|
|
})
|
|
|
|
it('should handle string JSON content', async () => {
|
|
const workflowStr = JSON.stringify({
|
|
nodes: [{ id: 1, type: 'StringifiedNode' }],
|
|
links: []
|
|
})
|
|
|
|
const mockFile = createMockGltfFile({
|
|
asset: {
|
|
version: '2.0',
|
|
extras: {
|
|
workflow: workflowStr // As string instead of object
|
|
}
|
|
}
|
|
})
|
|
|
|
const metadata = await getGltfBinaryMetadata(mockFile)
|
|
|
|
expect(metadata).toBeDefined()
|
|
expect(metadata.workflow).toBeDefined()
|
|
|
|
const workflow = metadata.workflow as {
|
|
nodes: Array<{ id: number; type: string }>
|
|
}
|
|
expect(workflow.nodes[0].type).toBe('StringifiedNode')
|
|
})
|
|
|
|
it('should handle invalid GLTF binary files gracefully', async () => {
|
|
const invalidEmptyFile = new File([], 'invalid.glb')
|
|
const metadata = await getGltfBinaryMetadata(invalidEmptyFile)
|
|
expect(metadata).toEqual({})
|
|
})
|
|
})
|