Files
wekan/client/lib/tests/subtaskViewTarget.tests.js
Lauri Ojansivu 7c0ae509ac Fix #2769 #1992 #2292 #2494 #1853 #1554 #2306 #1437.
- #2769: refresh drag geometry when the DOM changes mid-drag - cards no
  longer drop into the wrong swimlane while someone adds a card.
- #1992: board import restores all five card date fields (and creator)
  with fallbacks; receivedAt/endAt were never imported at all.
- #2292: archiving a swimlane archives its cards (mirroring lists);
  restore brings back exactly the cards archived with it.
- #2494: client noCache card lookup returned a Promise since the
  Meteor 3 port - multi-select board moves wrote sort: NaN everywhere.
- #1853: subtask "View it" falls back to the subtask's boardId when the
  deposit board is not loaded, instead of silently doing nothing.
- #1554: restore the reactive dependency lost in 7673c77c5 so cards
  added after board render accept sidebar label/member drops.
- #2306: "filter to selection" and every bulk action are board-scoped;
  foreign-board cards can no longer be silently archived.
- #1437: new POST /users/logout API endpoint revokes the presented
  resume token, or all tokens with {"all": true}.

All with positive+negative regression tests (see tests/*.test.cjs).

Closes #1389: already fixed - the standalone pencil edit button
(0cc63b810) plus the wrapped viewer (bf2b3b40c) guarantee an edit target
even when a full-width link fills the description.

Thanks to hever, Cactusbone, Vermeille, Vanclief, Miffe, IcedQuinn,
ppouliot, GhassenRjab and xet7.
2026-07-17 03:34:23 +03:00

94 lines
3.6 KiB
JavaScript

/* eslint-env mocha */
import { expect } from 'chai';
import { subtaskNavTarget } from '/client/components/cards/subtaskViewHelpers';
/**
* Unit tests for the subtask "View it" navigation target.
*
* Regression #3743: "[UX Bug] Subtask 'View it' button opens the parent card
* instead of the subtask". The js-view-subtask handler must navigate to the
* SUBTASK card's own board/slug/id, never to the parent (current) card's.
*
* subtaskNavTarget(subtask) returns the FlowRouter 'card' route params derived
* exclusively from the subtask. These tests build a subtask whose own ids are
* deliberately different from a "parent" card's ids and assert the result
* carries the subtask's ids, not the parent's.
*/
// A parent card whose ids must NOT leak into the navigation target.
const parentCard = {
_id: 'parentCardId',
boardId: 'parentBoardId',
};
// Build a subtask stub that mimics the Card model surface the helper uses:
// board() (with _id + slug), getRealId(), swimlaneId and listId.
function makeSubtask({ withRealId = true } = {}) {
const subtaskBoard = { _id: 'subtaskBoardId', slug: 'subtask-board-slug' };
return {
_id: 'subtaskCardId',
parentId: parentCard._id,
boardId: subtaskBoard._id,
swimlaneId: 'subtaskSwimlaneId',
listId: 'subtaskListId',
board() {
return subtaskBoard;
},
getRealId() {
return withRealId ? 'subtaskRealId' : undefined;
},
};
}
describe('subtaskNavTarget (#3743)', function() {
it('targets the subtask\'s own board, not the parent card\'s board', function() {
const target = subtaskNavTarget(makeSubtask());
expect(target.boardId).to.equal('subtaskBoardId');
expect(target.boardId).to.not.equal(parentCard.boardId);
});
it('targets the subtask card itself, not the parent card', function() {
const target = subtaskNavTarget(makeSubtask());
// Uses the subtask's real id and never the parent card id.
expect(target.cardId).to.equal('subtaskRealId');
expect(target.cardId).to.not.equal(parentCard._id);
});
it('uses the subtask board slug, swimlane and list', function() {
const target = subtaskNavTarget(makeSubtask());
expect(target.slug).to.equal('subtask-board-slug');
expect(target.swimlaneId).to.equal('subtaskSwimlaneId');
expect(target.listId).to.equal('subtaskListId');
});
it('falls back to subtask._id when getRealId yields nothing', function() {
const target = subtaskNavTarget(makeSubtask({ withRealId: false }));
expect(target.cardId).to.equal('subtaskCardId');
expect(target.cardId).to.not.equal(parentCard._id);
});
it('falls back to the subtask boardId when its board is not loaded (#1853/#4762)', function() {
// The deposit/target board is often ANOTHER board that is not in
// minimongo while the parent board is open; navigation must still work
// (the card route loads the board), it must not throw or no-op.
const subtask = makeSubtask();
subtask.board = () => undefined;
const target = subtaskNavTarget(subtask);
expect(target.boardId).to.equal('subtaskBoardId');
expect(target.slug).to.equal('board');
expect(target.cardId).to.equal('subtaskRealId');
});
it('returns undefined for a missing subtask', function() {
expect(subtaskNavTarget(undefined)).to.equal(undefined);
expect(subtaskNavTarget(null)).to.equal(undefined);
});
it('returns undefined for a broken subtask with no board reference at all', function() {
const subtask = makeSubtask();
subtask.board = () => undefined;
subtask.boardId = undefined;
expect(subtaskNavTarget(subtask)).to.equal(undefined);
});
});