implement license saga tests

This commit is contained in:
David Lechner
2021-01-17 14:59:03 -06:00
parent deac69fdab
commit 8c1e9a8273
5 changed files with 103 additions and 4 deletions
+13 -1
View File
@@ -6,6 +6,7 @@ import { LicenseInfo, LicenseList } from '../reducers/license';
export enum LicenseActionType {
DidFetchList = 'license.action.didFetchList',
DidFailToFetchList = 'license.action.didFailToFetchList',
Select = 'license.action.select',
}
@@ -17,6 +18,14 @@ export function didFetchList(list: LicenseList): LicenseDidFetchListAction {
return { type: LicenseActionType.DidFetchList, list };
}
export type LicenseDidFailToFetchListAction = Action<LicenseActionType.DidFailToFetchList> & {
reason: Response;
};
export function didFailToFetchList(reason: Response): LicenseDidFailToFetchListAction {
return { type: LicenseActionType.DidFailToFetchList, reason };
}
export type LicenseSelectAction = Action<LicenseActionType.Select> & {
info: LicenseInfo;
};
@@ -25,4 +34,7 @@ export function select(info: LicenseInfo): LicenseSelectAction {
return { type: LicenseActionType.Select, info };
}
export type LicenseAction = LicenseDidFetchListAction | LicenseSelectAction;
export type LicenseAction =
| LicenseDidFetchListAction
| LicenseDidFailToFetchListAction
| LicenseSelectAction;
+15
View File
@@ -7,6 +7,7 @@ import {
didFailToConnect as bleDidFailToConnect,
} from '../actions/ble';
import { didFailToWrite } from '../actions/ble-uart';
import { didFailToFetchList } from '../actions/license';
import {
BootloaderConnectionFailureReason,
didError,
@@ -68,3 +69,17 @@ test('bootloaderDidError', async () => {
await saga.end();
});
test('licenseDidFailToFetch', async () => {
const saga = new AsyncSaga(errorLog);
console.error = jest.fn();
saga.put(
didFailToFetchList(
new Response(undefined, { status: 404, statusText: 'not found' }),
),
);
expect(console.error).toHaveBeenCalledTimes(1);
await saga.end();
});
+6
View File
@@ -8,6 +8,7 @@ import {
BleDeviceFailToConnectReasonType,
} from '../actions/ble';
import { BleUartActionType, BleUartDidFailToWriteAction } from '../actions/ble-uart';
import { LicenseActionType, LicenseDidFailToFetchListAction } from '../actions/license';
import {
BootloaderConnectionActionType,
BootloaderConnectionDidErrorAction,
@@ -39,6 +40,10 @@ function bootloaderDidError(action: BootloaderConnectionDidErrorAction): void {
console.error(action.err);
}
function licenseDidFailToFetch(action: LicenseDidFailToFetchListAction): void {
console.error(`Failed to fetch licenses: ${action.reason.statusText}`);
}
export default function* (): Generator {
yield takeEvery(BleDeviceActionType.DidFailToConnect, bleDeviceDidFailToConnect);
yield takeEvery(BleUartActionType.DidFailToWrite, bleDataDidFailToWrite);
@@ -47,4 +52,5 @@ export default function* (): Generator {
bootloaderDidFailToConnect,
);
yield takeEvery(BootloaderConnectionActionType.DidError, bootloaderDidError);
yield takeEvery(LicenseActionType.DidFailToFetchList, licenseDidFailToFetch);
}
+67
View File
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
// Tests for license sagas.
import { AsyncSaga, delay } from '../../test';
import { openLicenseDialog } from '../actions/app';
import { didFailToFetchList, didFetchList } from '../actions/license';
import { LicenseList, LicenseState } from '../reducers/license';
import license from './license';
afterAll(() => {
jest.restoreAllMocks();
});
describe('fetchLicenses', () => {
test('first call', async () => {
const testLicenseList: LicenseList = [];
const saga = new AsyncSaga(license);
jest.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify(testLicenseList)),
);
// initially, license list starts as null, so fetch is called to get
// the list
saga.setState({ license: { list: null } as LicenseState });
saga.put(openLicenseDialog());
const action = await saga.take();
expect(action).toEqual(didFetchList(testLicenseList));
await saga.end();
});
test('second call', async () => {
const testLicenseList: LicenseList = [];
const saga = new AsyncSaga(license);
jest.spyOn(globalThis, 'fetch').mockRejectedValue(
'fetch () should not have been called',
);
// after we have the list, we don't fetch it again since it will
// always be the same list
saga.setState({ license: { list: testLicenseList } as LicenseState });
saga.put(openLicenseDialog());
// have to yield to be sure fetch call would have taken place on error
await delay(0);
await saga.end();
});
test('failed fetch', async () => {
const failResponse = new Response(undefined, { status: 404 });
const saga = new AsyncSaga(license);
jest.spyOn(globalThis, 'fetch').mockResolvedValue(failResponse);
saga.setState({ license: { list: null } as LicenseState });
saga.put(openLicenseDialog());
const action = await saga.take();
expect(action).toEqual(didFailToFetchList(failResponse));
await saga.end();
});
});
+2 -3
View File
@@ -3,7 +3,7 @@
import { call, put, select, takeEvery } from 'redux-saga/effects';
import { AppActionType } from '../actions/app';
import { didFetchList } from '../actions/license';
import { didFailToFetchList, didFetchList } from '../actions/license';
import { RootState } from '../reducers';
import { LicenseList } from '../reducers/license';
@@ -19,8 +19,7 @@ function* fetchLicenses(): Generator {
const response = (yield call(() => fetch('static/oss-licenses.json'))) as Response;
if (!response.ok || response.body === null) {
// TODO: dispatch an action to notify user
console.error('failed to fetch oss-licenses.json', response.statusText);
yield put(didFailToFetchList(response));
return;
}