Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,37 @@
// The drag preview's `getOffset` decides where the pointer sits on the
// preview, and Pragmatic only hands it to the real `setCustomNativeDragPreview`
// — nothing observable from the outside. So this file mocks that module and
// reads the options back, which the sibling engine spec cannot do: it renders
// previews for real. Separate file rather than a mock added there, because the
// suite runs with `isolate: false` and shares one module registry.
// reads the options back. It stays a separate file from the sibling engine
// spec because that one renders previews for real, and one file cannot both
// stub and exercise the same module.

import { vi } from 'vitest';
import { NativeDragSimulation } from 'core-common/drag-and-drop/testing/native-drag-simulation';
import { createSortableRoot } from './sortable-lists-engine';
import type { createSortableRoot as createSortableRootFn } from './sortable-lists-engine';
Comment thread
myabc marked this conversation as resolved.

const { previewCalls } = vi.hoisted(() => ({
previewCalls: [] as {
getOffset?:(args:{ container:HTMLElement }) => { x:number; y:number };
}[],
}));
// `doMock` is not hoisted, so this initialises before the factory below runs
// and a plain const does the job `vi.hoisted()` used to.
const previewCalls:{
getOffset?:(args:{ container:HTMLElement }) => { x:number; y:number };
}[] = [];

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
setCustomNativeDragPreview: (options:{
getOffset?:(args:{ container:HTMLElement }) => { x:number; y:number };
}) => {
previewCalls.push(options);
},
}));

let createSortableRoot:typeof createSortableRootFn;

