Skip to content

Commit 32d81c1

Browse files
Add testing for ComfyUI examples (#95)
* Add testing for ComfyUI examples * Remove examples, add test to github action * Create dir * Update readme
1 parent 7dae2eb commit 32d81c1

File tree

11 files changed

+414
-150
lines changed

11 files changed

+414
-150
lines changed

.env_example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ DEV_SERVER_COMFYUI_URL=http://127.0.0.1:8188
1111
# Add `--front-end-root {DEPLOY_COMFY_UI_DIR}/custom_web_versions/main/dev`
1212
# to ComfyUI launch script to serve the custom web version.
1313
DEPLOY_COMFYUI_DIR=/home/ComfyUI/web
14+
15+
# The directory containing the ComfyUI_examples repo used to extract test workflows.
16+
EXAMPLE_REPO_PATH=tests-ui/ComfyUI_examples

.github/workflows/test-ui.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ jobs:
2525
id: commit-message
2626
run: echo "::set-output name=message::$(git log -1 --pretty=%B)"
2727
working-directory: ComfyUI_frontend
28+
- name: Checkout ComfyUI_examples
29+
uses: actions/checkout@v4
30+
with:
31+
repository: "comfyanonymous/ComfyUI_examples"
32+
path: "ComfyUI_frontend/tests-ui/ComfyUI_examples"
33+
ref: master
2834
- name: Skip CI
2935
if: contains(steps.commit-message.outputs.message, '[skip ci]')
3036
run: echo "Skipping CI as commit contains '[skip ci]'"
@@ -58,6 +64,7 @@ jobs:
5864
- name: Run UI tests
5965
run: |
6066
npm run test:generate
67+
npm run test:generate:examples
6168
npm test -- --verbose
6269
working-directory: ComfyUI_frontend
6370
- name: Install Playwright Browsers

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ dist-ssr
2626

2727
# Ignore test data.
2828
tests-ui/data/*
29+
tests-ui/ComfyUI_examples
30+
tests-ui/workflows/examples
2931

3032
# Browser tests
3133
/test-results/

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ core extensions will be loaded.
4646

4747
### Test
4848

49+
- `git clone https://github.com/comfyanonymous/ComfyUI_examples.git` to `tests-ui/ComfyUI_examples` or the EXAMPLE_REPO_PATH location specified in .env
4950
- `npm i` to install all dependencies
5051
- `npm run test:generate` to fetch `tests-ui/data/object_info.json`
52+
- `npm run test:generate:examples` to extract the example workflows
5153
- `npm run test` to execute all unit tests.
5254

5355
## Deploy

package-lock.json

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

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"typecheck": "tsc --noEmit",
1212
"format": "prettier --write 'src/**/*.{js,ts,tsx}'",
1313
"test": "npm run build && jest",
14+
"test:generate:examples": "npx tsx tests-ui/extractExamples",
1415
"test:generate": "npx tsx tests-ui/setup",
1516
"test:browser": "npx playwright test",
1617
"prepare": "husky || true",
@@ -24,6 +25,7 @@
2425
"@types/node": "^20.14.8",
2526
"babel-plugin-transform-import-meta": "^2.2.1",
2627
"babel-plugin-transform-rename-import": "^2.3.0",
28+
"chalk": "^5.3.0",
2729
"fs-extra": "^11.2.0",
2830
"husky": "^9.0.11",
2931
"identity-obj-proxy": "^3.0.0",

src/scripts/metadata/flac.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
export function getFromFlacBuffer(buffer: ArrayBuffer): Record<string, string> {
2+
const dataView = new DataView(buffer);
3+
4+
// Verify the FLAC signature
5+
const signature = String.fromCharCode(...new Uint8Array(buffer, 0, 4));
6+
if (signature !== "fLaC") {
7+
console.error("Not a valid FLAC file");
8+
return;
9+
}
10+
11+
// Parse metadata blocks
12+
let offset = 4;
13+
let vorbisComment = null;
14+
while (offset < dataView.byteLength) {
15+
const isLastBlock = dataView.getUint8(offset) & 0x80;
16+
const blockType = dataView.getUint8(offset) & 0x7f;
17+
const blockSize = dataView.getUint32(offset, false) & 0xffffff;
18+
offset += 4;
19+
20+
if (blockType === 4) {
21+
// Vorbis Comment block type
22+
vorbisComment = parseVorbisComment(
23+
new DataView(buffer, offset, blockSize)
24+
);
25+
}
26+
27+
offset += blockSize;
28+
if (isLastBlock) break;
29+
}
30+
31+
return vorbisComment;
32+
}
33+
34+
export function getFromFlacFile(file: File): Promise<Record<string, string>> {
35+
return new Promise((r) => {
36+
const reader = new FileReader();
37+
reader.onload = function (event) {
38+
const arrayBuffer = event.target.result as ArrayBuffer;
39+
r(getFromFlacBuffer(arrayBuffer));
40+
};
41+
reader.readAsArrayBuffer(file);
42+
});
43+
}
44+
45+
// Function to parse the Vorbis Comment block
46+
function parseVorbisComment(dataView: DataView): Record<string, string> {
47+
let offset = 0;
48+
const vendorLength = dataView.getUint32(offset, true);
49+
offset += 4;
50+
const vendorString = getString(dataView, offset, vendorLength);
51+
offset += vendorLength;
52+
53+
const userCommentListLength = dataView.getUint32(offset, true);
54+
offset += 4;
55+
const comments = {};
56+
for (let i = 0; i < userCommentListLength; i++) {
57+
const commentLength = dataView.getUint32(offset, true);
58+
offset += 4;
59+
const comment = getString(dataView, offset, commentLength);
60+
offset += commentLength;
61+
62+
const [key, value] = comment.split("=");
63+
64+
comments[key] = value;
65+
}
66+
67+
return comments;
68+
}
69+
70+
function getString(dataView: DataView, offset: number, length: number): string {
71+
let string = "";
72+
for (let i = 0; i < length; i++) {
73+
string += String.fromCharCode(dataView.getUint8(offset + i));
74+
}
75+
return string;
76+
}

src/scripts/metadata/png.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export function getFromPngBuffer(buffer: ArrayBuffer) {
2+
// Get the PNG data as a Uint8Array
3+
const pngData = new Uint8Array(buffer);
4+
const dataView = new DataView(pngData.buffer);
5+
6+
// Check that the PNG signature is present
7+
if (dataView.getUint32(0) !== 0x89504e47) {
8+
console.error("Not a valid PNG file");
9+
return;
10+
}
11+
12+
// Start searching for chunks after the PNG signature
13+
let offset = 8;
14+
let txt_chunks: Record<string, string> = {};
15+
// Loop through the chunks in the PNG file
16+
while (offset < pngData.length) {
17+
// Get the length of the chunk
18+
const length = dataView.getUint32(offset);
19+
// Get the chunk type
20+
const type = String.fromCharCode(...pngData.slice(offset + 4, offset + 8));
21+
if (type === "tEXt" || type == "comf" || type === "iTXt") {
22+
// Get the keyword
23+
let keyword_end = offset + 8;
24+
while (pngData[keyword_end] !== 0) {
25+
keyword_end++;
26+
}
27+
const keyword = String.fromCharCode(
28+
...pngData.slice(offset + 8, keyword_end)
29+
);
30+
// Get the text
31+
const contentArraySegment = pngData.slice(
32+
keyword_end + 1,
33+
offset + 8 + length
34+
);
35+
const contentJson = new TextDecoder("utf-8").decode(contentArraySegment);
36+
txt_chunks[keyword] = contentJson;
37+
}
38+
39+
offset += 12 + length;
40+
}
41+
return txt_chunks;
42+
}
43+
44+
export function getFromPngFile(file: File) {
45+
return new Promise<Record<string, string>>((r) => {
46+
const reader = new FileReader();
47+
reader.onload = (event) => {
48+
r(getFromPngBuffer(event.target.result as ArrayBuffer));
49+
};
50+
51+
reader.readAsArrayBuffer(file);
52+
});
53+
}

0 commit comments

Comments
 (0)