Files
kochwas/tests/e2e/remote/photo-import.spec.ts

81 lines
2.7 KiB
TypeScript
Raw Normal View History

import { test, expect } from '@playwright/test';
import { resolve } from 'node:path';
// Wir stubben den Extract-Endpoint server-side nicht (das Feature liegt auf
// dev hinter dem echten Gemini-Key), sondern auf context-Ebene: Playwright
// fängt alle Requests auf /api/recipes/extract-from-photo ab und liefert
// einen deterministischen JSON-Body zurück. Keine Gemini-Kosten in CI.
test('Foto-Import Happy-Path mit gestubtem Extract-Endpoint', async ({
page,
context
}) => {
await context.route('**/api/recipes/extract-from-photo', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
recipe: {
id: null,
title: 'E2E Testrezept',
description: 'Aus dem Bild herbeigezaubert.',
source_url: null,
source_domain: null,
image_path: null,
servings_default: 2,
servings_unit: 'Portionen',
prep_time_min: 5,
cook_time_min: 10,
total_time_min: null,
cuisine: null,
category: null,
ingredients: [
{
position: 1,
quantity: 1,
unit: 'Stk',
name: 'E2E-Apfel',
note: null,
raw_text: '1 Stk E2E-Apfel',
section_heading: null
}
],
steps: [{ position: 1, text: 'Apfel waschen.' }],
tags: []
}
})
});
});
await page.goto('/new/from-photo');
await expect(page.getByRole('heading', { name: 'Rezept aus Foto' })).toBeVisible();
const fixture = resolve(__dirname, '../../fixtures/photo-recipe/sample-printed.jpg');
await page.locator('input[type="file"]').setInputFiles(fixture);
await expect(page.getByText('Aus Foto erstellt')).toBeVisible({ timeout: 5000 });
// Titel-Feld (das erste text-input im Editor)
await expect(page.locator('input[type="text"]').first()).toHaveValue(
'E2E Testrezept'
);
});
test('Camera-Icon im Header wird disabled, wenn der Client offline geht', async ({
page,
context
}) => {
await page.goto('/');
const icon = page.locator('[aria-label="Rezept aus Foto erstellen"]');
// Nur relevant, wenn der Dev-Server einen Gemini-Key hat — andernfalls ist
// das Icon per Graceful-Degradation gar nicht gerendert und der Test wird
// hier early-skipped. (Im Prod und Dev mit Key gilt der zweite Pfad.)
if ((await icon.count()) === 0) {
test.skip(true, 'Dev-Env hat keinen GEMINI_API_KEY gesetzt.');
return;
}
await expect(icon).toBeVisible();
await context.setOffline(true);
await page.waitForFunction(() => !navigator.onLine);
await expect(icon).toHaveClass(/disabled/);
});