Skip to content
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