mirror of
https://github.com/jackwener/OpenCLI.git
synced 2026-09-14 18:25:42 +08:00
25e86532a3
* fix(chatgpt): fix image generation detection and output path Three fixes for chatgpt image command: 1. Page navigation: ChatGPT redirects away from the conversation after sending. Poll for the /c/ URL after send, then periodically reload the conversation page during image wait to pick up asynchronously rendered images. 2. Composer selector: add fallback selectors for the chat input since ChatGPT uses different aria-labels across UI versions. 3. Output path: the default '~/Pictures/chatgpt' was passed as a literal string without tilde expansion, creating a directory named '~' in the working directory. Removed the string default and use os.homedir() fallback instead. Fixes #1206 * fix(chatgpt): fail fast on image export failures * fix(chatgpt): avoid reloads during image generation --------- Co-authored-by: jackwener <jakevingoo@gmail.com>
64 lines
2.5 KiB
JavaScript
64 lines
2.5 KiB
JavaScript
import { describe, expect, it, vi } from 'vitest';
|
|
import { __test__, waitForChatGPTImages } from './utils.js';
|
|
|
|
function createPageMock({ location = '', generating = [], imageUrls = [] } = {}) {
|
|
let generatingIndex = 0;
|
|
let imageIndex = 0;
|
|
return {
|
|
wait: vi.fn().mockResolvedValue(undefined),
|
|
goto: vi.fn().mockResolvedValue(undefined),
|
|
evaluate: vi.fn((script) => {
|
|
if (script === 'window.location.href') return Promise.resolve(location);
|
|
if (script.includes('Stop generating') || script.includes('Thinking')) {
|
|
const value = generating[Math.min(generatingIndex, generating.length - 1)] ?? false;
|
|
generatingIndex += 1;
|
|
return Promise.resolve(value);
|
|
}
|
|
if (script.includes("document.querySelectorAll('img')")) {
|
|
const value = imageUrls[Math.min(imageIndex, imageUrls.length - 1)] ?? [];
|
|
imageIndex += 1;
|
|
return Promise.resolve(value);
|
|
}
|
|
return Promise.resolve(undefined);
|
|
}),
|
|
};
|
|
}
|
|
|
|
describe('chatgpt image wait contract', () => {
|
|
it('does not periodically reload the conversation while generation is still active', async () => {
|
|
const convUrl = 'https://chatgpt.com/c/demo';
|
|
const page = createPageMock({
|
|
location: convUrl,
|
|
generating: [true, true, true, true, true, true],
|
|
});
|
|
|
|
await expect(waitForChatGPTImages(page, [], 18, convUrl)).resolves.toEqual([]);
|
|
expect(page.goto).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('jumps back to the captured conversation when the page drifts away', async () => {
|
|
const convUrl = 'https://chatgpt.com/c/demo';
|
|
const page = createPageMock({
|
|
location: 'https://chatgpt.com/',
|
|
generating: [false],
|
|
imageUrls: [['https://cdn.openai.com/generated/demo.png']],
|
|
});
|
|
|
|
await expect(waitForChatGPTImages(page, [], 3, convUrl)).resolves.toEqual([
|
|
'https://cdn.openai.com/generated/demo.png',
|
|
]);
|
|
expect(page.goto).toHaveBeenCalledWith(convUrl);
|
|
});
|
|
|
|
it('treats query and hash variants as the same conversation', () => {
|
|
expect(__test__.isSameChatGPTConversation(
|
|
'https://chatgpt.com/c/demo?model=gpt-image-1',
|
|
'https://chatgpt.com/c/demo',
|
|
)).toBe(true);
|
|
expect(__test__.isSameChatGPTConversation(
|
|
'https://chatgpt.com/c/other',
|
|
'https://chatgpt.com/c/demo',
|
|
)).toBe(false);
|
|
});
|
|
});
|