Merge pull request #453 from pybricks/dlech

fix run button when hub disconnects during download
This commit is contained in:
David Lechner
2021-07-01 12:05:16 -05:00
committed by GitHub
3 changed files with 176 additions and 12 deletions
+12 -6
View File
@@ -53,9 +53,12 @@ it('should manage license dialog open/close', async () => {
userEvent.click(screen.getByText('Software Licenses'));
expect(
screen.getByText('Pybricks Code is built on open source software.', {
exact: false,
}),
screen.getByText(
`${process.env.REACT_APP_NAME} is built on open source software.`,
{
exact: false,
},
),
).toBeInTheDocument();
const licenseDialog = document.querySelector(
@@ -64,8 +67,11 @@ it('should manage license dialog open/close', async () => {
userEvent.click(getByLabelText(licenseDialog, 'Close'));
await waitForElementToBeRemoved(() =>
screen.queryByText('Pybricks Code is built on open source software.', {
exact: false,
}),
screen.queryByText(
`${process.env.REACT_APP_NAME} is built on open source software.`,
{
exact: false,
},
),
);
});
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
import { Action } from '../actions';
import { statusReportEvent } from '../ble-pybricks-service/actions';
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
import { didDisconnect } from '../ble/actions';
import {
didFailToFinishDownload,
didFinishDownload,
didProgressDownload,
didStartDownload,
} from './actions';
import reducers, { HubRuntimeState } from './reducers';
type State = ReturnType<typeof reducers>;
test('initial state', () => {
expect(reducers(undefined, {} as Action)).toMatchInlineSnapshot(`
Object {
"downloadProgress": null,
"runtime": "hub.runtime.disconnected",
}
`);
});
describe('runtime', () => {
test.each(Object.values(HubRuntimeState))('didDisconnect', (startingState) => {
// all states are overridden by disconnect
expect(
reducers({ runtime: startingState } as State, didDisconnect()).runtime,
).toBe(HubRuntimeState.Disconnected);
});
test('didStartDownload', () => {
// download ignored if disconnected
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
didStartDownload(),
).runtime,
).toBe(HubRuntimeState.Disconnected);
expect(
reducers({ runtime: HubRuntimeState.Idle } as State, didStartDownload())
.runtime,
).toBe(HubRuntimeState.Loading);
});
test('didProgressDownload', () => {
// download ignored if disconnected
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
didProgressDownload(0),
).runtime,
).toBe(HubRuntimeState.Disconnected);
// this shouldn't have any effect
expect(
reducers(
{ runtime: HubRuntimeState.Loading } as State,
didProgressDownload(0),
).runtime,
).toBe(HubRuntimeState.Loading);
});
test('didFinishDownload', () => {
// download ignored if disconnected
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
didFinishDownload(),
).runtime,
).toBe(HubRuntimeState.Disconnected);
// normal operation
expect(
reducers({ runtime: HubRuntimeState.Loading } as State, didFinishDownload())
.runtime,
).toBe(HubRuntimeState.Loaded);
});
test('didFinishDownload', () => {
// download ignored if disconnected
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
didFailToFinishDownload(),
).runtime,
).toBe(HubRuntimeState.Disconnected);
// normal operation for error path
expect(
reducers(
{ runtime: HubRuntimeState.Loading } as State,
didFailToFinishDownload(),
).runtime,
).toBe(HubRuntimeState.Idle);
});
test('statusReportEvent', () => {
// don't ever expect this to happen in practice since we can't receive
// updates while disconnected
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
statusReportEvent(statusToFlag(Status.UserProgramRunning)),
).runtime,
).toBe(HubRuntimeState.Disconnected);
// status update ignored while download not finished
expect(
reducers(
{ runtime: HubRuntimeState.Loading } as State,
statusReportEvent(statusToFlag(Status.UserProgramRunning)),
).runtime,
).toBe(HubRuntimeState.Loading);
// normal operation - user program started
expect(
reducers(
{ runtime: HubRuntimeState.Loaded } as State,
statusReportEvent(statusToFlag(Status.UserProgramRunning)),
).runtime,
).toBe(HubRuntimeState.Running);
// really short program run finished before receiving download finished
expect(
reducers({ runtime: HubRuntimeState.Loaded } as State, statusReportEvent(0))
.runtime,
).toBe(HubRuntimeState.Idle);
// normal operation - user program stopped
expect(
reducers(
{ runtime: HubRuntimeState.Running } as State,
statusReportEvent(0),
).runtime,
).toBe(HubRuntimeState.Idle);
});
});
+23 -6
View File
@@ -46,21 +46,38 @@ const runtime: Reducer<HubRuntimeState, Action> = (
case BleDeviceActionType.DidDisconnect:
return HubRuntimeState.Disconnected;
case HubActionType.DidStartDownload:
// disconnected overrides download
if (state === HubRuntimeState.Disconnected) {
return state;
}
return HubRuntimeState.Loading;
case HubActionType.DidFinishDownload:
// disconnected overrides download
if (state === HubRuntimeState.Disconnected) {
return state;
}
return HubRuntimeState.Loaded;
case HubActionType.DidFailToFinishDownload:
// disconnected overrides download
if (state === HubRuntimeState.Disconnected) {
return state;
}
return HubRuntimeState.Idle;
case BlePybricksServiceEventActionType.StatusReport:
// The loading state is determined solely by the IDE, so we can't
// let the hub status interfere with it.
if (state !== HubRuntimeState.Loading) {
if (action.statusFlags & statusToFlag(Status.UserProgramRunning)) {
return HubRuntimeState.Running;
}
return HubRuntimeState.Idle;
if (
state === HubRuntimeState.Disconnected ||
state === HubRuntimeState.Loading
) {
return state;
}
return state;
if (action.statusFlags & statusToFlag(Status.UserProgramRunning)) {
return HubRuntimeState.Running;
}
return HubRuntimeState.Idle;
default:
return state;
}