use-vibes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,350 @@
1
+ // tests/browser/hello-world.test.ts
2
+ import { test, expect } from '@playwright/test';
3
+ // Simplified test that tests the core functionality with proper instrumentation
4
+ // This approach completely bypasses network calls for reliable test behavior
5
+ // Set up browser console logging for all tests
6
+ const setupLogging = (page) => {
7
+ // Forward browser console messages to test output
8
+ page.on('console', msg => {
9
+ /* eslint-disable-next-line no-console */
10
+ console.log(`🌐 ${msg.type()}: ${msg.text()}`);
11
+ });
12
+ page.on('pageerror', err => {
13
+ /* eslint-disable-next-line no-console */
14
+ console.error(`🔥 Browser error: ${err.message}`);
15
+ });
16
+ };
17
+ test('page loads with initial content', async ({ page }) => {
18
+ setupLogging(page);
19
+ // Navigate to the test page
20
+ await page.goto('http://localhost:3000/basic/hello-world.html');
21
+ // Check that our target element exists
22
+ const hasTarget = await page.evaluate(() => {
23
+ const target = document.getElementById('target');
24
+ /* eslint-disable-next-line no-console */
25
+ console.log('Target element exists:', !!target);
26
+ return !!target;
27
+ });
28
+ expect(hasTarget).toBe(true);
29
+ // Get the text content
30
+ const initialText = await page.textContent('#target');
31
+ /* eslint-disable-next-line no-console */
32
+ console.log('Initial text content:', initialText);
33
+ expect(initialText).toContain('This content will be modified');
34
+ });
35
+ test('useVibes with direct callAI mock', async ({ page }) => {
36
+ setupLogging(page);
37
+ // Navigate to the test page
38
+ await page.goto('http://localhost:3000/basic/hello-world.html');
39
+ // Wait for page to load
40
+ await page.waitForSelector('#target');
41
+ // Directly inject the mock - this is cleaner than relying on global setup
42
+ await page.evaluate(() => {
43
+ // Override callAI with a direct mock implementation
44
+ // @ts-expect-error - Mock the callAI function with correct type signatures
45
+ window.callAI = function mockCallAI(_prompt, _options) {
46
+ // Create HTML with the prompt for verification
47
+ const html = `
48
+ <div style="background-color: #e6f7ff; padding: 10px; border: 2px solid #1890ff; border-radius: 5px;">
49
+ <strong>🎭 Vibes received prompt:</strong> "Create a Hello World message with blue styling"
50
+ <br><small>(Mocked API Response)</small>
51
+ </div>
52
+ `;
53
+ // Create a response object matching what callAI would return
54
+ const responseObj = {
55
+ html: html,
56
+ explanation: 'Mock explanation for testing',
57
+ };
58
+ // callAI returns a Promise that resolves to a JSON string
59
+ return Promise.resolve(JSON.stringify(responseObj));
60
+ };
61
+ /* eslint-disable-next-line no-console */
62
+ console.log('🔄 callAI mocked directly on window object');
63
+ /* eslint-disable-next-line no-console */
64
+ console.log('🔄 Type of callAI:', typeof window.callAI);
65
+ });
66
+ // Verify our target element before modification
67
+ const initialHtml = await page.evaluate(() => {
68
+ const target = document.getElementById('target');
69
+ return target ? target.innerHTML : 'target not found';
70
+ });
71
+ /* eslint-disable-next-line no-console */
72
+ console.log('Target HTML before:', initialHtml);
73
+ // Execute useVibes on the target element
74
+ await page.evaluate(() => {
75
+ try {
76
+ // Get the target element
77
+ const target = document.getElementById('target');
78
+ if (!target)
79
+ throw new Error('Target element not found!');
80
+ /* eslint-disable-next-line no-console */
81
+ console.log('🔄 Applying useVibes to target element');
82
+ // Set API key for testing
83
+ window.CALLAI_API_KEY = 'test-api-key';
84
+ // Call useVibes with test prompt
85
+ window.useVibes(target, {
86
+ prompt: 'Create a Hello World message with blue styling',
87
+ });
88
+ /* eslint-disable-next-line no-console */
89
+ console.log('✅ useVibes called successfully');
90
+ }
91
+ catch (err) {
92
+ /* eslint-disable-next-line no-console */
93
+ console.error('❌ Error calling useVibes:', err.message);
94
+ /* eslint-disable-next-line no-console */
95
+ console.error('Stack:', err.stack);
96
+ }
97
+ });
98
+ // Wait for the async operation to complete
99
+ await page.waitForTimeout(2000);
100
+ // Check the HTML content after the timeout
101
+ const finalHtml = await page.evaluate(() => {
102
+ const target = document.getElementById('target');
103
+ /* eslint-disable-next-line no-console */
104
+ console.log('Target element after useVibes:', target ? 'exists' : 'not found');
105
+ return target ? target.innerHTML : 'target not found';
106
+ });
107
+ /* eslint-disable-next-line no-console */
108
+ console.log('Target HTML after:', finalHtml.substring(0, 200) + '...');
109
+ // Get the text content for assertions
110
+ const targetText = await page.textContent('#target');
111
+ expect(targetText).toContain('Vibes received prompt');
112
+ });
113
+ test('useVibes with direct mock custom configuration', async ({ page }) => {
114
+ setupLogging(page);
115
+ // Navigate to the test page
116
+ await page.goto('http://localhost:3000/basic/hello-world.html');
117
+ // Wait for page to load
118
+ await page.waitForSelector('#target-alt');
119
+ // Inject the mock implementation for callAI
120
+ await page.evaluate(() => {
121
+ // Override callAI with a direct mock implementation
122
+ // @ts-expect-error - Mock the callAI function
123
+ window.callAI = function mockCallAI(_prompt, _options) {
124
+ /* eslint-disable-next-line no-console */
125
+ console.log('📢 Mock callAI called with prompt:', _prompt.substring(0, 100) + '...');
126
+ // Create a response with alternative styling for this test
127
+ const html = `
128
+ <div style="background-color: #fff8e1; padding: 10px; border: 2px solid #ffc107; border-radius: 5px;">
129
+ <strong>🎭 Vibes received prompt:</strong> "Alternative configuration test"
130
+ <br><small>(Custom configuration test)</small>
131
+ </div>
132
+ `;
133
+ const responseObj = {
134
+ html: html,
135
+ explanation: 'Mock explanation for alternative configuration',
136
+ };
137
+ return Promise.resolve(JSON.stringify(responseObj));
138
+ };
139
+ });
140
+ // Execute useVibes on the alternative target with custom config
141
+ await page.evaluate(() => {
142
+ try {
143
+ const targetAlt = document.getElementById('target-alt');
144
+ if (!targetAlt)
145
+ throw new Error('Alt target element not found!');
146
+ // Apply with custom config
147
+ window.useVibes(targetAlt, {
148
+ prompt: 'Alternative configuration test',
149
+ });
150
+ }
151
+ catch (err) {
152
+ /* eslint-disable-next-line no-console */
153
+ console.error('Error in alt config test:', err.message);
154
+ }
155
+ });
156
+ // Wait for async operations
157
+ await page.waitForTimeout(2000);
158
+ // Verify the content
159
+ const targetText = await page.textContent('#target-alt');
160
+ expect(targetText).toContain('Vibes received prompt');
161
+ expect(targetText).toContain('Alternative configuration test');
162
+ });
163
+ // Simple diagnostic test to validate our mocking approach
164
+ test('verify mock callAI is actually being called', async ({ page }) => {
165
+ setupLogging(page);
166
+ // Navigate to the test page
167
+ await page.goto('http://localhost:3000/basic/hello-world.html');
168
+ // Don't override the mock here - instead use the one from our test bundle
169
+ // This will properly test that our mocking approach works
170
+ // Set up an error handler to detect if our diagnostic error is thrown
171
+ let diagnosticErrorDetected = false;
172
+ page.on('pageerror', error => {
173
+ /* eslint-disable-next-line no-console */
174
+ console.log('📋 Page error detected:', error.message);
175
+ if (error.message.includes('DIAGNOSTIC_MOCK_ERROR')) {
176
+ diagnosticErrorDetected = true;
177
+ }
178
+ });
179
+ // Execute useVibes with the diagnostic prompt
180
+ await page.evaluate(() => {
181
+ try {
182
+ const target = document.getElementById('target');
183
+ if (!target)
184
+ throw new Error('Target element not found!');
185
+ /* eslint-disable-next-line no-console */
186
+ console.log('🔄 Calling useVibes with diagnostic prompt');
187
+ // Set API key for testing
188
+ window.CALLAI_API_KEY = 'test-api-key';
189
+ // The 'Diagnostic test prompt' string is what triggers our special mock behavior
190
+ window.useVibes(target, {
191
+ prompt: 'Diagnostic test prompt',
192
+ });
193
+ /* eslint-disable-next-line no-console */
194
+ console.log('✅ useVibes call with diagnostic prompt completed (if this appears, error was caught internally)');
195
+ }
196
+ catch (err) {
197
+ /* eslint-disable-next-line no-console */
198
+ console.error('❌ Error caught in page context:', err.message);
199
+ }
200
+ });
201
+ // Wait for any async operations and error handlers to complete
202
+ await page.waitForTimeout(2000);
203
+ // Check if our diagnostic error HTML element exists in the page
204
+ const errorElementExists = await page.evaluate(() => {
205
+ return !!document.getElementById('DIAGNOSTIC_MOCK_ERROR');
206
+ });
207
+ /* eslint-disable-next-line no-console */
208
+ console.log('Diagnostic error element in DOM:', errorElementExists);
209
+ /* eslint-disable-next-line no-console */
210
+ console.log('Diagnostic error detected in console:', diagnosticErrorDetected);
211
+ // The test passes if either the error was detected or the error element exists in the DOM
212
+ expect(errorElementExists || diagnosticErrorDetected).toBeTruthy();
213
+ });
214
+ test('useVibes should handle errors gracefully', async ({ page }) => {
215
+ setupLogging(page);
216
+ // Navigate to the test page
217
+ await page.goto('http://localhost:3000/basic/hello-world.html');
218
+ // Inject mock that simulates an error
219
+ await page.evaluate(() => {
220
+ window.callAI = function mockCallAIWithError() {
221
+ /* eslint-disable-next-line no-console */
222
+ console.log('🚨 Mock error function called');
223
+ return Promise.reject(new Error('Simulated API error'));
224
+ };
225
+ });
226
+ // Execute useVibes and expect it to handle the error
227
+ await page.evaluate(() => {
228
+ const target = document.getElementById('target');
229
+ if (target) {
230
+ window.useVibes(target, {
231
+ prompt: 'This should fail with an error',
232
+ });
233
+ }
234
+ });
235
+ // Wait for error handling
236
+ await page.waitForTimeout(1000);
237
+ // Verify error message shows in the element
238
+ const errorContent = await page.textContent('#target');
239
+ expect(errorContent).toContain('Error');
240
+ });
241
+ test('useVibes with custom configuration options', async ({ page }) => {
242
+ // Set up API request interception with a custom configuration response
243
+ await page.route('**/*api.openai.com*/v1/chat/completions', async (route) => {
244
+ const mockResponse = {
245
+ choices: [
246
+ {
247
+ message: {
248
+ role: 'assistant',
249
+ content: JSON.stringify({
250
+ html: `<div style="background-color: #fff8e1; padding: 10px; border: 2px solid #ffc107; border-radius: 5px;">
251
+ <strong>🎭 Vibes received prompt:</strong> "Alternative configuration test"
252
+ <br><small>(Custom configuration test response)</small>
253
+ </div>`,
254
+ explanation: 'Mock explanation for custom configuration test',
255
+ }),
256
+ },
257
+ index: 0,
258
+ },
259
+ ],
260
+ id: 'mock-custom-config-id',
261
+ model: 'gpt-3.5-turbo',
262
+ object: 'chat.completion',
263
+ };
264
+ await route.fulfill({
265
+ status: 200,
266
+ contentType: 'application/json',
267
+ body: JSON.stringify(mockResponse),
268
+ });
269
+ });
270
+ // Also mock the call-ai API endpoint as a fallback
271
+ await page.route('**/*api.call-ai.com*', async (route) => {
272
+ const mockResponse = {
273
+ choices: [
274
+ {
275
+ message: {
276
+ role: 'assistant',
277
+ content: JSON.stringify({
278
+ html: `<div style="background-color: #fff8e1; padding: 10px; border: 2px solid #ffc107; border-radius: 5px;">
279
+ <strong>🎭 Vibes received prompt:</strong> "Alternative configuration test"
280
+ <br><small>(Custom configuration test response)</small>
281
+ </div>`,
282
+ explanation: 'Mock explanation for custom configuration test',
283
+ }),
284
+ },
285
+ index: 0,
286
+ },
287
+ ],
288
+ id: 'mock-custom-config-id',
289
+ model: 'gpt-3.5-turbo',
290
+ object: 'chat.completion',
291
+ };
292
+ await route.fulfill({
293
+ status: 200,
294
+ contentType: 'application/json',
295
+ body: JSON.stringify(mockResponse),
296
+ });
297
+ });
298
+ // Navigate to test page
299
+ await page.goto('http://localhost:3000/basic/hello-world.html');
300
+ // Wait for page to load
301
+ await page.waitForSelector('#target-alt');
302
+ // Make sure our mocks are loaded
303
+ await page.waitForFunction(() => {
304
+ return window.fetch !== window._originalFetch;
305
+ }, { timeout: 5000 });
306
+ // Apply useVibes to the alternative target
307
+ await page.evaluate(() => {
308
+ const target = document.getElementById('target-alt');
309
+ if (!target) {
310
+ throw new Error('Alternative target element not found');
311
+ }
312
+ // Using the global useVibes function
313
+ window.CALLAI_API_KEY = 'test-api-key'; // Set test API key
314
+ return useVibes(target, {
315
+ prompt: 'Alternative configuration test',
316
+ });
317
+ });
318
+ // Wait longer for changes to apply
319
+ await page.waitForTimeout(200);
320
+ // Verify the content was changed
321
+ const targetText = await page.textContent('#target-alt');
322
+ expect(targetText).toContain('Vibes received prompt');
323
+ expect(targetText).toContain('Alternative configuration test');
324
+ });
325
+ test('useVibes should handle invalid selector errors', async ({ page }) => {
326
+ await page.goto('http://localhost:3000/basic/hello-world.html');
327
+ // Wait for mocks to be set up
328
+ await page.waitForFunction(() => {
329
+ return window.fetch !== window._originalFetch;
330
+ }, { timeout: 5000 });
331
+ // Test with invalid selector
332
+ const errorResult = await page.evaluate(async () => {
333
+ try {
334
+ // Set test API key
335
+ window.CALLAI_API_KEY = 'test-api-key';
336
+ // Try to use a non-existent element with the global useVibes function
337
+ await useVibes('#non-existent-element', {
338
+ prompt: 'Test error handling',
339
+ });
340
+ return 'No error thrown';
341
+ }
342
+ catch (e) {
343
+ return e instanceof Error ? e.message : String(e);
344
+ }
345
+ });
346
+ // Ensure we got an error message
347
+ expect(errorResult).not.toBe('No error thrown');
348
+ expect(typeof errorResult).toBe('string');
349
+ expect(errorResult.length).toBeGreaterThan(0);
350
+ });
@@ -0,0 +1,15 @@
1
+ import { Page } from '@playwright/test';
2
+ /**
3
+ * Helper function to inject and test the useVibes module in a browser context
4
+ * This avoids the TypeScript errors from directly importing browser modules in Node.js
5
+ */
6
+ interface UseVibesConfig {
7
+ prompt: string;
8
+ [key: string]: unknown;
9
+ }
10
+ export declare function applyUseVibes(page: Page, selector: string, config: UseVibesConfig): Promise<void>;
11
+ /**
12
+ * Helper function to apply custom effects in a browser context
13
+ */
14
+ export declare function applyCustomEffect(page: Page, selector: string, effectFn: string): Promise<void>;
15
+ export {};
@@ -0,0 +1,32 @@
1
+ export async function applyUseVibes(page, selector, config) {
2
+ await page.evaluate(({ selector, config }) => {
3
+ return new Promise((resolve, reject) => {
4
+ // Dynamically import the module within the browser context
5
+ import('../../src/index.js')
6
+ .then(({ useVibes }) => {
7
+ const element = document.querySelector(selector);
8
+ if (!element) {
9
+ reject(new Error(`Element not found: ${selector}`));
10
+ return;
11
+ }
12
+ useVibes(element, config)
13
+ .then(() => resolve())
14
+ .catch((err) => reject(err));
15
+ })
16
+ .catch((err) => reject(err));
17
+ });
18
+ }, { selector, config });
19
+ }
20
+ /**
21
+ * Helper function to apply custom effects in a browser context
22
+ */
23
+ export async function applyCustomEffect(page, selector, effectFn) {
24
+ await page.evaluate(({ selector, effectFn }) => {
25
+ const element = document.querySelector(selector);
26
+ if (!element)
27
+ return;
28
+ // Execute the string function in the browser context
29
+ const fn = new Function('element', effectFn);
30
+ fn(element);
31
+ }, { selector, effectFn });
32
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,242 @@
1
+ // Mock implementation for the browser tests
2
+ // This script will be injected into the test page before any tests run
3
+ (function setupMocks() {
4
+ // Module interception - CRITICAL: This must run before any other scripts
5
+ // Create a module-level interception that redirects 'call-ai' imports to our mock
6
+ // Debug indicator that helps us verify our mock is working
7
+ window.__MOCK_STATUS__ = {
8
+ initialized: true,
9
+ moduleIntercepted: false,
10
+ callCount: 0,
11
+ lastPrompt: null,
12
+ lastOptions: null,
13
+ lastResponse: null,
14
+ errors: [],
15
+ };
16
+ // Log that we're starting the mock setup
17
+ /* eslint-disable-next-line no-console */
18
+ console.log('🔄 MOCK SETUP: Initializing module interception for call-ai');
19
+ try {
20
+ // Define our mock implementation that will replace the real callAI
21
+ const mockCallAI = function (userPrompt, options = {}) {
22
+ // Track usage
23
+ window.__MOCK_STATUS__.callCount++;
24
+ window.__MOCK_STATUS__.lastPrompt = userPrompt;
25
+ window.__MOCK_STATUS__.lastOptions = options;
26
+ /* eslint-disable-next-line no-console */
27
+ console.log(`🔍 MOCK CALL #${window.__MOCK_STATUS__.callCount}: callAI invoked with:`, typeof userPrompt === 'string'
28
+ ? userPrompt.substring(0, 100) + '...'
29
+ : '[non-string-prompt]');
30
+ // Check if this is an error test case
31
+ if (typeof userPrompt === 'string' &&
32
+ (userPrompt.includes('error') || userPrompt.includes('fail'))) {
33
+ /* eslint-disable-next-line no-console */
34
+ console.log('🚨 MOCK: Simulating error response');
35
+ return Promise.reject(new Error('Simulated error from mock callAI'));
36
+ }
37
+ // Extract the actual request from the longer prompt
38
+ let extractedPrompt = 'Default prompt';
39
+ if (typeof userPrompt === 'string') {
40
+ const promptMatch = userPrompt.match(/Transform the HTML content based on this request:\s*([^\n]+)/);
41
+ if (promptMatch && promptMatch[1]) {
42
+ extractedPrompt = promptMatch[1].trim();
43
+ }
44
+ else if (userPrompt.includes('Alternative configuration test')) {
45
+ extractedPrompt = 'Alternative configuration test';
46
+ }
47
+ }
48
+ // Create response HTML based on the prompt content
49
+ let htmlContent;
50
+ let explanationText;
51
+ if (extractedPrompt.includes('Alternative configuration')) {
52
+ htmlContent = `<div style="background-color: #fff8e1; padding: 10px; border: 2px solid #ffc107; border-radius: 5px;">
53
+ <strong>🎭 Vibes received prompt:</strong> "Alternative configuration test"
54
+ <br><small>(Alternative config mock response)</small>
55
+ </div>`;
56
+ explanationText = 'Mock explanation for alternative configuration';
57
+ }
58
+ else {
59
+ htmlContent = `<div style="background-color: #eefbff; padding: 10px; border: 2px solid #0099cc; border-radius: 5px;">
60
+ <strong>🎭 Vibes received prompt:</strong> "${extractedPrompt}"
61
+ <br><small>(This is a mock response from browser test)</small>
62
+ </div>`;
63
+ explanationText = 'This is a mock explanation from the browser test';
64
+ }
65
+ // Create the structured response object that matches the schema in useVibes
66
+ const responseObj = {
67
+ html: htmlContent,
68
+ explanation: explanationText,
69
+ };
70
+ // Store for debugging
71
+ window.__MOCK_STATUS__.lastResponse = responseObj;
72
+ /* eslint-disable-next-line no-console */
73
+ console.log('✅ MOCK: Created JSON response:', JSON.stringify(responseObj).substring(0, 100) + '...');
74
+ // Return a properly structured response that matches what useVibes expects
75
+ return Promise.resolve(JSON.stringify(responseObj));
76
+ };
77
+ // Create a mock module object that matches the structure of the real call-ai module
78
+ const mockModule = {
79
+ callAI: mockCallAI,
80
+ __isMock: true,
81
+ };
82
+ // Attempt multiple interception strategies for maximum browser compatibility
83
+ // Strategy 1: Intercept dynamic imports
84
+ // This works with newer module bundlers like Vite, Webpack, etc.
85
+ const originalImport = window.import;
86
+ window.import = function (specifier) {
87
+ if (specifier === 'call-ai') {
88
+ /* eslint-disable-next-line no-console */
89
+ console.log('🎯 MOCK: Import intercepted for call-ai module');
90
+ window.__MOCK_STATUS__.moduleIntercepted = true;
91
+ return Promise.resolve(mockModule);
92
+ }
93
+ return originalImport.apply(this, arguments);
94
+ };
95
+ // Strategy 2: Define the module globally for ESM imports to find
96
+ // Helps with static imports which can't be intercepted directly
97
+ window.mockCallAI = mockCallAI;
98
+ // Also set window.callAI for direct access tests
99
+ window.callAI = mockCallAI;
100
+ /* eslint-disable-next-line no-console */
101
+ console.log('✅ MOCK SETUP: Module interception complete - callAI has been mocked');
102
+ }
103
+ catch (error) {
104
+ console.error('❌ MOCK SETUP ERROR:', error);
105
+ window.__MOCK_STATUS__.errors.push(error.message);
106
+ }
107
+ // Flag to indicate mocks are initialized
108
+ window.mockInitialized = true;
109
+ // eslint-disable-next-line no-console
110
+ console.log('-----------------------------------------------------------');
111
+ // eslint-disable-next-line no-console
112
+ console.log('🔧 MOCK SETUP: Setting up call-ai mocks for browser tests...');
113
+ // eslint-disable-next-line no-console
114
+ console.log('-----------------------------------------------------------');
115
+ // Create a global debug flag to track what's happening with our mocks
116
+ window.MOCK_DEBUG = {
117
+ mockCallsCount: 0,
118
+ lastPrompt: null,
119
+ lastResponse: null,
120
+ };
121
+ // Mock the callAI function directly to ensure tests work correctly
122
+ // This is the most reliable way to mock the call-ai module
123
+ window.callAI = function mockCallAI(userPrompt, options = {}) {
124
+ window.MOCK_DEBUG.mockCallsCount++;
125
+ // eslint-disable-next-line no-console
126
+ console.log('🔄 MOCK INTERCEPTED: callAI invoked - call #', window.MOCK_DEBUG.mockCallsCount);
127
+ // eslint-disable-next-line no-console
128
+ console.log('📝 MOCK PROMPT:', typeof userPrompt === 'string' ? userPrompt.substring(0, 100) + '...' : 'Non-string prompt');
129
+ // eslint-disable-next-line no-console
130
+ console.log('⚙️ MOCK OPTIONS:', JSON.stringify(options));
131
+ // Store the prompt for debugging
132
+ window.MOCK_DEBUG.lastPrompt = userPrompt;
133
+ window.MOCK_DEBUG.lastOptions = options;
134
+ // Extract the actual request from the longer prompt - more robust regex handling
135
+ let extractedPrompt = 'Default prompt';
136
+ if (typeof userPrompt === 'string') {
137
+ const promptMatch = userPrompt.match(/Transform the HTML content based on this request:\s*([^\n]+)/);
138
+ if (promptMatch && promptMatch[1]) {
139
+ extractedPrompt = promptMatch[1].trim();
140
+ }
141
+ else if (userPrompt.includes('Alternative configuration test')) {
142
+ extractedPrompt = 'Alternative configuration test';
143
+ }
144
+ else if (userPrompt.includes('error') || userPrompt.includes('fail')) {
145
+ extractedPrompt = 'Error simulation test';
146
+ }
147
+ else {
148
+ // Just use a substring as a fallback - don't let tests fail because of regex
149
+ extractedPrompt = userPrompt.length > 50 ? userPrompt.substring(0, 50) + '...' : userPrompt;
150
+ }
151
+ }
152
+ // eslint-disable-next-line no-console
153
+ console.log('🔍 EXTRACTED PROMPT:', extractedPrompt);
154
+ // Check if this is an error test case
155
+ if (extractedPrompt.includes('error') || extractedPrompt.includes('fail')) {
156
+ // eslint-disable-next-line no-console
157
+ console.log('🚨 SIMULATING ERROR RESPONSE');
158
+ return Promise.reject(new Error('Simulated error from mock callAI'));
159
+ }
160
+ // Create response based on the prompt content
161
+ let htmlContent;
162
+ let explanationText;
163
+ if (extractedPrompt.includes('Alternative configuration')) {
164
+ // Custom response for alternative config test
165
+ htmlContent = `<div style="background-color: #fff8e1; padding: 10px; border: 2px solid #ffc107; border-radius: 5px;">
166
+ <strong>🎭 Vibes received prompt:</strong> "Alternative configuration test"
167
+ <br><small>(Alternative config mock response)</small>
168
+ </div>`;
169
+ explanationText = 'Mock explanation for alternative configuration';
170
+ }
171
+ else {
172
+ // Default response
173
+ htmlContent = `<div style="background-color: #eefbff; padding: 10px; border: 2px solid #0099cc; border-radius: 5px;">
174
+ <strong>🎭 Vibes received prompt:</strong> "${extractedPrompt}"
175
+ <br><small>(This is a mock response from browser test)</small>
176
+ </div>`;
177
+ explanationText = 'This is a mock explanation from the browser test';
178
+ }
179
+ // Create the response object in the exact format that useVibes expects
180
+ const responseObj = {
181
+ html: htmlContent,
182
+ explanation: explanationText,
183
+ };
184
+ // Store the response for debugging
185
+ window.MOCK_DEBUG.lastResponse = responseObj;
186
+ // eslint-disable-next-line no-console
187
+ console.log('✅ MOCK RESPONSE CREATED:', JSON.stringify(responseObj).substring(0, 100) + '...');
188
+ // useVibes expects a Promise that resolves to a string (JSON)
189
+ return Promise.resolve(JSON.stringify(responseObj));
190
+ };
191
+ // As a fallback, also mock fetch for any direct API calls
192
+ // Store the original fetch
193
+ window._originalFetch = window.fetch;
194
+ // Mock the fetch API for call-ai
195
+ window.fetch = async function mockedFetch(url, options) {
196
+ // Check if this is a call to the AI API
197
+ if (url && (url.includes('api.call-ai.com') || url.includes('api/v1/chat/completions'))) {
198
+ // eslint-disable-next-line no-console
199
+ console.log('Intercepted fetch call to:', url);
200
+ // Parse the request body to get the prompt
201
+ const requestBody = JSON.parse(options.body);
202
+ let promptText = '';
203
+ // Extract prompt from messages
204
+ if (requestBody.messages && requestBody.messages.length > 0) {
205
+ const lastMessage = requestBody.messages[requestBody.messages.length - 1];
206
+ promptText = lastMessage.content || '';
207
+ }
208
+ // Create a properly formatted mock response
209
+ const mockResponse = {
210
+ choices: [
211
+ {
212
+ message: {
213
+ role: 'assistant',
214
+ content: JSON.stringify({
215
+ html: `<div>🎭 Vibes received prompt: "${promptText}"</div>`,
216
+ explanation: 'This is a mock explanation from the browser test',
217
+ }),
218
+ },
219
+ index: 0,
220
+ },
221
+ ],
222
+ id: 'mock-response-id',
223
+ model: 'gpt-3.5-turbo',
224
+ object: 'chat.completion',
225
+ };
226
+ // Return a Response object with the mock data
227
+ return new Response(JSON.stringify(mockResponse), {
228
+ status: 200,
229
+ headers: { 'Content-Type': 'application/json' },
230
+ });
231
+ }
232
+ // For any other fetch calls, use the original implementation
233
+ return window._originalFetch(url, options);
234
+ };
235
+ // eslint-disable-next-line no-console
236
+ console.log('-----------------------------------------------------------');
237
+ // eslint-disable-next-line no-console
238
+ console.log('✅ MOCK SETUP COMPLETE: All mocks for callAI and fetch API ready!');
239
+ // eslint-disable-next-line no-console
240
+ console.log('-----------------------------------------------------------');
241
+ })();
242
+ export {};
@@ -0,0 +1 @@
1
+ export {};