Skip to content

Add Settings page with options #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/src/__mocks__/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// export this mock function so the executions can be checked in tests
export const debugMock = jest.fn();

const debug = jest.fn(() => {
// return the exported mock above each time `debug()` is called
return debugMock;
});

export default debug;
17 changes: 11 additions & 6 deletions app/src/__stories__/ChannelBalance.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { lndListChannelsOne } from 'util/tests/sampleData';
import { Store, useStore } from 'store';
import { Channel } from 'store/models';
import ChannelBalance from 'components/loop/ChannelBalance';

Expand All @@ -9,27 +10,31 @@ export default {
parameters: { centered: true },
};

const getChannel = (ratio: number) => {
const channel = new Channel(lndListChannelsOne.channelsList[0]);
const getChannel = (store: Store, ratio: number) => {
const channel = new Channel(store, lndListChannelsOne.channelsList[0]);
channel.localBalance = channel.capacity * ratio;
channel.remoteBalance = channel.capacity * (1 - ratio);
return channel;
};

export const Good = () => {
return <ChannelBalance channel={getChannel(0.59)} />;
const store = useStore();
return <ChannelBalance channel={getChannel(store, 0.59)} />;
};

export const Warn = () => {
return <ChannelBalance channel={getChannel(0.28)} />;
const store = useStore();
return <ChannelBalance channel={getChannel(store, 0.28)} />;
};

export const Bad = () => {
return <ChannelBalance channel={getChannel(0.91)} />;
const store = useStore();
return <ChannelBalance channel={getChannel(store, 0.91)} />;
};

export const Inactive = () => {
const channel = getChannel(0.45);
const store = useStore();
const channel = getChannel(store, 0.45);
channel.active = false;
return <ChannelBalance channel={channel} />;
};
40 changes: 32 additions & 8 deletions app/src/__stories__/ChannelList.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { observable } from 'mobx';
import { observable, ObservableMap, values } from 'mobx';
import { BalanceMode } from 'util/constants';
import { useStore } from 'store';
import { Channel } from 'store/models';
import ChannelList from 'components/loop/ChannelList';
Expand All @@ -10,22 +11,45 @@ export default {
parameters: { contained: true },
};

const channelSubset = (channels: ObservableMap<string, Channel>) => {
const few = values(channels)
.slice(0, 20)
.reduce((result, c) => {
result[c.chanId] = c;
return result;
}, {} as Record<string, Channel>);
return observable.map(few);
};

export const NoChannels = () => {
const store = useStore();
store.channelStore.channels = observable.map();
return <ChannelList />;
};

export const FewChannels = () => {
const store = useStore();
const channels = store.channelStore.sortedChannels.slice(0, 10).reduce((result, c) => {
result[c.chanId] = c;
return result;
}, {} as Record<string, Channel>);
store.channelStore.channels = observable.map(channels);
export const ReceiveMode = () => {
const { channelStore, settingsStore } = useStore();
settingsStore.balanceMode = BalanceMode.receive;
channelStore.channels = channelSubset(channelStore.channels);
return <ChannelList />;
};

export const SendMode = () => {
const { channelStore, settingsStore } = useStore();
settingsStore.balanceMode = BalanceMode.send;
channelStore.channels = channelSubset(channelStore.channels);
return <ChannelList />;
};

export const RoutingMode = () => {
const { channelStore, settingsStore } = useStore();
settingsStore.balanceMode = BalanceMode.routing;
channelStore.channels = channelSubset(channelStore.channels);
return <ChannelList />;
};

export const ManyChannels = () => {
const { settingsStore } = useStore();
settingsStore.balanceMode = BalanceMode.routing;
return <ChannelList />;
};
24 changes: 14 additions & 10 deletions app/src/__stories__/ChannelRow.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,53 +32,57 @@ const renderStory = (
};

export const Good = () => {
const channel = new Channel(lndListChannels.channelsList[0]);
return renderStory(channel, { ratio: 0.59 });
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[0]);
return renderStory(channel, { ratio: 0.3 });
};

export const Warn = () => {
const channel = new Channel(lndListChannels.channelsList[1]);
return renderStory(channel, { ratio: 0.28 });
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[1]);
return renderStory(channel, { ratio: 0.5 });
};

export const Bad = () => {
const channel = new Channel(lndListChannels.channelsList[2]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[2]);
return renderStory(channel, { ratio: 0.91 });
};

