This commit is contained in:
@@ -3,7 +3,7 @@ import { ref } from 'vue';
|
||||
import {
|
||||
deleteImage,
|
||||
listAdminImages,
|
||||
reorderImage,
|
||||
moveImage,
|
||||
retryImageProcessing,
|
||||
setPrimaryImage,
|
||||
updateImageAltText,
|
||||
@@ -76,18 +76,6 @@ export function useAdminImages(inventoryItemId) {
|
||||
});
|
||||
}
|
||||
|
||||
async function moveImage(imageId, direction) {
|
||||
const ordered = [...images.value].sort((left, right) => left.sortOrder - right.sortOrder);
|
||||
const index = ordered.findIndex((image) => image.id === imageId);
|
||||
const neighborIndex = direction === 'up' ? index - 1 : index + 1;
|
||||
if (index === -1 || neighborIndex < 0 || neighborIndex >= ordered.length) return;
|
||||
const current = ordered[index];
|
||||
const neighbor = ordered[neighborIndex];
|
||||
await apply(async (token) => {
|
||||
await reorderImage(current.id, neighbor.sortOrder, token);
|
||||
await reorderImage(neighbor.id, current.sortOrder, token);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
images,
|
||||
@@ -98,7 +86,7 @@ export function useAdminImages(inventoryItemId) {
|
||||
hasLoaded,
|
||||
load,
|
||||
upload,
|
||||
move: moveImage,
|
||||
move: (imageId, direction) => apply((token) => moveImage(imageId, direction, token)),
|
||||
setPrimary: (imageId) => apply((token) => setPrimaryImage(imageId, token)),
|
||||
updateAltText: (imageId, altText) => apply((token) => updateImageAltText(imageId, altText, token)),
|
||||
retry: (imageId) => apply((token) => retryImageProcessing(imageId, token)),
|
||||
|
||||
@@ -10,6 +10,7 @@ export default {
|
||||
let reads = 0;
|
||||
let writes = 0;
|
||||
let images = [{ id: 'image-1', altText: 'Front of card', sortOrder: 0, isPrimary: true, processingStatus: 'COMPLETED' }];
|
||||
if (scenario === 'move' || scenario === 'move-error') images.push({ id: 'image-2', altText: 'Back of card', sortOrder: 1, isPrimary: false, processingStatus: 'COMPLETED' });
|
||||
const reply = (data) => new Response(JSON.stringify({ data }), { headers: { 'content-type': 'application/json' } });
|
||||
const fail = (message) => new Response(JSON.stringify({ error: { message } }), { status: 503 });
|
||||
globalThis.fetch = async (url, options = {}) => {
|
||||
@@ -21,6 +22,15 @@ export default {
|
||||
return reply(images);
|
||||
}
|
||||
writes += 1;
|
||||
if (scenario === 'move' || scenario === 'move-error') {
|
||||
await expect(String(url)).toMatch(/\/images\/image-[12]\/move$/);
|
||||
await expect(options.method).toBe('POST');
|
||||
const { direction } = JSON.parse(options.body);
|
||||
await expect(['up', 'down']).toContain(direction);
|
||||
if (scenario === 'move-error' && writes === 1) return fail('Move failed.');
|
||||
images = [...images].reverse().map((image, sortOrder) => ({ ...image, sortOrder }));
|
||||
return reply(images[0]);
|
||||
}
|
||||
if (scenario === 'saving') return new Promise(() => {});
|
||||
if (scenario === 'partial-upload' && writes === 2) return fail('Second upload failed.');
|
||||
if (options.body instanceof FormData) images = [...images, { id: `uploaded-${writes}`, altText: options.body.get('altText'), sortOrder: images.length, isPrimary: false, processingStatus: 'COMPLETED' }];
|
||||
@@ -137,3 +147,29 @@ export const PartialUploadFailure = {
|
||||
await expect(canvas.getByRole('button', { name: 'front.png' })).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const AtomicMove = {
|
||||
parameters: { imageScenario: 'move' },
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const down = await canvas.findAllByRole('button', { name: 'Move down' });
|
||||
await userEvent.click(down[0]);
|
||||
await waitFor(() => expect(canvas.getAllByRole('button', { name: /^(Front|Back) of card$/ })[0]).toHaveTextContent('Back of card'));
|
||||
await userEvent.click(canvas.getAllByRole('button', { name: 'Move up' })[1]);
|
||||
await waitFor(() => expect(canvas.getAllByRole('button', { name: /^(Front|Back) of card$/ })[0]).toHaveTextContent('Front of card'));
|
||||
await expect(canvas.getAllByRole('button', { name: 'Move up' })[0]).toBeDisabled();
|
||||
await expect(canvas.getAllByRole('button', { name: 'Move down' })[1]).toBeDisabled();
|
||||
},
|
||||
};
|
||||
export const FailedAtomicMove = {
|
||||
parameters: { imageScenario: 'move-error' },
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click((await canvas.findAllByRole('button', { name: 'Move down' }))[0]);
|
||||
await expect(await canvas.findByRole('alert')).toHaveTextContent('Move failed.');
|
||||
await waitFor(() => expect(canvas.getAllByRole('button', { name: 'Move down' })[0]).toBeEnabled());
|
||||
await expect(canvas.getAllByRole('button', { name: /^(Front|Back) of card$/ })[0]).toHaveTextContent('Front of card');
|
||||
await userEvent.click(canvas.getAllByRole('button', { name: 'Move down' })[0]);
|
||||
await waitFor(() => expect(canvas.getAllByRole('button', { name: /^(Front|Back) of card$/ })[0]).toHaveTextContent('Back of card'));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -80,3 +80,11 @@ export async function listAdminImages(inventoryItemId) {
|
||||
headers: {},
|
||||
});
|
||||
}
|
||||
|
||||
export function moveImage(imageId, direction, csrfToken) {
|
||||
return request(`/admin/images/${encodeURIComponent(imageId)}/move`, {
|
||||
method: 'POST',
|
||||
headers: { 'x-csrf-token': csrfToken },
|
||||
body: JSON.stringify({ direction }),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user