文件
mynode/packages/lib/services/rest/routes/revisions.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

78 行
3.0 KiB
TypeScript

import Api, { RequestMethod } from '../Api';
import Note from '../../../models/Note';
import Revision from '../../../models/Revision';
import Setting from '../../../models/Setting';
import BaseModel from '../../../BaseModel';
import { setupDatabaseAndSynchronizer, switchClient, noteLockCipherTextStandIn } from '../../../testing/test-utils';
import { RevisionEntity } from '../../database/types';
const createNoteAndRevision = async (isLocked: number) => {
// A JLD-prefixed body passes the save path untouched, standing in for real ciphertext.
const note = await Note.save({ title: 'note', body: isLocked ? noteLockCipherTextStandIn('body') : 'body', is_locked: isLocked });
const revision = await Revision.save({
item_type: BaseModel.TYPE_NOTE,
item_id: note.id,
item_updated_time: note.updated_time,
parent_id: '',
title_diff: '[]',
body_diff: '[]',
metadata_diff: '{"new":{},"deleted":[]}',
is_locked: isLocked,
});
return { note, revision };
};
describe('routes/revisions', () => {
beforeEach(async () => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
});
test('should block load and save of a locked revision', async () => {
Setting.setValue('featureFlag.noteLock', true);
const api = new Api();
const { revision } = await createNoteAndRevision(1);
await expect(api.route(RequestMethod.GET, `revisions/${revision.id}`)).rejects.toThrow('locked revision');
await expect(api.route(RequestMethod.PUT, `revisions/${revision.id}`, null, JSON.stringify({ title_diff: '[]' }))).rejects.toThrow('locked revision');
expect(await Revision.load(revision.id)).toBeTruthy();
});
test('should still allow deleting the revisions of a locked note', async () => {
Setting.setValue('featureFlag.noteLock', true);
const api = new Api();
const { revision } = await createNoteAndRevision(1);
await api.route(RequestMethod.DELETE, `revisions/${revision.id}`);
expect(await Revision.load(revision.id)).toBeFalsy();
});
test('should exclude the revisions of locked notes from the collection response', async () => {
Setting.setValue('featureFlag.noteLock', true);
const api = new Api();
await createNoteAndRevision(1);
const { revision: plainRevision } = await createNoteAndRevision(0);
const response = await api.route(RequestMethod.GET, 'revisions');
expect(response.items.map((r: RevisionEntity) => r.id)).toEqual([plainRevision.id]);
Setting.setValue('featureFlag.noteLock', false);
expect((await api.route(RequestMethod.GET, 'revisions')).items.length).toBe(2);
});
test.each([
{ label: 'the note is not locked', flagEnabled: true, isLocked: 0 },
{ label: 'note lock is disabled', flagEnabled: false, isLocked: 1 },
])('should allow revision access when $label', async ({ flagEnabled, isLocked }) => {
Setting.setValue('featureFlag.noteLock', flagEnabled);
const api = new Api();
const { revision } = await createNoteAndRevision(isLocked);
const response = await api.route(RequestMethod.GET, `revisions/${revision.id}`);
expect(response.id).toBe(revision.id);
});
});