🐛 Add test of fixes in the plugins api suite

This commit is contained in:
alonso.torres 2026-07-01 11:43:24 +02:00 committed by Alonso Torres
parent 1c9ab691e6
commit f1426cb3bb
5 changed files with 125 additions and 4 deletions

View File

@ -4,9 +4,9 @@ import type { CommentThread, Page } from '@penpot/plugin-types';
import type { TestContext } from '../framework/types';
// Comments.
// Comment threads are created on the current page. Both thread removal APIs are
// currently broken (see the dedicated red tests), so cleanup is best-effort to
// keep the other assertions meaningful.
// Comment threads are created on the current page. Thread/comment removal is
// asynchronous (it resolves once the backend delete RPC completes), so callers
// must await it; cleanup is best-effort and swallows errors.
function page(ctx: TestContext): Page {
const p = ctx.penpot.currentPage;
@ -124,7 +124,7 @@ describe.skipIfMocked('Comments', () => {
x: 8,
y: 8,
});
thread.remove();
await thread.remove();
const threads = await p.findCommentThreads();
expect(threads.every((t) => t.seqNumber !== thread.seqNumber)).toBe(true);
});

View File

@ -83,6 +83,21 @@ describe('Interactions', () => {
expect(interaction.action.type).toBe('open-overlay');
});
// position is optional; when omitted the overlay defaults to 'center'.
test('open-overlay without a position defaults to center', (ctx) => {
const overlay = board(ctx);
const r = rect(ctx);
const interaction = r.addInteraction('click', {
type: 'open-overlay',
destination: overlay,
});
expect(interaction.action.type).toBe('open-overlay');
if (interaction.action.type === 'open-overlay') {
expect(interaction.action.destination.id).toBe(overlay.id);
expect(interaction.action.position).toBe('center');
}
});
test('toggle-overlay interaction round-trips', (ctx) => {
const overlay = board(ctx);
const r = rect(ctx);
@ -116,6 +131,23 @@ describe('Interactions', () => {
}
});
// animation is optional on close-overlay; omitting it closes with no transition.
test('close-overlay without an animation round-trips', (ctx) => {
const overlay = board(ctx);
const r = rect(ctx);
const interaction = r.addInteraction('click', {
type: 'close-overlay',
destination: overlay,
});
expect(interaction.action.type).toBe('close-overlay');
if (interaction.action.type === 'close-overlay') {
expect(
interaction.action.destination && interaction.action.destination.id,
).toBe(overlay.id);
expect(interaction.action.animation).toBeUndefined();
}
});
test('previous-screen interaction round-trips', (ctx) => {
const r = rect(ctx);
const interaction = r.addInteraction('click', { type: 'previous-screen' });
@ -134,6 +166,19 @@ describe('Interactions', () => {
expect(interaction.delay).toBeCloseTo(1000, 0);
});
// A zero delay is a valid value (fires immediately), not an error.
test('after-delay accepts a zero delay', (ctx) => {
const dest = board(ctx);
const r = rect(ctx);
const interaction = r.addInteraction(
'after-delay',
{ type: 'navigate-to', destination: dest },
0,
);
expect(interaction.trigger).toBe('after-delay');
expect(interaction.delay).toBeCloseTo(0, 0);
});
test('mouse-leave trigger is recorded', (ctx) => {
// click / mouse-enter / after-delay are covered above; mouse-leave is the
// remaining trigger.
@ -167,6 +212,20 @@ describe('Interactions', () => {
expect(interaction.action.type).toBe('previous-screen');
});
// The delay setter accepts zero (fires immediately) as a valid value.
test('delay setter accepts a zero value', (ctx) => {
const dest = board(ctx);
const r = rect(ctx);
const interaction = r.addInteraction(
'after-delay',
{ type: 'navigate-to', destination: dest },
1000,
);
interaction.delay = 0;
expect(interaction.delay).toBeCloseTo(0, 0);
});
describe('Animations', () => {
test('dissolve animation round-trips', (ctx) => {
const dest = board(ctx);

View File

@ -65,6 +65,23 @@ describe('Layout', () => {
expect(flex.leftPadding).toBeCloseTo(4, 0);
});
// Gap and padding setters accept fractional numbers, not just integers.
test('gaps and padding accept fractional values', (ctx) => {
const flex = board(ctx).addFlexLayout();
flex.rowGap = 5.5;
flex.columnGap = 10.25;
flex.topPadding = 1.5;
flex.rightPadding = 2.25;
flex.bottomPadding = 3.75;
flex.leftPadding = 4.5;
expect(flex.rowGap).toBeCloseTo(5.5, 2);
expect(flex.columnGap).toBeCloseTo(10.25, 2);
expect(flex.topPadding).toBeCloseTo(1.5, 2);
expect(flex.rightPadding).toBeCloseTo(2.25, 2);
expect(flex.bottomPadding).toBeCloseTo(3.75, 2);
expect(flex.leftPadding).toBeCloseTo(4.5, 2);
});
test('sizing round-trips', (ctx) => {
const flex = board(ctx).addFlexLayout();
flex.horizontalSizing = 'fix';
@ -176,6 +193,23 @@ describe('Layout', () => {
expect(grid.columnGap).toBeCloseTo(9, 0);
});
// Gap and padding setters accept fractional numbers, not just integers.
test('gaps and padding accept fractional values', (ctx) => {
const grid = board(ctx).addGridLayout();
grid.rowGap = 7.5;
grid.columnGap = 9.25;
grid.topPadding = 1.5;
grid.rightPadding = 2.75;
grid.bottomPadding = 3.25;
grid.leftPadding = 4.5;
expect(grid.rowGap).toBeCloseTo(7.5, 2);
expect(grid.columnGap).toBeCloseTo(9.25, 2);
expect(grid.topPadding).toBeCloseTo(1.5, 2);
expect(grid.rightPadding).toBeCloseTo(2.75, 2);
expect(grid.bottomPadding).toBeCloseTo(3.25, 2);
expect(grid.leftPadding).toBeCloseTo(4.5, 2);
});
// Index boundaries — invalid indices must be rejected.
test('addRowAtIndex with a negative index throws', (ctx) => {
const grid = board(ctx).addGridLayout();

View File

@ -237,6 +237,21 @@ describe('Shapes', () => {
expect(r.borderRadiusBottomRight).toBeCloseTo(3, 0);
expect(r.borderRadiusBottomLeft).toBeCloseTo(4, 0);
});
// Border radius setters accept fractional numbers, not just integers.
test('border radius accepts fractional values', (ctx) => {
const r = rect(ctx);
r.borderRadius = 4.5;
expect(r.borderRadius).toBeCloseTo(4.5, 2);
r.borderRadiusTopLeft = 1.25;
r.borderRadiusTopRight = 2.5;
r.borderRadiusBottomRight = 3.75;
r.borderRadiusBottomLeft = 0.5;
expect(r.borderRadiusTopLeft).toBeCloseTo(1.25, 2);
expect(r.borderRadiusTopRight).toBeCloseTo(2.5, 2);
expect(r.borderRadiusBottomRight).toBeCloseTo(3.75, 2);
expect(r.borderRadiusBottomLeft).toBeCloseTo(0.5, 2);
});
});
describe('Ordering', () => {

View File

@ -148,6 +148,19 @@ describe('Tokens', () => {
theme.removeSet(set);
});
// addSet/removeSet also accept a token set id (string), not just a TokenSet.
test('addSet and removeSet accept a set id', async (ctx) => {
const cat = catalog(ctx);
const theme = cat.addTheme({ group: '', name: unique('theme') });
const set = cat.addSet({ name: unique('set'), active: false });
theme.addSet(set.id);
await sleep(300);
expect(theme.activeSets.length).toBeGreaterThan(0);
theme.removeSet(set.id);
await sleep(300);
expect(theme.activeSets.length).toBe(0);
});
test('duplicate and remove a theme', (ctx) => {
const theme = catalog(ctx).addTheme({ group: '', name: unique('theme') });
const dup = theme.duplicate();