226 lines
8.9 KiB
TypeScript
226 lines
8.9 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { ConfigSchema } from '../src/config/index.js';
|
|
|
|
describe('Prompt Testing', () => {
|
|
const configPath = path.resolve(process.cwd(), 'config.yaml');
|
|
|
|
describe('config.yaml prompts', () => {
|
|
it('loads successfully', () => {
|
|
expect(fs.existsSync(configPath)).toBe(true);
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
expect(content).toContain('imageAnalysisPrompt');
|
|
expect(content).toContain('messageGenerationPrompt');
|
|
});
|
|
|
|
it('imageAnalysisPrompt requests body features', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.imageAnalysisPrompt).toContain('breasts');
|
|
expect(prompts.imageAnalysisPrompt).toContain('ASS');
|
|
expect(prompts.imageAnalysisPrompt).toContain('vagina');
|
|
expect(prompts.imageAnalysisPrompt).toContain('BODY');
|
|
expect(prompts.imageAnalysisPrompt).toContain('POSE');
|
|
expect(prompts.imageAnalysisPrompt).toContain('VIBE');
|
|
expect(prompts.imageAnalysisPrompt).toContain('EXTRAS');
|
|
});
|
|
|
|
it('messageGenerationPrompt has proper structure', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.messageGenerationPrompt).toContain('{analysis}');
|
|
expect(prompts.messageGenerationPrompt).toContain('{title}');
|
|
expect(prompts.messageGenerationPrompt).toContain('{author}');
|
|
});
|
|
|
|
it('messageGenerationPrompt specifies DO NOT list', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.messageGenerationPrompt).toContain('DO NOT');
|
|
expect(prompts.messageGenerationPrompt).toContain('captivating');
|
|
expect(prompts.messageGenerationPrompt).toContain('alluring');
|
|
expect(prompts.messageGenerationPrompt).toContain('exquisite');
|
|
expect(prompts.messageGenerationPrompt).toContain('radiant');
|
|
});
|
|
|
|
it('messageGenerationPrompt specifies GOOD HOOKS', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.messageGenerationPrompt).toContain('GOOD HOOKS');
|
|
expect(prompts.messageGenerationPrompt).toContain('BAD HOOKS');
|
|
});
|
|
|
|
it('messageGenerationPrompt specifies language requirements', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.messageGenerationPrompt).toContain('explicit terms');
|
|
expect(prompts.messageGenerationPrompt).toContain('tits');
|
|
expect(prompts.messageGenerationPrompt).toContain('ass');
|
|
expect(prompts.messageGenerationPrompt).toContain('pussy');
|
|
expect(prompts.messageGenerationPrompt).toContain('boobs');
|
|
});
|
|
|
|
it('messageGenerationPrompt specifies what to avoid', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const prompts = parseYamlPrompts(content);
|
|
|
|
expect(prompts.messageGenerationPrompt).toContain('breasts');
|
|
expect(prompts.messageGenerationPrompt).toContain('buttocks');
|
|
expect(prompts.messageGenerationPrompt).toContain('posterior');
|
|
expect(prompts.messageGenerationPrompt).toContain('physique');
|
|
});
|
|
});
|
|
|
|
describe('strategy prompts', () => {
|
|
it('loads strategy variants', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.strategies.variants).toBeDefined();
|
|
expect(config.strategies.variants.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('each strategy has id and promptOverride', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
for (const variant of config.strategies.variants) {
|
|
expect(variant.id).toBeDefined();
|
|
expect(variant.promptOverride).toBeDefined();
|
|
expect(typeof variant.id).toBe('string');
|
|
expect(typeof variant.promptOverride).toBe('string');
|
|
expect(variant.id.length).toBeGreaterThan(0);
|
|
expect(variant.promptOverride.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('strategy prompts are distinct', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
const prompts = config.strategies.variants.map(v => v.promptOverride.toLowerCase());
|
|
const uniquePrompts = new Set(prompts);
|
|
expect(uniquePrompts.size).toBe(prompts.length);
|
|
});
|
|
|
|
it('strategy variants have valid IDs', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
for (const variant of config.strategies.variants) {
|
|
expect(variant.id).toMatch(/^[a-z0-9_]+$/);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('prompt variable substitution', () => {
|
|
it('imageAnalysisPrompt contains all required variables', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
// The image analysis prompt should not contain unsubstitutable variables
|
|
// (it receives raw image data, not text variables)
|
|
expect(config.openrouter.imageAnalysisPrompt).toBeDefined();
|
|
});
|
|
|
|
it('messageGenerationPrompt contains all substitution variables', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.openrouter.messageGenerationPrompt).toContain('{analysis}');
|
|
expect(config.openrouter.messageGenerationPrompt).toContain('{title}');
|
|
expect(config.openrouter.messageGenerationPrompt).toContain('{author}');
|
|
});
|
|
|
|
it('all substitution variables are in {variable} format', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
const variables = config.openrouter.messageGenerationPrompt.match(/\{(\w+)\}/g);
|
|
expect(variables).toEqual(expect.arrayContaining(['{analysis}', '{title}', '{author}']));
|
|
});
|
|
});
|
|
|
|
describe('prompt quality checks', () => {
|
|
it('messageGenerationPrompt is not empty', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.openrouter.messageGenerationPrompt.trim().length).toBeGreaterThan(50);
|
|
});
|
|
|
|
it('imageAnalysisPrompt is not empty', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.openrouter.imageAnalysisPrompt.trim().length).toBeGreaterThan(50);
|
|
});
|
|
|
|
it('messageGenerationPrompt has examples', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.openrouter.messageGenerationPrompt).toContain('Examples of good messages');
|
|
expect(config.openrouter.messageGenerationPrompt).toContain('"Damn those tits');
|
|
});
|
|
|
|
it('imageAnalysisPrompt requests a rating', () => {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
|
|
expect(config.openrouter.imageAnalysisPrompt).toContain('rate her attractiveness');
|
|
expect(config.openrouter.imageAnalysisPrompt).toContain('1-100 scale');
|
|
expect(config.openrouter.imageAnalysisPrompt).toContain('RATING:');
|
|
});
|
|
});
|
|
|
|
describe('seller keywords', () => {
|
|
function loadParsedConfig() {
|
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
const yaml = require('yaml');
|
|
const rawConfig = yaml.parse(content);
|
|
rawConfig.openrouter = rawConfig.openrouter || {};
|
|
rawConfig.openrouter.apiKey = rawConfig.openrouter.apiKey || 'test';
|
|
rawConfig.web = rawConfig.web || {};
|
|
rawConfig.web.authToken = 'create01';
|
|
return ConfigSchema.parse(rawConfig);
|
|
}
|
|
|
|
it('reddit sellerKeywords includes common platforms', () => {
|
|
const config = loadParsedConfig();
|
|
const keywords = config.reddit.sellerKeywords.map((k: string) => k.toLowerCase());
|
|
expect(keywords).toContain('onlyfans');
|
|
expect(keywords).toContain('fansly');
|
|
expect(keywords).toContain('manyvids');
|
|
expect(keywords).toContain('cash.app');
|
|
expect(keywords).toContain('venmo');
|
|
});
|
|
});
|
|
});
|
|
|
|
function parseYamlPrompts(content: string): { imageAnalysisPrompt: string; messageGenerationPrompt: string } {
|
|
const yaml = require('yaml');
|
|
const config = yaml.parse(content);
|
|
return {
|
|
imageAnalysisPrompt: config.openrouter.imageAnalysisPrompt,
|
|
messageGenerationPrompt: config.openrouter.messageGenerationPrompt,
|
|
};
|
|
}
|