work on tests
This commit is contained in:
parent
a1e2368468
commit
3296d3ab6e
|
|
@ -2,12 +2,30 @@
|
||||||
* Canvas interaction utilities for UI testing
|
* Canvas interaction utilities for UI testing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset canvas scroll/pan to origin
|
||||||
|
*/
|
||||||
|
export async function resetCanvasView() {
|
||||||
|
await browser.execute(function() {
|
||||||
|
if (window.context && window.context.stageWidget) {
|
||||||
|
window.context.stageWidget.offsetX = 0;
|
||||||
|
window.context.stageWidget.offsetY = 0;
|
||||||
|
// Trigger redraw to apply the reset
|
||||||
|
if (window.context.updateUI) {
|
||||||
|
window.context.updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await browser.pause(100); // Wait for canvas to reset
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click at specific coordinates on the canvas
|
* Click at specific coordinates on the canvas
|
||||||
* @param {number} x - X coordinate relative to canvas
|
* @param {number} x - X coordinate relative to canvas
|
||||||
* @param {number} y - Y coordinate relative to canvas
|
* @param {number} y - Y coordinate relative to canvas
|
||||||
*/
|
*/
|
||||||
export async function clickCanvas(x, y) {
|
export async function clickCanvas(x, y) {
|
||||||
|
await resetCanvasView();
|
||||||
await browser.clickCanvas(x, y);
|
await browser.clickCanvas(x, y);
|
||||||
await browser.pause(100); // Wait for render
|
await browser.pause(100); // Wait for render
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +38,7 @@ export async function clickCanvas(x, y) {
|
||||||
* @param {number} toY - Ending Y coordinate
|
* @param {number} toY - Ending Y coordinate
|
||||||
*/
|
*/
|
||||||
export async function dragCanvas(fromX, fromY, toX, toY) {
|
export async function dragCanvas(fromX, fromY, toX, toY) {
|
||||||
|
await resetCanvasView();
|
||||||
await browser.dragCanvas(fromX, fromY, toX, toY);
|
await browser.dragCanvas(fromX, fromY, toX, toY);
|
||||||
await browser.pause(200); // Wait for render
|
await browser.pause(200); // Wait for render
|
||||||
}
|
}
|
||||||
|
|
@ -206,6 +225,11 @@ export async function setPlayheadTime(time) {
|
||||||
if (window.context.timelineWidget && window.context.timelineWidget.requestRedraw) {
|
if (window.context.timelineWidget && window.context.timelineWidget.requestRedraw) {
|
||||||
window.context.timelineWidget.requestRedraw();
|
window.context.timelineWidget.requestRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger stage redraw to show shapes at new time
|
||||||
|
if (window.context.updateUI) {
|
||||||
|
window.context.updateUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, time);
|
}, time);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
clickCanvas
|
clickCanvas
|
||||||
} from '../helpers/canvas.js';
|
} from '../helpers/canvas.js';
|
||||||
import { assertShapeExists } from '../helpers/assertions.js';
|
import { assertShapeExists } from '../helpers/assertions.js';
|
||||||
|
import { verifyManually, logStep } from '../helpers/manual.js';
|
||||||
|
|
||||||
describe('Group Editing', () => {
|
describe('Group Editing', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
@ -71,6 +72,7 @@ describe('Group Editing', () => {
|
||||||
|
|
||||||
it('should handle nested group editing with correct positioning', async () => {
|
it('should handle nested group editing with correct positioning', async () => {
|
||||||
// Create first group with two shapes
|
// Create first group with two shapes
|
||||||
|
await logStep('Drawing two rectangles for inner group');
|
||||||
await drawRectangle(400, 100, 60, 60);
|
await drawRectangle(400, 100, 60, 60);
|
||||||
await drawRectangle(480, 100, 60, 60);
|
await drawRectangle(480, 100, 60, 60);
|
||||||
await selectMultipleShapes([
|
await selectMultipleShapes([
|
||||||
|
|
@ -80,24 +82,47 @@ describe('Group Editing', () => {
|
||||||
await useKeyboardShortcut('g', true);
|
await useKeyboardShortcut('g', true);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: Do you see two rectangles grouped together?\nClick OK if yes, Cancel if no');
|
||||||
|
|
||||||
// Verify both shapes exist
|
// Verify both shapes exist
|
||||||
await assertShapeExists(430, 130, 'First shape should exist');
|
await assertShapeExists(430, 130, 'First shape should exist');
|
||||||
await assertShapeExists(510, 130, 'Second shape should exist');
|
await assertShapeExists(510, 130, 'Second shape should exist');
|
||||||
|
|
||||||
// Create another shape and group everything together
|
// Create another shape and group everything together
|
||||||
|
await logStep('Drawing third rectangle and creating nested group');
|
||||||
await drawRectangle(400, 180, 60, 60);
|
await drawRectangle(400, 180, 60, 60);
|
||||||
await selectMultipleShapes([
|
|
||||||
{ x: 470, y: 130 }, // Center of first group
|
// Select both the group and the new shape by dragging a selection box
|
||||||
{ x: 430, y: 210 } // Center of new shape
|
// We need to start from well outside the shapes to avoid hitting them
|
||||||
]);
|
// The first group spans x=400-540, y=100-160
|
||||||
|
// The third shape spans x=400-460, y=180-240
|
||||||
|
await selectTool('select');
|
||||||
|
await dragCanvas(390, 90, 550, 250); // Start from outside all shapes
|
||||||
|
await browser.pause(200);
|
||||||
|
|
||||||
await useKeyboardShortcut('g', true);
|
await useKeyboardShortcut('g', true);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: All three rectangles now grouped together (nested group)?\nClick OK if yes, Cancel if no');
|
||||||
|
|
||||||
// Double-click to enter outer group
|
// Double-click to enter outer group
|
||||||
|
await logStep('Double-clicking to enter outer group');
|
||||||
await doubleClickCanvas(470, 130);
|
await doubleClickCanvas(470, 130);
|
||||||
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: Are we now inside the outer group?\nClick OK if yes, Cancel if no');
|
||||||
|
|
||||||
// Double-click again to enter inner group
|
// Double-click again to enter inner group
|
||||||
|
await logStep('Double-clicking again to enter inner group');
|
||||||
await doubleClickCanvas(470, 130);
|
await doubleClickCanvas(470, 130);
|
||||||
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually(
|
||||||
|
'VERIFY: Are we now inside the inner group?\n' +
|
||||||
|
'Can you see the two original rectangles at their original positions?\n' +
|
||||||
|
'First at (430, 130), second at (510, 130)?\n\n' +
|
||||||
|
'Click OK if yes, Cancel if no'
|
||||||
|
);
|
||||||
|
|
||||||
// All shapes should still be at their original positions
|
// All shapes should still be at their original positions
|
||||||
await assertShapeExists(430, 130, 'First shape should maintain position in nested group');
|
await assertShapeExists(430, 130, 'First shape should maintain position in nested group');
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ import { waitForAppReady } from '../../helpers/app.js';
|
||||||
import {
|
import {
|
||||||
drawRectangle,
|
drawRectangle,
|
||||||
selectMultipleShapes,
|
selectMultipleShapes,
|
||||||
|
selectTool,
|
||||||
dragCanvas,
|
dragCanvas,
|
||||||
|
clickCanvas,
|
||||||
setPlayheadTime,
|
setPlayheadTime,
|
||||||
getPlayheadTime,
|
getPlayheadTime,
|
||||||
addKeyframe,
|
addKeyframe,
|
||||||
|
|
@ -42,7 +44,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
it('TEST 1: Group animation - draw, group, keyframe, move group', async () => {
|
it('TEST 1: Group animation - draw, group, keyframe, move group', async () => {
|
||||||
await logStep('Drawing a RED rectangle at (100, 100) with size 100x100');
|
await logStep('Drawing a RED rectangle at (100, 100) with size 100x100');
|
||||||
await drawRectangle(100, 100, 100, 100, true, '#ff0000');
|
await drawRectangle(100, 100, 100, 100, true, '#ff0000');
|
||||||
await pauseAndDescribe('RED rectangle drawn', 2000);
|
await pauseAndDescribe('RED rectangle drawn', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Do you see a RED filled rectangle at the top-left area?\n' +
|
'VERIFY: Do you see a RED filled rectangle at the top-left area?\n' +
|
||||||
|
|
@ -52,7 +54,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Selecting the RED rectangle by dragging a selection box over it');
|
await logStep('Selecting the RED rectangle by dragging a selection box over it');
|
||||||
await selectMultipleShapes([{ x: 150, y: 150 }]);
|
await selectMultipleShapes([{ x: 150, y: 150 }]);
|
||||||
await pauseAndDescribe('RED rectangle selected', 2000);
|
await pauseAndDescribe('RED rectangle selected', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Is the RED rectangle now selected? (Should have selection indicators)\n\n' +
|
'VERIFY: Is the RED rectangle now selected? (Should have selection indicators)\n\n' +
|
||||||
|
|
@ -61,7 +63,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Grouping the selected rectangle (Ctrl+G)');
|
await logStep('Grouping the selected rectangle (Ctrl+G)');
|
||||||
await useKeyboardShortcut('g', true);
|
await useKeyboardShortcut('g', true);
|
||||||
await pauseAndDescribe('RED rectangle grouped', 2000);
|
await pauseAndDescribe('RED rectangle grouped', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Was the rectangle grouped? (May look similar but is now a group)\n\n' +
|
'VERIFY: Was the rectangle grouped? (May look similar but is now a group)\n\n' +
|
||||||
|
|
@ -70,11 +72,11 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Selecting the group by dragging a selection box over it');
|
await logStep('Selecting the group by dragging a selection box over it');
|
||||||
await selectMultipleShapes([{ x: 150, y: 150 }]);
|
await selectMultipleShapes([{ x: 150, y: 150 }]);
|
||||||
await pauseAndDescribe('Group selected', 2000);
|
await pauseAndDescribe('Group selected', 200);
|
||||||
|
|
||||||
await logStep('Moving playhead to time 0.333 (frame 10 at 30fps)');
|
await logStep('Moving playhead to time 0.333 (frame 10 at 30fps)');
|
||||||
await setPlayheadTime(0.333);
|
await setPlayheadTime(0.333);
|
||||||
await pauseAndDescribe('Playhead moved to 0.333s - WAIT for UI to update', 3000);
|
await pauseAndDescribe('Playhead moved to 0.333s - WAIT for UI to update', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the playhead indicator move on the timeline?\n' +
|
'VERIFY: Did the playhead indicator move on the timeline?\n' +
|
||||||
|
|
@ -84,7 +86,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Adding a keyframe at current position');
|
await logStep('Adding a keyframe at current position');
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await pauseAndDescribe('Keyframe added', 2000);
|
await pauseAndDescribe('Keyframe added', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Was a keyframe added? (Should see a keyframe marker on timeline)\n\n' +
|
'VERIFY: Was a keyframe added? (Should see a keyframe marker on timeline)\n\n' +
|
||||||
|
|
@ -93,7 +95,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Dragging the selected group to move it right (from x=150 to x=250)');
|
await logStep('Dragging the selected group to move it right (from x=150 to x=250)');
|
||||||
await dragCanvas(150, 150, 250, 150);
|
await dragCanvas(150, 150, 250, 150);
|
||||||
await pauseAndDescribe('Group moved to the right', 3000);
|
await pauseAndDescribe('Group moved to the right', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the RED rectangle move to the right?\n' +
|
'VERIFY: Did the RED rectangle move to the right?\n' +
|
||||||
|
|
@ -103,7 +105,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Moving playhead back to time 0 (frame 1)');
|
await logStep('Moving playhead back to time 0 (frame 1)');
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await pauseAndDescribe('Playhead back at start', 3000);
|
await pauseAndDescribe('Playhead back at start', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the RED rectangle jump back to its original position (x=150)?\n' +
|
'VERIFY: Did the RED rectangle jump back to its original position (x=150)?\n' +
|
||||||
|
|
@ -113,7 +115,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Moving playhead to middle (time 0.166, frame 5)');
|
await logStep('Moving playhead to middle (time 0.166, frame 5)');
|
||||||
await setPlayheadTime(0.166);
|
await setPlayheadTime(0.166);
|
||||||
await pauseAndDescribe('Playhead at middle frame', 3000);
|
await pauseAndDescribe('Playhead at middle frame', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Is the RED rectangle now between the two positions?\n' +
|
'VERIFY: Is the RED rectangle now between the two positions?\n' +
|
||||||
|
|
@ -123,13 +125,13 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Moving playhead back and forth to show animation');
|
await logStep('Moving playhead back and forth to show animation');
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(1000);
|
await browser.pause(300);
|
||||||
await setPlayheadTime(0.333);
|
await setPlayheadTime(0.333);
|
||||||
await browser.pause(1000);
|
await browser.pause(300);
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(1000);
|
await browser.pause(300);
|
||||||
await setPlayheadTime(0.333);
|
await setPlayheadTime(0.333);
|
||||||
await browser.pause(1000);
|
await browser.pause(300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did you see the RED rectangle animate back and forth?\n' +
|
'VERIFY: Did you see the RED rectangle animate back and forth?\n' +
|
||||||
|
|
@ -146,9 +148,13 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('TEST 2: Shape tween - draw shape, add keyframes, modify edges', async () => {
|
it('TEST 2: Shape tween - draw shape, add keyframes, modify edges', async () => {
|
||||||
|
await logStep('Resetting playhead to time 0 at start of test');
|
||||||
|
await setPlayheadTime(0);
|
||||||
|
await pauseAndDescribe('Playhead reset to time 0', 200);
|
||||||
|
|
||||||
await logStep('Drawing a BLUE rectangle at (400, 100)');
|
await logStep('Drawing a BLUE rectangle at (400, 100)');
|
||||||
await drawRectangle(400, 100, 80, 80, true, '#0000ff');
|
await drawRectangle(400, 100, 80, 80, true, '#0000ff');
|
||||||
await pauseAndDescribe('BLUE rectangle drawn', 2000);
|
await pauseAndDescribe('BLUE rectangle drawn', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Do you see a BLUE filled rectangle?\n' +
|
'VERIFY: Do you see a BLUE filled rectangle?\n' +
|
||||||
|
|
@ -158,7 +164,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Selecting the BLUE rectangle');
|
await logStep('Selecting the BLUE rectangle');
|
||||||
await selectMultipleShapes([{ x: 440, y: 140 }]);
|
await selectMultipleShapes([{ x: 440, y: 140 }]);
|
||||||
await pauseAndDescribe('BLUE rectangle selected', 2000);
|
await pauseAndDescribe('BLUE rectangle selected', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Is the BLUE rectangle selected?\n' +
|
'VERIFY: Is the BLUE rectangle selected?\n' +
|
||||||
|
|
@ -166,9 +172,9 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
'Click OK if yes, Cancel if no'
|
'Click OK if yes, Cancel if no'
|
||||||
);
|
);
|
||||||
|
|
||||||
await logStep('Moving playhead to time 0.5');
|
await logStep('Moving playhead to time 0.5 (frame 12 at 24fps)');
|
||||||
await setPlayheadTime(0.5);
|
await setPlayheadTime(0.5);
|
||||||
await pauseAndDescribe('Playhead moved to 0.5s - WAIT for UI to update', 3000);
|
await pauseAndDescribe('Playhead moved to 0.5s - WAIT for UI to update', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the playhead move to 0.5s on the timeline?\n\n' +
|
'VERIFY: Did the playhead move to 0.5s on the timeline?\n\n' +
|
||||||
|
|
@ -177,16 +183,26 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Adding a keyframe at time 0.5');
|
await logStep('Adding a keyframe at time 0.5');
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await pauseAndDescribe('Keyframe added at 0.5s', 2000);
|
await pauseAndDescribe('Keyframe added at 0.5s', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Was a keyframe added at 0.5s?\n\n' +
|
'VERIFY: Was a keyframe added at 0.5s?\n\n' +
|
||||||
'Click OK if yes, Cancel if no'
|
'Click OK if yes, Cancel if no'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await logStep('Clicking away from the shape to deselect it');
|
||||||
|
await clickCanvas(600, 300);
|
||||||
|
await pauseAndDescribe('Shape deselected', 100);
|
||||||
|
|
||||||
|
await verifyManually(
|
||||||
|
'VERIFY: Is the BLUE rectangle now deselected?\n' +
|
||||||
|
'(No selection indicators around it)\n\n' +
|
||||||
|
'Click OK if yes, Cancel if no'
|
||||||
|
);
|
||||||
|
|
||||||
await logStep('Dragging the right edge of the BLUE rectangle to curve/extend it');
|
await logStep('Dragging the right edge of the BLUE rectangle to curve/extend it');
|
||||||
await dragCanvas(480, 140, 530, 140);
|
await dragCanvas(480, 140, 530, 140);
|
||||||
await pauseAndDescribe('Dragged right edge of BLUE rectangle', 3000);
|
await pauseAndDescribe('Dragged right edge of BLUE rectangle', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the right edge of the BLUE rectangle get curved/pulled out?\n' +
|
'VERIFY: Did the right edge of the BLUE rectangle get curved/pulled out?\n' +
|
||||||
|
|
@ -196,7 +212,7 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
|
|
||||||
await logStep('Moving playhead back to time 0');
|
await logStep('Moving playhead back to time 0');
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await pauseAndDescribe('Playhead back at start', 3000);
|
await pauseAndDescribe('Playhead back at start', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Did the BLUE rectangle return to its original rectangular shape?\n' +
|
'VERIFY: Did the BLUE rectangle return to its original rectangular shape?\n' +
|
||||||
|
|
@ -204,13 +220,14 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
'Click OK if yes, Cancel if no'
|
'Click OK if yes, Cancel if no'
|
||||||
);
|
);
|
||||||
|
|
||||||
await logStep('Moving playhead to middle (time 0.25)');
|
await logStep('Moving playhead to middle between keyframes (time 0.25, frame 6)');
|
||||||
await setPlayheadTime(0.25);
|
await setPlayheadTime(0.25);
|
||||||
await pauseAndDescribe('Playhead at middle (0.25s)', 3000);
|
await pauseAndDescribe('Playhead at middle (0.25s) - halfway between frame 0 and frame 12', 300);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: Is the BLUE rectangle shape somewhere between the two versions?\n' +
|
'VERIFY: Is the BLUE rectangle shape somewhere between the two versions?\n' +
|
||||||
'It should be partially morphed (shape tween interpolation)\n\n' +
|
'It should be partially morphed (shape tween interpolation)\n' +
|
||||||
|
'Halfway between the original rectangle and the curved version\n\n' +
|
||||||
'Click OK if yes, Cancel if no'
|
'Click OK if yes, Cancel if no'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -223,9 +240,13 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('TEST 3: Test dragging unselected shape edge', async () => {
|
it('TEST 3: Test dragging unselected shape edge', async () => {
|
||||||
|
await logStep('Resetting playhead to time 0');
|
||||||
|
await setPlayheadTime(0);
|
||||||
|
await pauseAndDescribe('Playhead reset to time 0', 100);
|
||||||
|
|
||||||
await logStep('Drawing a GREEN rectangle at (200, 250) WITHOUT selecting it');
|
await logStep('Drawing a GREEN rectangle at (200, 250) WITHOUT selecting it');
|
||||||
await drawRectangle(200, 250, 100, 100, true, '#00ff00');
|
await drawRectangle(200, 250, 100, 100, true, '#00ff00');
|
||||||
await pauseAndDescribe('GREEN rectangle drawn (not selected)', 2000);
|
await pauseAndDescribe('GREEN rectangle drawn (not selected)', 100);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: GREEN rectangle should be visible but NOT selected\n' +
|
'VERIFY: GREEN rectangle should be visible but NOT selected\n' +
|
||||||
|
|
@ -233,9 +254,13 @@ describe('MANUAL: Timeline Animation', () => {
|
||||||
'Click OK if yes, Cancel if no'
|
'Click OK if yes, Cancel if no'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await logStep('Switching to select tool');
|
||||||
|
await selectTool('select');
|
||||||
|
await pauseAndDescribe('Select tool activated', 100);
|
||||||
|
|
||||||
await logStep('Dragging from the right edge (x=300) of GREEN rectangle to extend it');
|
await logStep('Dragging from the right edge (x=300) of GREEN rectangle to extend it');
|
||||||
await dragCanvas(300, 300, 350, 300);
|
await dragCanvas(300, 300, 350, 300);
|
||||||
await pauseAndDescribe('Dragged the right edge of GREEN rectangle', 3000);
|
await pauseAndDescribe('Dragged the right edge of GREEN rectangle', 200);
|
||||||
|
|
||||||
await verifyManually(
|
await verifyManually(
|
||||||
'VERIFY: What happened to the GREEN rectangle?\n\n' +
|
'VERIFY: What happened to the GREEN rectangle?\n\n' +
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,9 @@ describe('Shape Drawing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should draw large rectangles', async () => {
|
it('should draw large rectangles', async () => {
|
||||||
// Draw a large rectangle
|
// Draw a large rectangle (canvas is ~350px tall, so keep within bounds)
|
||||||
await drawRectangle(50, 300, 400, 200);
|
await drawRectangle(50, 50, 400, 250);
|
||||||
await assertShapeExists(250, 400, 'Large rectangle should exist at center');
|
await assertShapeExists(250, 175, 'Large rectangle should exist at center');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import {
|
||||||
getPixelColor
|
getPixelColor
|
||||||
} from '../helpers/canvas.js';
|
} from '../helpers/canvas.js';
|
||||||
import { assertShapeExists } from '../helpers/assertions.js';
|
import { assertShapeExists } from '../helpers/assertions.js';
|
||||||
|
import { verifyManually, logStep } from '../helpers/manual.js';
|
||||||
|
|
||||||
describe('Timeline Animation', () => {
|
describe('Timeline Animation', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
@ -44,10 +45,19 @@ describe('Timeline Animation', () => {
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await logStep('About to drag selected shape - dragging selected shapes does not move them yet');
|
||||||
|
|
||||||
// Shape is selected, so dragging from its center will move it
|
// Shape is selected, so dragging from its center will move it
|
||||||
await dragCanvas(150, 150, 250, 150);
|
await dragCanvas(150, 150, 250, 150);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually(
|
||||||
|
'VERIFY: Did the shape move to x=250?\n' +
|
||||||
|
'Expected: Shape at x=250\n' +
|
||||||
|
'Note: Dragging selected shapes is not implemented yet\n\n' +
|
||||||
|
'Click OK if at x=250, Cancel if not'
|
||||||
|
);
|
||||||
|
|
||||||
// At frame 10, shape should be at the new position (moved 100px to the right)
|
// At frame 10, shape should be at the new position (moved 100px to the right)
|
||||||
await assertShapeExists(250, 150, 'Shape should be at new position at frame 10');
|
await assertShapeExists(250, 150, 'Shape should be at new position at frame 10');
|
||||||
|
|
||||||
|
|
@ -55,6 +65,11 @@ describe('Timeline Animation', () => {
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await verifyManually(
|
||||||
|
'VERIFY: Did the shape return to original position (x=150)?\n\n' +
|
||||||
|
'Click OK if yes, Cancel if no'
|
||||||
|
);
|
||||||
|
|
||||||
// Shape should be at original position
|
// Shape should be at original position
|
||||||
await assertShapeExists(150, 150, 'Shape should be at original position at frame 1');
|
await assertShapeExists(150, 150, 'Shape should be at original position at frame 1');
|
||||||
|
|
||||||
|
|
@ -62,6 +77,11 @@ describe('Timeline Animation', () => {
|
||||||
await setPlayheadTime(0.166);
|
await setPlayheadTime(0.166);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await verifyManually(
|
||||||
|
'VERIFY: Is the shape interpolated at x=200 (halfway)?\n\n' +
|
||||||
|
'Click OK if yes, Cancel if no'
|
||||||
|
);
|
||||||
|
|
||||||
// Shape should be interpolated between the two positions
|
// Shape should be interpolated between the two positions
|
||||||
// At frame 5 (halfway), shape should be around x=200 (halfway between 150 and 250)
|
// At frame 5 (halfway), shape should be around x=200 (halfway between 150 and 250)
|
||||||
await assertShapeExists(200, 150, 'Shape should be interpolated at frame 5');
|
await assertShapeExists(200, 150, 'Shape should be interpolated at frame 5');
|
||||||
|
|
@ -91,74 +111,85 @@ describe('Timeline Animation', () => {
|
||||||
|
|
||||||
it('should handle multiple keyframes on the same shape', async () => {
|
it('should handle multiple keyframes on the same shape', async () => {
|
||||||
// Draw a shape
|
// Draw a shape
|
||||||
await drawRectangle(100, 300, 80, 80);
|
await drawRectangle(100, 100, 80, 80);
|
||||||
|
|
||||||
// Select it
|
// Select it
|
||||||
await selectMultipleShapes([{ x: 140, y: 340 }]);
|
await selectMultipleShapes([{ x: 140, y: 140 }]);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
// Keyframe 1: time 0 (original position at x=140, y=340)
|
// Keyframe 1: time 0 (original position at x=140, y=140)
|
||||||
|
|
||||||
// Keyframe 2: time 0.333 (move right)
|
// Keyframe 2: time 0.333 (move right)
|
||||||
await setPlayheadTime(0.333);
|
await setPlayheadTime(0.333);
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await logStep('Dragging selected shape (not implemented yet)');
|
||||||
// Shape should still be selected, drag to move
|
// Shape should still be selected, drag to move
|
||||||
await dragCanvas(140, 340, 200, 340);
|
await dragCanvas(140, 140, 200, 140);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
// Keyframe 3: time 0.666 (move down but stay within canvas)
|
await verifyManually('VERIFY: Did shape move to x=200? (probably not)\nClick OK if at x=200, Cancel if not');
|
||||||
|
|
||||||
|
// Keyframe 3: time 0.666 (move down)
|
||||||
await setPlayheadTime(0.666);
|
await setPlayheadTime(0.666);
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
// Drag to move down (y=380 instead of 400 to stay in canvas)
|
// Drag to move down
|
||||||
await dragCanvas(200, 340, 200, 380);
|
await dragCanvas(200, 140, 200, 180);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: Did shape move to y=180?\nClick OK if yes, Cancel if no');
|
||||||
|
|
||||||
// Verify positions at each keyframe
|
// Verify positions at each keyframe
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(140, 340, 'Shape at keyframe 1 (x=140, y=340)');
|
await verifyManually('VERIFY: Shape at original position (x=140, y=140)?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(140, 140, 'Shape at keyframe 1 (x=140, y=140)');
|
||||||
|
|
||||||
await setPlayheadTime(0.333);
|
await setPlayheadTime(0.333);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(200, 340, 'Shape at keyframe 2 (x=200, y=340)');
|
await verifyManually('VERIFY: Shape at x=200, y=140?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(200, 140, 'Shape at keyframe 2 (x=200, y=140)');
|
||||||
|
|
||||||
await setPlayheadTime(0.666);
|
await setPlayheadTime(0.666);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(200, 380, 'Shape at keyframe 3 (x=200, y=380)');
|
await verifyManually('VERIFY: Shape at x=200, y=180?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(200, 180, 'Shape at keyframe 3 (x=200, y=180)');
|
||||||
|
|
||||||
// Check interpolation between keyframe 1 and 2 (at t=0.166, halfway)
|
// Check interpolation between keyframe 1 and 2 (at t=0.166, halfway)
|
||||||
await setPlayheadTime(0.166);
|
await setPlayheadTime(0.166);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(170, 340, 'Shape interpolated between kf1 and kf2');
|
await verifyManually('VERIFY: Shape interpolated at x=170, y=140?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(170, 140, 'Shape interpolated between kf1 and kf2');
|
||||||
|
|
||||||
// Check interpolation between keyframe 2 and 3 (at t=0.5, halfway)
|
// Check interpolation between keyframe 2 and 3 (at t=0.5, halfway)
|
||||||
await setPlayheadTime(0.5);
|
await setPlayheadTime(0.5);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(200, 360, 'Shape interpolated between kf2 and kf3');
|
await verifyManually('VERIFY: Shape interpolated at x=200, y=160?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(200, 160, 'Shape interpolated between kf2 and kf3');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Group/Object Animation', () => {
|
describe('Group/Object Animation', () => {
|
||||||
it('should animate group position across keyframes', async () => {
|
it('should animate group position across keyframes', async () => {
|
||||||
// Create a group with two shapes
|
// Create a group with two shapes
|
||||||
await drawRectangle(300, 300, 60, 60);
|
await drawRectangle(300, 100, 60, 60);
|
||||||
await drawRectangle(380, 300, 60, 60);
|
await drawRectangle(380, 100, 60, 60);
|
||||||
|
|
||||||
await selectMultipleShapes([
|
await selectMultipleShapes([
|
||||||
{ x: 330, y: 330 },
|
{ x: 330, y: 130 },
|
||||||
{ x: 410, y: 330 }
|
{ x: 410, y: 130 }
|
||||||
]);
|
]);
|
||||||
await useKeyboardShortcut('g', true);
|
await useKeyboardShortcut('g', true);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
// Verify both shapes exist at frame 1
|
// Verify both shapes exist at frame 1
|
||||||
await assertShapeExists(330, 330, 'First shape at frame 1');
|
await assertShapeExists(330, 130, 'First shape at frame 1');
|
||||||
await assertShapeExists(410, 330, 'Second shape at frame 1');
|
await assertShapeExists(410, 130, 'Second shape at frame 1');
|
||||||
|
|
||||||
// Select the group by dragging a selection box over it
|
// Select the group by dragging a selection box over it
|
||||||
await selectMultipleShapes([{ x: 370, y: 330 }]);
|
await selectMultipleShapes([{ x: 370, y: 130 }]);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
// Move to frame 10 and add keyframe
|
// Move to frame 10 and add keyframe
|
||||||
|
|
@ -166,30 +197,37 @@ describe('Timeline Animation', () => {
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await logStep('Dragging group down');
|
||||||
// Group is selected, so dragging will move it
|
// Group is selected, so dragging will move it
|
||||||
// Drag from center of group down (but keep it within canvas bounds)
|
// Drag from center of group down
|
||||||
await dragCanvas(370, 330, 370, 380);
|
await dragCanvas(370, 130, 370, 200);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
// At frame 10, group should be at new position (moved 50px down)
|
await verifyManually('VERIFY: Did the group move down to y=200?\nClick OK if yes, Cancel if no');
|
||||||
await assertShapeExists(330, 380, 'First shape at new position at frame 10');
|
|
||||||
await assertShapeExists(410, 380, 'Second shape at new position at frame 10');
|
// At frame 10, group should be at new position (moved down)
|
||||||
|
await assertShapeExists(330, 200, 'First shape at new position at frame 10');
|
||||||
|
await assertShapeExists(410, 200, 'Second shape at new position at frame 10');
|
||||||
|
|
||||||
// Go to frame 1
|
// Go to frame 1
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: Did group return to original position (y=130)?\nClick OK if yes, Cancel if no');
|
||||||
|
|
||||||
// Group should be at original position
|
// Group should be at original position
|
||||||
await assertShapeExists(330, 330, 'First shape at original position at frame 1');
|
await assertShapeExists(330, 130, 'First shape at original position at frame 1');
|
||||||
await assertShapeExists(410, 330, 'Second shape at original position at frame 1');
|
await assertShapeExists(410, 130, 'Second shape at original position at frame 1');
|
||||||
|
|
||||||
// Go to frame 5 (middle, t=0.166)
|
// Go to frame 5 (middle, t=0.166)
|
||||||
await setPlayheadTime(0.166);
|
await setPlayheadTime(0.166);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
// Group should be interpolated (halfway between y=330 and y=380, so y=355)
|
await verifyManually('VERIFY: Is group interpolated at y=165 (halfway)?\nClick OK if yes, Cancel if no');
|
||||||
await assertShapeExists(330, 355, 'First shape interpolated at frame 5');
|
|
||||||
await assertShapeExists(410, 355, 'Second shape interpolated at frame 5');
|
// Group should be interpolated (halfway between y=130 and y=200, so y=165)
|
||||||
|
await assertShapeExists(330, 165, 'First shape interpolated at frame 5');
|
||||||
|
await assertShapeExists(410, 165, 'Second shape interpolated at frame 5');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should maintain relative positions of shapes within animated group', async () => {
|
it('should maintain relative positions of shapes within animated group', async () => {
|
||||||
|
|
@ -233,41 +271,47 @@ describe('Timeline Animation', () => {
|
||||||
describe('Interpolation', () => {
|
describe('Interpolation', () => {
|
||||||
it('should smoothly interpolate between keyframes', async () => {
|
it('should smoothly interpolate between keyframes', async () => {
|
||||||
// Draw a simple shape
|
// Draw a simple shape
|
||||||
await drawRectangle(500, 100, 50, 50);
|
await drawRectangle(100, 100, 50, 50);
|
||||||
|
|
||||||
// Select it
|
// Select it
|
||||||
await selectMultipleShapes([{ x: 525, y: 125 }]);
|
await selectMultipleShapes([{ x: 125, y: 125 }]);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
// Keyframe at start (x=525)
|
// Keyframe at start (x=125)
|
||||||
await setPlayheadTime(0);
|
await setPlayheadTime(0);
|
||||||
await browser.pause(100);
|
await browser.pause(100);
|
||||||
|
|
||||||
// Keyframe at end (1 second = frame 30, move to x=725)
|
// Keyframe at end (1 second = frame 30, move to x=325)
|
||||||
await setPlayheadTime(1.0);
|
await setPlayheadTime(1.0);
|
||||||
await addKeyframe();
|
await addKeyframe();
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
|
|
||||||
await dragCanvas(525, 125, 725, 125);
|
await logStep('Dragging shape (selected shapes cannot be dragged yet)');
|
||||||
|
await dragCanvas(125, 125, 325, 125);
|
||||||
await browser.pause(300);
|
await browser.pause(300);
|
||||||
|
|
||||||
|
await verifyManually('VERIFY: Did shape move to x=325? (probably not)\nClick OK if at x=325, Cancel if not');
|
||||||
|
|
||||||
// Check multiple intermediate frames for smooth interpolation
|
// Check multiple intermediate frames for smooth interpolation
|
||||||
// Total movement: 200px over 1 second
|
// Total movement: 200px over 1 second
|
||||||
|
|
||||||
// At 25% (0.25s), x should be 525 + 50 = 575
|
// At 25% (0.25s), x should be 125 + 50 = 175
|
||||||
await setPlayheadTime(0.25);
|
await setPlayheadTime(0.25);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(575, 125, 'Shape at 25% interpolation');
|
await verifyManually('VERIFY: Shape at x=175 (25% interpolation)?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(175, 125, 'Shape at 25% interpolation');
|
||||||
|
|
||||||
// At 50% (0.5s), x should be 525 + 100 = 625
|
// At 50% (0.5s), x should be 125 + 100 = 225
|
||||||
await setPlayheadTime(0.5);
|
await setPlayheadTime(0.5);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(625, 125, 'Shape at 50% interpolation');
|
await verifyManually('VERIFY: Shape at x=225 (50% interpolation)?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(225, 125, 'Shape at 50% interpolation');
|
||||||
|
|
||||||
// At 75% (0.75s), x should be 525 + 150 = 675
|
// At 75% (0.75s), x should be 125 + 150 = 275
|
||||||
await setPlayheadTime(0.75);
|
await setPlayheadTime(0.75);
|
||||||
await browser.pause(200);
|
await browser.pause(200);
|
||||||
await assertShapeExists(675, 125, 'Shape at 75% interpolation');
|
await verifyManually('VERIFY: Shape at x=275 (75% interpolation)?\nClick OK if yes, Cancel if no');
|
||||||
|
await assertShapeExists(275, 125, 'Shape at 75% interpolation');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue