一些检查失败了
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
135 行
3.1 KiB
TypeScript
135 行
3.1 KiB
TypeScript
import AsyncActionQueue from './AsyncActionQueue';
|
|
import { runWithFakeTimers, withWarningSilenced } from './testing/test-utils';
|
|
|
|
describe('AsyncActionQueue', () => {
|
|
beforeEach(() => {
|
|
jest.useRealTimers();
|
|
});
|
|
|
|
test('should run a single task', async () => {
|
|
const queue = new AsyncActionQueue(0);
|
|
|
|
await expect(new Promise(resolve => {
|
|
queue.push(() => resolve('success'));
|
|
})).resolves.toBe('success');
|
|
|
|
await expect(new Promise(resolve => {
|
|
queue.push(() => resolve('task 2'));
|
|
})).resolves.toBe('task 2');
|
|
});
|
|
|
|
test('should merge all tasks by default', async () => {
|
|
const queue = new AsyncActionQueue(100);
|
|
jest.useFakeTimers();
|
|
|
|
const result = {
|
|
ranFirst: false,
|
|
ranSecond: false,
|
|
ranThird: false,
|
|
ranFourth: false,
|
|
};
|
|
queue.push(() => {
|
|
result.ranFirst = true;
|
|
});
|
|
queue.push(() => {
|
|
result.ranSecond = true;
|
|
});
|
|
queue.push(() => {
|
|
result.ranThird = true;
|
|
});
|
|
queue.push(() => {
|
|
result.ranFourth = true;
|
|
});
|
|
|
|
const processPromise = queue.processAllNow();
|
|
await jest.runAllTimersAsync();
|
|
await processPromise;
|
|
|
|
expect(result).toMatchObject({
|
|
ranFirst: false,
|
|
ranSecond: false,
|
|
ranThird: false,
|
|
ranFourth: true,
|
|
});
|
|
});
|
|
|
|
test('should reject processAllNow when a task fails', async () => {
|
|
const queue = new AsyncActionQueue(100);
|
|
jest.useFakeTimers();
|
|
const error = new Error('Task failed');
|
|
|
|
await withWarningSilenced(/Task failed/, async () => {
|
|
queue.push(async () => {
|
|
throw error;
|
|
});
|
|
|
|
const processPromise = queue.processAllNow();
|
|
const rejectionExpectation = expect(processPromise).rejects.toBe(error);
|
|
await jest.runAllTimersAsync();
|
|
await rejectionExpectation;
|
|
expect(queue.isEmpty).toBe(true);
|
|
}, { requireWarning: true });
|
|
});
|
|
|
|
test('should handle failures when queue processing is not awaited', async () => {
|
|
await runWithFakeTimers(() => withWarningSilenced(/Task failed/, async () => {
|
|
const queue = new AsyncActionQueue(100);
|
|
const failingAction = jest.fn(async () => {
|
|
throw new Error('Task failed');
|
|
});
|
|
queue.push(failingAction);
|
|
|
|
await jest.runAllTimersAsync();
|
|
expect(failingAction).toHaveBeenCalledTimes(1);
|
|
}, { requireWarning: true }));
|
|
});
|
|
|
|
test.each([
|
|
{
|
|
tasks: [
|
|
'a', 'b',
|
|
],
|
|
expectedToRun: [
|
|
'a', 'b',
|
|
],
|
|
},
|
|
{
|
|
tasks: [
|
|
'a', 'b', 'c',
|
|
],
|
|
expectedToRun: [
|
|
'a', 'b', 'c',
|
|
],
|
|
},
|
|
{
|
|
tasks: [
|
|
'group1', 'group1', 'group1', 'group2', 'group1', 'group1', 'group2', 'group2',
|
|
],
|
|
expectedToRun: [
|
|
'group1', 'group2', 'group1', 'group2',
|
|
],
|
|
},
|
|
])('should support customising how tasks are merged', async ({ tasks, expectedToRun }) => {
|
|
const queue = new AsyncActionQueue<string>(100);
|
|
|
|
// Determine which tasks can be merged based on their context
|
|
queue.setCanSkipTaskHandler((current, next) => {
|
|
return current.context === next.context;
|
|
});
|
|
jest.useFakeTimers();
|
|
|
|
const result: string[] = [];
|
|
for (const task of tasks) {
|
|
queue.push(() => {
|
|
result.push(task);
|
|
}, task);
|
|
}
|
|
|
|
const processPromise = queue.processAllNow();
|
|
await jest.runAllTimersAsync();
|
|
await processPromise;
|
|
|
|
expect(result).toMatchObject(expectedToRun);
|
|
});
|
|
});
|