describe('createSortableRoot drag preview offset', () => {
let cleanupFns:(() => void)[] = [];

beforeAll(async () => {
({ createSortableRoot } = await import('./sortable-lists-engine'));
});

beforeEach(() => { previewCalls.length = 0; });

afterEach(() => {
Expand Down
34 changes: 20 additions & 14 deletions frontend/src/common/drag-and-drop/sortable-lists-engine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ import {
centerOf,
towardsEdgeOf,
} from 'core-common/drag-and-drop/testing/native-drag-simulation';
import {
createSortableRoot,
type SortableDropIntent,
type SortableDropTransaction,
type SortableSource,
import type {
createSortableRoot as createSortableRootFn,
SortableDropIntent,
SortableDropTransaction,
SortableSource,
} from './sortable-lists-engine';
Comment thread
myabc marked this conversation as resolved.

const { autoScrollRegistrations } = vi.hoisted(() => ({
autoScrollRegistrations: [] as {
element:Element;
getAllowedAxis:() => string;
cleanup:() => void;
cleaned:boolean;
}[],
}));
// `doMock` is not hoisted, so this initialises before the factory below runs
// and a plain const does the job `vi.hoisted()` used to.
const autoScrollRegistrations:{
element:Element;
getAllowedAxis:() => string;
cleanup:() => void;
cleaned:boolean;
}[] = [];

vi.mock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
autoScrollForElements: (args:{ element:Element; getAllowedAxis:() => string }) => {
const entry = {
element: args.element,
Expand All @@ -62,6 +62,8 @@ vi.mock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
},
}));

let createSortableRoot:typeof createSortableRootFn;

const liveRegistrations = () => autoScrollRegistrations.filter((r) => !r.cleaned);

function buildList(items:string[]):{ root:HTMLElement; rows:HTMLElement[] } {
Expand Down Expand Up @@ -145,6 +147,10 @@ function buildCardGrid(items:string[], columns:number):{ root:HTMLElement; cards
describe('createSortableRoot', () => {
let cleanupFns:(() => void)[] = [];

beforeAll(async () => {
({ createSortableRoot } = await import('./sortable-lists-engine'));
});

beforeEach(() => { autoScrollRegistrations.length = 0; });

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,32 @@
// See COPYRIGHT and LICENSE files for more details.
//++

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
// vi.doMock is not hoisted above imports, unlike vi.mock, so the subject
// below is imported dynamically further down, after these calls run.
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
draggable: vi.fn(() => vi.fn()),
dropTargetForElements: vi.fn(() => vi.fn()),
monitorForElements: vi.fn(() => vi.fn()),
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
autoScrollForElements: vi.fn(() => vi.fn()),
}));

// This spec mounts the real item controller, which pulls in these modules.
// Tests share one module registry (the runner does not isolate spec files),
// so importing the real versions here would leak into the item controller
// spec and break its spies. Mock them to keep the shared cache inert.
vi.mock('@atlaskit/pragmatic-drag-and-drop/combine', () => ({
// This spec mounts the real item controller, which pulls in these three
// modules. Stub them so its Pragmatic side effects stay inert; nothing
// here reads them back.
vi.doMock('@atlaskit/pragmatic-drag-and-drop/combine', () => ({
combine: vi.fn((...cleanups:(() => void)[]) => vi.fn(() => {
cleanups.forEach((cleanup) => cleanup());
})),
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop/prevent-unhandled', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/prevent-unhandled', () => ({
preventUnhandled: { start: vi.fn(), stop: vi.fn() },
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
setCustomNativeDragPreview: vi.fn(),
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,28 @@
// See COPYRIGHT and LICENSE files for more details.
//++

vi.mock('@atlaskit/pragmatic-drag-and-drop/combine', () => ({
// vi.doMock is not hoisted above imports, unlike vi.mock, so the subject
// below is imported dynamically further down, after these calls run.
vi.doMock('@atlaskit/pragmatic-drag-and-drop/combine', () => ({
combine: vi.fn((...cleanups:(() => void)[]) => vi.fn(() => {
cleanups.forEach((cleanup) => cleanup());
})),
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
draggable: vi.fn(() => vi.fn()),
dropTargetForElements: vi.fn(() => vi.fn()),
monitorForElements: vi.fn(() => vi.fn()),
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop/prevent-unhandled', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/prevent-unhandled', () => ({
preventUnhandled: {
start: vi.fn(),
stop: vi.fn(),
},
}));

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview', () => ({
setCustomNativeDragPreview: vi.fn(),
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
// See COPYRIGHT and LICENSE files for more details.
//++

vi.mock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
// vi.doMock is not hoisted above imports, unlike vi.mock, so the subject
// below is imported dynamically further down, after these calls run.
vi.doMock('@atlaskit/pragmatic-drag-and-drop/element/adapter', () => ({
draggable: vi.fn(() => vi.fn()),
dropTargetForElements: vi.fn(() => vi.fn()),
monitorForElements: vi.fn(() => vi.fn()),
Expand Down Expand Up @@ -113,7 +115,7 @@
}

function dropTargetOptionsFor(element:HTMLElement) {
return vi.mocked(dropTargetForElements).mock.calls.find(([options]) => options.element === element)?.[0];

Check failure on line 118 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > exposes the configured list-only drop position

TypeError: Cannot read properties of undefined (reading 'calls') ❯ dropTargetOptionsFor src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:118:49 ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:213:11 ❯ fulfilled chunk-WDQAD3YQ.js:111:24

Check failure on line 118 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > defaults its list-only drop position to end

TypeError: Cannot read properties of undefined (reading 'calls') ❯ dropTargetOptionsFor src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:118:49 ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:206:11 ❯ fulfilled chunk-WDQAD3YQ.js:111:24

Check failure on line 118 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > falls back to the list element as the rows container when there is no child <ul>

TypeError: Cannot read properties of undefined (reading 'calls') ❯ dropTargetOptionsFor src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:118:49 ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:199:11 ❯ fulfilled chunk-WDQAD3YQ.js:111:24

Check failure on line 118 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > resolves the child <ul> as the rows container on the payload

TypeError: Cannot read properties of undefined (reading 'calls') ❯ dropTargetOptionsFor src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:118:49 ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:192:11 ❯ fulfilled chunk-WDQAD3YQ.js:111:24

Check failure on line 118 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > exposes its list payload through getData

TypeError: Cannot read properties of undefined (reading 'calls') ❯ dropTargetOptionsFor src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:118:49 ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:178:11 ❯ fulfilled chunk-WDQAD3YQ.js:111:24
}

function source(
Expand All @@ -134,7 +136,7 @@
it('registers itself as a drop target', async () => {
const { list } = await connectedListFor();

expect(dropTargetForElements).toHaveBeenCalledWith(expect.objectContaining({ element: list }));

Check failure on line 139 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > registers itself as a drop target

TypeError: [Function dropTargetForConsumers] is not a spy or a call to a spy! ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:139:34 ❯ fulfilled chunk-WDQAD3YQ.js:111:24
});

it('drops the previous registration and registers again on reregister', async () => {
Expand All @@ -142,7 +144,7 @@

controller.reregister();

expect(vi.mocked(dropTargetForElements).mock.calls.filter(([options]) => options.element === list)).toHaveLength(2);

Check failure on line 147 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > drops the previous registration and registers again on reregister

TypeError: Cannot read properties of undefined (reading 'calls') ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:147:49 ❯ fulfilled chunk-WDQAD3YQ.js:111:24
});

it('stays inert on reregister for a display-only list', async () => {
Expand All @@ -150,13 +152,13 @@

controller.reregister();

expect(vi.mocked(dropTargetForElements).mock.calls.filter(([options]) => options.element === list)).toHaveLength(0);

Check failure on line 155 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > stays inert on reregister for a display-only list

TypeError: Cannot read properties of undefined (reading 'calls') ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:155:49 ❯ fulfilled chunk-WDQAD3YQ.js:111:24
});

it('does not register without an accepted type', async () => {
const { list } = await connectedListFor({ acceptedType: null, root: null });

expect(dropTargetForElements).not.toHaveBeenCalledWith(expect.objectContaining({ element: list }));

Check failure on line 161 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > does not register without an accepted type

TypeError: [Function dropTargetForConsumers] is not a spy or a call to a spy! ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:161:38 ❯ fulfilled chunk-WDQAD3YQ.js:111:24
});

it('warns and does not register when it accepts a type but has no list type', async () => {
Expand All @@ -165,7 +167,7 @@
const { list } = await connectedListFor({ type: null, acceptedType: 'work_package', root: null });

expect(warn).toHaveBeenCalledWith(expect.stringContaining('type'), expect.anything());
expect(dropTargetForElements).not.toHaveBeenCalledWith(expect.objectContaining({ element: list }));

Check failure on line 170 in frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts

View workflow job for this annotation

GitHub Actions / Units (chromium)

[OpenProject (chromium)] src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts > Sortable lists list controller > warns and does not register when it accepts a type but has no list type

TypeError: [Function dropTargetForConsumers] is not a spy or a call to a spy! ❯ src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts:170:38 ❯ fulfilled chunk-WDQAD3YQ.js:111:24

warn.mockRestore();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { setupStimulusTest, type StimulusTestContext } from 'core-stimulus/test-
import type ScrollableControllerType from './scrollable.controller';
import type { sortableItemData as sortableItemDataFn, SortableListsRoot } from './drag-and-drop';

vi.mock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
vi.doMock('@atlaskit/pragmatic-drag-and-drop-auto-scroll/element', () => ({
autoScrollForElements: vi.fn(() => vi.fn()),
}));

Expand Down
Loading