From a244f295a63625aa03681432e2513ceae258129c Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Fri, 28 Feb 2025 20:01:40 -0500 Subject: [PATCH] Remove server elements from unit tests (#2777) --- .env_example | 3 - .github/workflows/test-ui.yaml | 19 ---- README.md | 2 - package.json | 1 - tests-ui/extractExamples.ts | 172 -------------------------------- tests-ui/setup.ts | 46 --------- tests-ui/tests/apiTypes.test.ts | 18 ---- 7 files changed, 261 deletions(-) delete mode 100644 tests-ui/extractExamples.ts delete mode 100644 tests-ui/setup.ts diff --git a/.env_example b/.env_example index b7f049aa9..e5c8781df 100644 --- a/.env_example +++ b/.env_example @@ -21,8 +21,5 @@ DEPLOY_COMFYUI_DIR=/home/ComfyUI/web # If you aren't using a separate install for testing, point this to your regular install. TEST_COMFYUI_DIR=/home/ComfyUI -# The directory containing the ComfyUI_examples repo used to extract test workflows. -EXAMPLE_REPO_PATH=tests-ui/ComfyUI_examples - # Whether to enable minification of the frontend code. ENABLE_MINIFY=true diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/test-ui.yaml index 7ae6e8276..fc098a27e 100644 --- a/.github/workflows/test-ui.yaml +++ b/.github/workflows/test-ui.yaml @@ -68,27 +68,8 @@ jobs: ComfyUI_frontend key: comfyui-setup-${{ needs.setup.outputs.cache-key }} - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: Install requirements - run: | - python -m pip install --upgrade pip - pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu - pip install -r requirements.txt - pip install wait-for-it - working-directory: ComfyUI - - - name: Start ComfyUI server - run: | - python main.py --cpu --multi-user & - wait-for-it --service 127.0.0.1:8188 -t 600 - working-directory: ComfyUI - - name: Run Jest tests run: | - npm run test:generate npm run test:jest -- --verbose working-directory: ComfyUI_frontend diff --git a/README.md b/README.md index 191d892a0..cf24ab651 100644 --- a/README.md +++ b/README.md @@ -546,9 +546,7 @@ navigate to `http://:5173` (e.g. `http://192.168.2.20:5173` here), to ### Unit Test -- `git clone https://github.com/comfyanonymous/ComfyUI_examples.git` to `tests-ui/ComfyUI_examples` or the EXAMPLE_REPO_PATH location specified in .env - `npm i` to install all dependencies -- `npm run test:generate` to fetch `tests-ui/data/object_info.json` - `npm run test:jest` to execute all unit tests. ### Component Test diff --git a/package.json b/package.json index f0f56bd72..7c10b2751 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "format": "prettier --write './**/*.{js,ts,tsx,vue,mts}'", "format:check": "prettier --check './**/*.{js,ts,tsx,vue,mts}'", "test:jest": "jest --config jest.config.ts", - "test:generate": "npx tsx tests-ui/setup", "test:browser": "npx playwright test", "test:component": "vitest run src/components/", "prepare": "husky || true", diff --git a/tests-ui/extractExamples.ts b/tests-ui/extractExamples.ts deleted file mode 100644 index e23c42f70..000000000 --- a/tests-ui/extractExamples.ts +++ /dev/null @@ -1,172 +0,0 @@ -// @ts-strict-ignore -/* - Script to generate test API json from the ComfyUI_examples repo. - Requires the repo to be cloned to the tests-ui directory or specified via the EXAMPLE_REPO_PATH env var. -*/ -import chalk from 'chalk' -import dotenv from 'dotenv' -import fs from 'fs' -import { fileURLToPath } from 'node:url' -import path from 'path' - -import { getFromFlacBuffer } from '@/scripts/metadata/flac' -import { getFromPngBuffer } from '@/scripts/metadata/png' - -dotenv.config() - -const dirname = path.dirname(fileURLToPath(import.meta.url)) -const repoPath = - process.env.EXAMPLE_REPO_PATH || path.resolve(dirname, 'ComfyUI_examples') -const workflowsPath = path.resolve(dirname, 'workflows', 'examples') - -if (!fs.existsSync(repoPath)) { - console.error( - `ComfyUI_examples repo not found. Please clone this to ${repoPath} or set the EXAMPLE_REPO_PATH env var (see .env_example) and re-run.` - ) -} - -if (!fs.existsSync(workflowsPath)) { - await fs.promises.mkdir(workflowsPath) -} - -async function* getFiles( - dir: string, - ...exts: string[] -): AsyncGenerator { - const dirents = await fs.promises.readdir(dir, { withFileTypes: true }) - for (const dirent of dirents) { - const res = path.resolve(dir, dirent.name) - if (dirent.isDirectory()) { - yield* getFiles(res, ...exts) - } else if (exts.includes(path.extname(res))) { - yield res - } - } -} - -async function validateMetadata(metadata: Record) { - const check = (prop: 'prompt' | 'workflow') => { - const v = metadata?.[prop] - if (!v) throw `${prop} not found in metadata` - try { - JSON.parse(v) - } catch (error) { - throw `${prop} invalid json: ${error.message}` - } - return v - } - - return { prompt: check('prompt'), workflow: check('workflow') } -} - -async function hasExampleChanged( - existingFilePath: string, - exampleJson: string -) { - return exampleJson !== (await fs.promises.readFile(existingFilePath, 'utf8')) -} - -// Example images to ignore as they don't contain workflows -const ignore = [ - 'unclip_sunset.png', - 'unclip_mountains.png', - 'inpaint_yosemite_inpaint_example.png', - 'controlnet_shark_depthmap.png', - 'controlnet_pose_worship.png', - 'controlnet_pose_present.png', - 'controlnet_input_scribble_example.png', - 'controlnet_house_scribble.png' -] - -// Find all existing examples so we can check if any are removed/changed -const existing = new Set( - (await fs.promises.readdir(workflowsPath, { withFileTypes: true })) - .filter((d) => d.isFile()) - .map((d) => path.resolve(workflowsPath, d.name)) -) - -const results = { - new: [], - changed: [], - unchanged: [], - missing: [], - failed: [] -} - -let total = 0 -for await (const file of getFiles(repoPath, '.png', '.flac')) { - const cleanedName = path - .relative(repoPath, file) - .replaceAll('/', '_') - .replaceAll('\\', '_') - - if (ignore.includes(cleanedName)) continue - total++ - - let metadata: { prompt: string; workflow: string } - try { - const { buffer } = await fs.promises.readFile(file) - switch (path.extname(file)) { - case '.png': - metadata = await validateMetadata(getFromPngBuffer(buffer)) - break - case '.flac': - metadata = await validateMetadata(getFromFlacBuffer(buffer)) - break - } - - const outPath = path.resolve(workflowsPath, cleanedName + '.json') - const exampleJson = JSON.stringify(metadata) - if (existing.has(outPath)) { - existing.delete(outPath) - if (await hasExampleChanged(outPath, exampleJson)) { - results.changed.push(outPath) - } else { - // Unchanged, no point in re-saving - results.unchanged.push(outPath) - continue - } - } else { - results.new.push(outPath) - } - - await fs.promises.writeFile(outPath, exampleJson, 'utf8') - } catch (error) { - results.failed.push({ file, error }) - } -} - -// Any workflows left in the existing set are now missing, these will want checking and manually removing -results.missing.push(...existing) - -const c = (v: number, gt0: 'red' | 'yellow' | 'green') => - chalk[v > 0 ? gt0 : 'gray'](v) - -console.log(`Processed ${chalk.green(total)} examples`) -console.log(` ${chalk.gray(results.unchanged.length)} unchanged`) -console.log(` ${c(results.changed.length, 'yellow')} changed`) -console.log(` ${c(results.new.length, 'green')} new`) -console.log(` ${c(results.missing.length, 'red')} missing`) -console.log(` ${c(results.failed.length, 'red')} failed`) - -if (results.missing.length) { - console.log() - console.log( - chalk.red( - 'The following examples are missing and require manual reviewing & removal:' - ) - ) - for (const m of results.missing) { - console.log(m) - } -} - -if (results.failed.length) { - console.log() - console.log(chalk.red('The following examples failed to extract:')) - for (const m of results.failed) { - console.log(m.file) - console.error(m.error) - console.log() - } -} diff --git a/tests-ui/setup.ts b/tests-ui/setup.ts deleted file mode 100644 index f96fd559e..000000000 --- a/tests-ui/setup.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { existsSync, mkdirSync, writeFileSync } from 'fs' -import http from 'http' -import { resolve } from 'path' - -async function setup() { - await new Promise((res, rej) => { - http - .get('http://127.0.0.1:8188/object_info', (resp) => { - let data = '' - resp.on('data', (chunk) => { - data += chunk - }) - resp.on('end', () => { - // Modify the response data to add some checkpoints - const objectInfo = JSON.parse(data) - objectInfo.CheckpointLoaderSimple.input.required.ckpt_name[0] = [ - 'model1.safetensors', - 'model2.ckpt' - ] - objectInfo.VAELoader.input.required.vae_name[0] = [ - 'vae1.safetensors', - 'vae2.ckpt' - ] - - data = JSON.stringify(objectInfo, undefined, '\t') - - const outDir = resolve('./tests-ui/data') - if (!existsSync(outDir)) { - mkdirSync(outDir) - } - - const outPath = resolve(outDir, 'object_info.json') - console.log( - `Writing ${Object.keys(objectInfo).length} nodes to ${outPath}` - ) - writeFileSync(outPath, data, { - encoding: 'utf8' - }) - res() - }) - }) - .on('error', rej) - }) -} - -setup() diff --git a/tests-ui/tests/apiTypes.test.ts b/tests-ui/tests/apiTypes.test.ts index 942bfd917..7effd5b14 100644 --- a/tests-ui/tests/apiTypes.test.ts +++ b/tests-ui/tests/apiTypes.test.ts @@ -1,7 +1,4 @@ // @ts-strict-ignore -import fs from 'fs' -import path from 'path' - import { type ComfyNodeDef, validateComfyNodeDef @@ -76,19 +73,4 @@ describe('validateNodeDef', () => { }) } ) - - it('Should accept all built-in node definitions', async () => { - const nodeDefs = Object.values( - JSON.parse( - fs.readFileSync( - path.resolve('./tests-ui/data/object_info.json'), - 'utf8' - ) - ) - ) - - for (const nodeDef of nodeDefs) { - expect(validateComfyNodeDef(nodeDef)).not.toBeNull() - } - }) })