文件
mynode/packages/lib/services/commands/stateToWhenClauseContext.test.ts
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

266 行
7.8 KiB
TypeScript

import { defaultState } from '../../reducer';
import SyncTargetRegistry from '../../SyncTargetRegistry';
import { FolderEntity, NoteEntity } from '../database/types';
import { getTrashFolderId } from '../trash';
import stateToWhenClauseContext from './stateToWhenClauseContext';
let mockNoteLockEnabled = true;
jest.mock('../noteLock/isNoteLockEnabled', () => () => mockNoteLockEnabled);
interface StateOptions {
folders: FolderEntity[];
notes: NoteEntity[];
selectedFolderId: string;
selectedFolderIds: string[];
selectedNoteIds: string[];
notesParentType: string;
noteLockSessionUnlocked: boolean;
activeNoteIsUndecryptable: boolean;
}
const buildState = (options: Partial<StateOptions>) => {
return {
...defaultState,
selectedFolderIds: options.selectedFolderId ? [options.selectedFolderId] : [],
...options,
};
};
describe('stateToWhenClauseContext', () => {
it.each([
{
label: 'the note lock session is locked',
noteLockSessionUnlocked: false,
activeNoteIsUndecryptable: false,
isLocked: 1,
expected: true,
},
{
label: 'the active note cannot be decrypted',
noteLockSessionUnlocked: true,
activeNoteIsUndecryptable: true,
isLocked: 1,
expected: true,
},
{
label: 'the locked note has been decrypted',
noteLockSessionUnlocked: true,
activeNoteIsUndecryptable: false,
isLocked: 1,
expected: false,
},
{
label: 'the active note is not locked',
noteLockSessionUnlocked: false,
activeNoteIsUndecryptable: true,
isLocked: 0,
expected: false,
},
{
label: 'the decrypted note is inside a share',
noteLockSessionUnlocked: true,
activeNoteIsUndecryptable: false,
isLocked: 1,
shareId: 'share-1',
expected: true,
},
])('should make the note read-only when $label', ({ noteLockSessionUnlocked, activeNoteIsUndecryptable, isLocked, shareId, expected }) => {
const applicationState = buildState({
selectedNoteIds: ['1'],
notes: [{ id: '1', is_locked: isLocked, share_id: shareId, deleted_time: 0 }],
noteLockSessionUnlocked,
activeNoteIsUndecryptable,
});
const resultingState = stateToWhenClauseContext(applicationState);
expect(resultingState.noteIsReadOnly).toBe(expected);
expect(resultingState.noteIsReadOnlyShare).toBe(false);
});
it('should make a locked note inside a share read-only with the note lock feature turned off', () => {
mockNoteLockEnabled = false;
try {
const applicationState = buildState({
selectedNoteIds: ['1'],
notes: [{ id: '1', is_locked: 1, share_id: 'share-1', deleted_time: 0 }],
noteLockSessionUnlocked: false,
});
expect(stateToWhenClauseContext(applicationState).noteIsReadOnly).toBe(true);
} finally {
mockNoteLockEnabled = true;
}
});
it('should be in trash if selected note has been deleted and selected folder is trash', async () => {
const applicationState = buildState({
selectedNoteIds: ['1'],
selectedFolderId: getTrashFolderId(),
notes: [
{ id: '1', deleted_time: 1722567036580 },
],
folders: [],
});
const resultingState = stateToWhenClauseContext(applicationState);
expect(resultingState.inTrash).toBe(true);
});
it('should NOT be in trash if selected note has not been deleted', async () => {
const applicationState = buildState({
selectedNoteIds: ['1'],
selectedFolderId: getTrashFolderId(),
notes: [
{ id: '1', deleted_time: 0 },
],
folders: [],
});
const resultingState = stateToWhenClauseContext(applicationState);
expect(resultingState.inTrash).toBe(false);
});
it('should NOT be in trash if selected folder is not trash', async () => {
const applicationState = buildState({
selectedNoteIds: ['1'],
selectedFolderId: 'any-other-folder',
notes: [
{ id: '1', deleted_time: 1722567036580 },
],
folders: [],
});
const resultingState = stateToWhenClauseContext(applicationState);
expect(resultingState.inTrash).toBe(false);
});
it('should be in trash if command folder is deleted', async () => {
const applicationState = buildState({
notes: [],
notesParentType: 'Folder',
folders: [
{ id: '1', deleted_time: 1722567036580, share_id: '', parent_id: '' },
],
});
const resultingState = stateToWhenClauseContext(applicationState, { commandFolderId: '1' });
expect(resultingState.inTrash).toBe(true);
});
it('should NOT be in trash if command folder is not deleted', async () => {
const applicationState = buildState({
notes: [],
folders: [
{ id: '1', deleted_time: 0, share_id: '', parent_id: '' },
],
});
const resultingState = stateToWhenClauseContext(applicationState, { commandFolderId: '1' });
expect(resultingState.inTrash).toBe(false);
});
it('should not be in trash if viewing all notes', async () => {
const applicationState = buildState({
selectedFolderId: 'folder',
notesParentType: 'SmartFolder',
});
const resultingState = stateToWhenClauseContext(applicationState);
expect(resultingState.inTrash).toBe(false);
});
it.each(SyncTargetRegistry.allIds().map(id => ({
id,
name: SyncTargetRegistry.idToName(id),
expected: SyncTargetRegistry.isJoplinServerOrCloud(id),
})))('should set joplinServerConnected to $expected when the sync target is $name', ({ id, expected }) => {
const getWhenClauseContext = (syncTarget: number) => {
const applicationState = {
...defaultState,
settings: {
'sync.target': syncTarget,
},
};
return stateToWhenClauseContext(applicationState);
};
const whenClauseContext = getWhenClauseContext(id);
expect(whenClauseContext.joplinServerConnected).toBe(expected);
});
it.each([
{
label: 'should be true when all target folders are deleted',
commandFolderIds: ['del1', 'del2'],
expectedDeletedState: true,
},
{
label: 'should be false when one or more target folders is not deleted',
commandFolderIds: ['del1', 'del2', '1'],
expectedDeletedState: false,
},
{
label: 'should default to the state of the selected items',
commandFolderIds: null,
expectedDeletedState: false,
},
])('should set foldersAreDeleted correctly: $label', ({ commandFolderIds, expectedDeletedState }) => {
const applicationState = buildState({
folders: [
{ id: '1', deleted_time: 0, share_id: '', parent_id: '' },
{ id: 'del1', deleted_time: 1, share_id: '', parent_id: '' },
{ id: 'del2', deleted_time: 1, share_id: '', parent_id: '' },
],
selectedFolderIds: ['1'],
selectedFolderId: '1',
notesParentType: 'Folder',
});
expect(
stateToWhenClauseContext(applicationState, { commandFolderIds }),
).toHaveProperty('foldersAreDeleted', expectedDeletedState);
});
it.each([
{
label: 'should be false when no folders exist (new profile)',
selectedFolderId: 'non-existent-folder',
folders: [],
expected: false,
},
{
label: 'should be false when selectedFolderId is null',
selectedFolderId: null,
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
expected: false,
},
{
label: 'should be false when selected folder has been deleted',
selectedFolderId: '1',
folders: [{ id: '1', deleted_time: 1000, share_id: '', parent_id: '' }],
expected: false,
},
{
label: 'should be true when selected folder exists and is not deleted',
selectedFolderId: '1',
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
expected: true,
},
{
label: 'should be false when selectedFolderId does not match any folder',
selectedFolderId: 'stale-id',
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
expected: false,
},
])('should set selectedFolderIsValid correctly: $label', ({ selectedFolderId, folders, expected }) => {
const applicationState = buildState({
selectedFolderId,
folders,
notes: [],
});
expect(
stateToWhenClauseContext(applicationState),
).toHaveProperty('selectedFolderIsValid', expected);
});
});