mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
This starts moving alerts to the same subsystem where they are relevant instead of putting everything in notifications. So far, only the explorer file in use error is handled like this.
116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
// SPDX-License-Identifier: MIT
|
|
// Copyright (c) 2022 The Pybricks Authors
|
|
|
|
import { IToastOptions, IToastProps, IToaster } from '@blueprintjs/core';
|
|
import { waitFor } from '@testing-library/dom';
|
|
import { AsyncSaga } from '../../test';
|
|
import { alertsDidShowAlert, alertsShowAlert } from './actions';
|
|
import alerts from './sagas';
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
class TestToaster implements IToaster {
|
|
private toasts = new Array<IToastOptions>();
|
|
|
|
public getToasts(): IToastOptions[] {
|
|
return this.toasts;
|
|
}
|
|
|
|
public show(props: IToastProps, key?: string): string {
|
|
if (!key) {
|
|
throw new Error('key is required!');
|
|
}
|
|
|
|
this.toasts.push({ key, ...props });
|
|
|
|
return key;
|
|
}
|
|
|
|
public dismiss(key: string): void {
|
|
const index = this.toasts.findIndex((t) => t.key === key);
|
|
|
|
if (index < 0) {
|
|
return;
|
|
}
|
|
|
|
const toast = this.toasts.at(index);
|
|
toast?.onDismiss?.(false);
|
|
|
|
this.toasts.splice(index, 1);
|
|
}
|
|
|
|
public clear(): void {
|
|
throw new Error('this method should never be called!');
|
|
}
|
|
}
|
|
|
|
describe('handleShowAlert', () => {
|
|
let toaster: TestToaster;
|
|
let saga: AsyncSaga;
|
|
|
|
beforeEach(async () => {
|
|
toaster = new TestToaster();
|
|
jest.spyOn(toaster, 'show');
|
|
jest.spyOn(toaster, 'dismiss');
|
|
saga = new AsyncSaga(alerts, { toaster });
|
|
});
|
|
|
|
it('should show toast', async () => {
|
|
saga.put(
|
|
alertsShowAlert('alerts', 'unexpectedError', {
|
|
error: { name: 'TestError', message: 'test error' },
|
|
}),
|
|
);
|
|
|
|
expect(toaster.dismiss).not.toHaveBeenCalled();
|
|
expect(toaster.show).toHaveBeenCalled();
|
|
|
|
toaster.dismiss(toaster.getToasts().at(-1)?.key ?? '');
|
|
|
|
await expect(saga.take()).resolves.toEqual(
|
|
alertsDidShowAlert('alerts', 'unexpectedError', 'dismiss'),
|
|
);
|
|
});
|
|
|
|
it('should show close and re-open toast with same key', async () => {
|
|
// request to show the same alert twice
|
|
saga.put(
|
|
alertsShowAlert('alerts', 'unexpectedError', {
|
|
error: { name: 'TestError', message: 'test error' },
|
|
}),
|
|
);
|
|
saga.put(
|
|
alertsShowAlert('alerts', 'unexpectedError', {
|
|
error: { name: 'TestError', message: 'test error' },
|
|
}),
|
|
);
|
|
|
|
// at this point, show has only been called once to display the first alert
|
|
expect(toaster.show).toHaveBeenCalled();
|
|
// and then dismiss was called to close it
|
|
expect(toaster.dismiss).toHaveBeenCalled();
|
|
|
|
// which should result in an action
|
|
await expect(saga.take()).resolves.toEqual(
|
|
alertsDidShowAlert('alerts', 'unexpectedError', 'dismiss'),
|
|
);
|
|
|
|
// then after a delay, the second alert is shown
|
|
await waitFor(() => expect(toaster.show).toHaveBeenCalledTimes(2));
|
|
|
|
// then we dismiss it manually, like normal
|
|
toaster.dismiss(toaster.getToasts().at(-1)?.key ?? '');
|
|
|
|
// and get the action for the second dismiss
|
|
await expect(saga.take()).resolves.toEqual(
|
|
alertsDidShowAlert('alerts', 'unexpectedError', 'dismiss'),
|
|
);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await saga.end();
|
|
});
|
|
});
|