export const Inactive = () => {
const channel = new Channel(lndListChannels.channelsList[3]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[3]);
channel.active = false;
return renderStory(channel);
};

export const Editable = () => {
const channel = new Channel(lndListChannels.channelsList[4]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[4]);
store.buildSwapStore.startSwap();
return renderStory(channel);
};

export const Selected = () => {
const channel = new Channel(lndListChannels.channelsList[5]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[5]);
store.buildSwapStore.startSwap();
store.buildSwapStore.toggleSelectedChannel(channel.chanId);
return renderStory(channel);
};

export const Disabled = () => {
const channel = new Channel(lndListChannels.channelsList[6]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[6]);
store.buildSwapStore.startSwap();
store.buildSwapStore.toggleSelectedChannel(channel.chanId);
store.buildSwapStore.setDirection(SwapDirection.OUT);
return renderStory(channel);
};

export const Dimmed = () => {
const channel = new Channel(lndListChannels.channelsList[6]);
const store = useStore();
const channel = new Channel(store, lndListChannels.channelsList[6]);
store.buildSwapStore.startSwap();
store.buildSwapStore.setDirection(SwapDirection.OUT);
return renderStory(channel);
Expand Down
21 changes: 21 additions & 0 deletions app/src/__stories__/SettingsPage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { Layout } from 'components/layout';
import SettingsPage from 'components/settings/SettingsPage';

export default {
title: 'Pages/Settings',
component: SettingsPage,
parameters: { contained: true },
};

export const Default = () => {
return <SettingsPage />;
};

export const InsideLayout = () => {
return (
<Layout>
<SettingsPage />
</Layout>
);
};
17 changes: 15 additions & 2 deletions app/src/__stories__/StoryWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { CSSProperties, useMemo } from 'react';
import { observer } from 'mobx-react-lite';
import { BalanceMode, Unit } from 'util/constants';
import { sampleApiResponses } from 'util/tests/sampleData';
import { createStore, StoreProvider } from 'store';
import { PersistentSettings } from 'store/stores/settingsStore';
import { Background } from 'components/common/base';
import { ThemeProvider } from 'components/theme';

Expand All @@ -16,8 +18,19 @@ const grpc = {
},
};

// Create a store that pulls data from the mock GRPC for stories
const createStoryStore = () => createStore(grpc);
// fake the AppStorage dependency so that settings aren't shared across stories
class StoryAppStorage {
set = () => undefined;
get = (): PersistentSettings => ({
sidebarVisible: true,
unit: Unit.sats,
balanceMode: BalanceMode.receive,
});
}

// Create a store that pulls data from the mock GRPC and doesn't use
// the real localStorage to save settings
const createStoryStore = () => createStore(grpc, new StoryAppStorage());

