`,
})
@@ -804,10 +823,12 @@ describe('sortable-lists directive group behavior', () => {
@Component({
imports: [OpSortableListsDirective, OpSortableListsItemDirective],
template: `
-
- @for (id of ids(); track id) {
-
{{ id }}
- }
+
`,
})
diff --git a/frontend/src/app/shared/helpers/drag-and-drop/drag-and-drop.service.spec.ts b/frontend/src/app/shared/helpers/drag-and-drop/drag-and-drop.service.spec.ts
index 90732497014a..381b7e72e4ec 100644
--- a/frontend/src/app/shared/helpers/drag-and-drop/drag-and-drop.service.spec.ts
+++ b/frontend/src/app/shared/helpers/drag-and-drop/drag-and-drop.service.spec.ts
@@ -60,7 +60,10 @@ function buildRow(id:string, opts:{ handle?:boolean } = {}):HTMLElement {
function buildContainer(ids:string[], opts:{ handle?:boolean } = {}):{ container:HTMLElement; rows:HTMLElement[] } {
const container = document.createElement('div');
- container.style.cssText = 'width:200px;';
+ // `overflow-y` with no height keeps the container a scroll container for
+ // Pragmatic's computed-overflow check. This also computes overflow-x to
+ // `auto`, but rows are exactly 200px wide in a 200px container.
+ container.style.cssText = 'width:200px; overflow-y:auto;';
const rows = ids.map((id) => {
const row = buildRow(id, opts);
container.appendChild(row);
@@ -159,7 +162,7 @@ describe('DragAndDropService', () => {
describe('container append', () => {
it('reports a drop below the rows as a null-target append intent', async () => {
const { container, rows } = buildContainer(['a0', 'a1']);
- container.style.cssText = 'width:200px; padding-bottom:40px;';
+ container.style.cssText = 'width:200px; padding-bottom:40px; overflow-y:auto;';
const onMoved = vi.fn();
service.register(buildMember(container, { onMoved }));
diff --git a/frontend/src/common/drag-and-drop/sortable-lists-engine.preview.spec.ts b/frontend/src/common/drag-and-drop/sortable-lists-engine.preview.spec.ts
index 22ead4d7e03f..2654b58a332b 100644
--- a/frontend/src/common/drag-and-drop/sortable-lists-engine.preview.spec.ts
+++ b/frontend/src/common/drag-and-drop/sortable-lists-engine.preview.spec.ts
@@ -29,21 +29,21 @@
// 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';
-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 };
}) => {
@@ -51,9 +51,15 @@ vi.mock('@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-previe
},
}));
+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(() => {
@@ -64,6 +70,10 @@ describe('createSortableRoot drag preview offset', () => {
function setup():{ rows:HTMLElement[] } {
const root = document.createElement('div');
+ // The engine attaches auto-scroll to this element directly, with no
+ // ancestor walk, so the overflow has to sit here. This also computes
+ // overflow-x to auto; 600px rows just happen to fit the viewport.
+ root.style.cssText = 'overflow-y:auto;';
const rows = ['a', 'b'].map((id) => {
const row = document.createElement('div');
row.style.cssText = 'height:40px; width:600px;';
diff --git a/frontend/src/common/drag-and-drop/sortable-lists-engine.spec.ts b/frontend/src/common/drag-and-drop/sortable-lists-engine.spec.ts
index f515b3b28b43..ed0ddcf6e350 100644
--- a/frontend/src/common/drag-and-drop/sortable-lists-engine.spec.ts
+++ b/frontend/src/common/drag-and-drop/sortable-lists-engine.spec.ts
@@ -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';
-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,
@@ -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[] } {
@@ -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(() => {
diff --git a/frontend/src/stimulus/controllers/dynamic/sortable-lists.controller.spec.ts b/frontend/src/stimulus/controllers/dynamic/sortable-lists.controller.spec.ts
index 76c264e3aa49..2ae29b583f04 100644
--- a/frontend/src/stimulus/controllers/dynamic/sortable-lists.controller.spec.ts
+++ b/frontend/src/stimulus/controllers/dynamic/sortable-lists.controller.spec.ts
@@ -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(),
}));
diff --git a/frontend/src/stimulus/controllers/dynamic/sortable-lists/item.controller.spec.ts b/frontend/src/stimulus/controllers/dynamic/sortable-lists/item.controller.spec.ts
index 8bc94713becc..1d7b0832c14f 100644
--- a/frontend/src/stimulus/controllers/dynamic/sortable-lists/item.controller.spec.ts
+++ b/frontend/src/stimulus/controllers/dynamic/sortable-lists/item.controller.spec.ts
@@ -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(),
}));
diff --git a/frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts b/frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts
index 018b9a38d8f4..5a4fed5dcc2e 100644
--- a/frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts
+++ b/frontend/src/stimulus/controllers/dynamic/sortable-lists/list.controller.spec.ts
@@ -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()),
diff --git a/frontend/src/stimulus/controllers/dynamic/sortable-lists/scrollable.controller.spec.ts b/frontend/src/stimulus/controllers/dynamic/sortable-lists/scrollable.controller.spec.ts
index 09bc7bcb20d9..11645e71829e 100644
--- a/frontend/src/stimulus/controllers/dynamic/sortable-lists/scrollable.controller.spec.ts
+++ b/frontend/src/stimulus/controllers/dynamic/sortable-lists/scrollable.controller.spec.ts
@@ -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()),
}));