feat: support external and step images with structured cooking instructions
This commit is contained in:
1 parent
361862ad0b
commit
0ec1d45bdb
34 files changed
+898
-92
No files matched your search
@@ -17,6 +17,53 @@ describe('Versioned, safe, lossless recipe interchange', () => {
|
||||
};
|
||||
expect(parseImport(exportRecipes([r], 'xml'), 'xml').recipes[0]).toEqual(r);
|
||||
});
|
||||
it.each(['json', 'xml'] as const)(
|
||||
'roundtrips external cover, gallery and step images in %s',
|
||||
(format) => {
|
||||
const r = recipeSchema.parse({
|
||||
...pasta,
|
||||
image: 'https://images.example.org/cover?width=1200&format=webp',
|
||||
images: ['https://images.example.org/gallery.jpg'],
|
||||
steps: pasta.steps.map((s, n) => ({
|
||||
...s,
|
||||
images:
|
||||
n === 0 ? ['/images/kitchen.jpg', 'https://images.example.org/step.png?x=1&y=2'] : [],
|
||||
})),
|
||||
});
|
||||
expect(parseImport(exportRecipes([r], format), format).recipes[0]).toEqual(r);
|
||||
},
|
||||
);
|
||||
it('keeps older recipes without step images compatible', () => {
|
||||
const r = { ...pasta, steps: pasta.steps.map(({ images, ...step }) => step) };
|
||||
expect(
|
||||
parseImport(JSON.stringify({ version: 1, recipes: [r] }), 'json').recipes[0].steps.every(
|
||||
(s) => s.images.length === 0,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
it.each([
|
||||
'http://example.org/a.jpg',
|
||||
'//example.org/a.jpg',
|
||||
'javascript:alert(1)',
|
||||
'data:image/png;base64,AAAA',
|
||||
'https://user:password@example.org/a.jpg',
|
||||
'https://',
|
||||
'https://example.org/\\evil',
|
||||
'https://example.org/' + 'a'.repeat(2048),
|
||||
])('rejects unsupported image URL %s', (image) => {
|
||||
expect(recipeSchema.safeParse({ ...pasta, image }).success).toBe(false);
|
||||
expect(
|
||||
recipeSchema.safeParse({ ...pasta, steps: [{ ...pasta.steps[0], images: [image] }] }).success,
|
||||
).toBe(false);
|
||||
});
|
||||
it('limits step images', () => {
|
||||
expect(
|
||||
recipeSchema.safeParse({
|
||||
...pasta,
|
||||
steps: [{ ...pasta.steps[0], images: Array(11).fill('/images/kitchen.jpg') }],
|
||||
}).success,
|
||||
).toBe(false);
|
||||
});
|
||||
it('rejects unknown versions and missing mandatory fields', () => {
|
||||
expect(() => parseImport('{"version":2,"recipes":[]}', 'json')).toThrow();
|
||||
expect(() => parseImport('{"version":1,"recipes":[{"title":"Test"}]}', 'json')).toThrow();
|
||||
|
||||
Reference in new issue
Block a user