/**
* This component is used to wrap every story. It provides the app theme
Expand Down
2 changes: 1 addition & 1 deletion app/src/__stories__/Tile.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ export const WithArrowIcon = () => (
);

export const InboundLiquidity = () => (
<Tile title="Inbound Liquidity" text="123,456,789 SAT" />
<Tile title="Inbound Liquidity" text="123,456,789 sats" />
);
7 changes: 7 additions & 0 deletions app/src/__tests__/Pages.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ describe('Pages Component', () => {
expect(getByText('Loop History')).toBeInTheDocument();
expect(store.uiStore.page).toBe('history');
});

it('should display the Settings page', () => {
const { getByText, store } = render();
store.uiStore.goToSettings();
expect(getByText('Settings')).toBeInTheDocument();
expect(store.uiStore.page).toBe('settings');
});
});
2 changes: 1 addition & 1 deletion app/src/__tests__/components/NodeStatus.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('NodeStatus component', () => {
it('should display the lightning balance', () => {
const { getByText, store } = render();
store.nodeStore.wallet = { channelBalance: 123, walletBalance: 0 };
expect(getByText('123 SAT')).toBeInTheDocument();
expect(getByText('123 sats')).toBeInTheDocument();
});

it('should display the bitcoin balance', () => {
Expand Down
8 changes: 4 additions & 4 deletions app/src/__tests__/components/common/Range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('Range component', () => {
it('should display slider and value by default', () => {
const { getByText, getByLabelText } = render();
expect(getByLabelText('range-slider')).toBeInTheDocument();
expect(getByText('50 SAT')).toBeInTheDocument();
expect(getByText('50 sats')).toBeInTheDocument();
});

it('should accept custom props', () => {
Expand All @@ -41,9 +41,9 @@ describe('Range component', () => {
showRadios: true,
});
expect(getByLabelText('range-slider')).toBeInTheDocument();
expect(getByText('5,000 SAT')).toBeInTheDocument();
expect(getByText('2,500 SAT')).toBeInTheDocument();
expect(getByText('7,500 SAT')).toBeInTheDocument();
expect(getByText('5,000 sats')).toBeInTheDocument();
expect(getByText('2,500 sats')).toBeInTheDocument();
expect(getByText('7,500 sats')).toBeInTheDocument();
expect(getByText('Min')).toHaveAttribute('aria-checked', 'false');
expect(getByText('Max')).toHaveAttribute('aria-checked', 'false');
});
Expand Down
11 changes: 11 additions & 0 deletions app/src/__tests__/components/layout/Layout.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,15 @@ describe('Layout component', () => {
expect(store.uiStore.page).toBe('loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
});

it('should navigate back to the Settings page', () => {
const { getByText, store } = render();
expect(store.uiStore.page).toBe('loop');
fireEvent.click(getByText('Settings'));
expect(store.uiStore.page).toBe('settings');
expect(getByText('Settings').parentElement).toHaveClass('active');
fireEvent.click(getByText('Lightning Loop'));
expect(store.uiStore.page).toBe('loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
});
});
30 changes: 13 additions & 17 deletions app/src/__tests__/components/loop/ChannelBalance.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import React from 'react';
import { renderWithProviders } from 'util/tests';
import { lndListChannelsOne } from 'util/tests/sampleData';
import { createStore } from 'store';
import { Channel } from 'store/models';
import ChannelBalance from 'components/loop/ChannelBalance';

describe('ChannelBalance component', () => {
const channel: Channel = new Channel(lndListChannelsOne.channelsList[0]);
let channel: Channel;

const bgColor = (el: any) => window.getComputedStyle(el).backgroundColor;
const width = (el: any) => window.getComputedStyle(el).width;

const shiftBalance = (channel: Channel, ratio: number) => {
const render = (ratio: number, active = true) => {
const store = createStore();
channel = new Channel(store, lndListChannelsOne.channelsList[0]);
channel.localBalance = channel.capacity * ratio;
channel.remoteBalance = channel.capacity * (1 - ratio);
};
channel.active = active;

const render = () => {
const result = renderWithProviders(<ChannelBalance channel={channel} />);
const result = renderWithProviders(<ChannelBalance channel={channel} />, store);
const el = result.container.children[0];
return {
...result,
Expand All @@ -27,37 +29,31 @@ describe('ChannelBalance component', () => {
};

it('should display a good balance', () => {
shiftBalance(channel, 0.55);
channel.localBalance = channel.capacity * 0.55;
const { el, remote, local } = render();
const { el, remote, local } = render(0.25);
expect(el.children.length).toBe(3);
expect(width(local)).toBe('55%');
expect(width(local)).toBe('25%');
expect(bgColor(local)).toBe('rgb(70, 232, 14)');
expect(bgColor(remote)).toBe('rgb(70, 232, 14)');
});

it('should display a warning balance', () => {
shiftBalance(channel, 0.72);
const { el, remote, local } = render();
const { el, remote, local } = render(0.52);
expect(el.children.length).toBe(3);
expect(width(local)).toBe('72%');
expect(width(local)).toBe('52%');
expect(bgColor(local)).toBe('rgb(246, 107, 28)');
expect(bgColor(remote)).toBe('rgb(246, 107, 28)');
});

it('should display a bad balance', () => {
shiftBalance(channel, 0.93);
const { el, remote, local } = render();
const { el, remote, local } = render(0.93);
expect(el.children.length).toBe(3);
expect(width(local)).toBe('93%');
expect(bgColor(local)).toBe('rgb(245, 64, 110)');
expect(bgColor(remote)).toBe('rgb(245, 64, 110)');
});

it('should display an inactive channel', () => {
channel.active = false;
shiftBalance(channel, 0.55);
const { el, remote, local } = render();
const { el, remote, local } = render(0.55, false);
expect(el.children.length).toBe(3);
expect(width(local)).toBe('55%');
expect(bgColor(local)).toBe('rgb(132, 138, 153)');
Expand Down
Loading