From a2378e290cbce3bd2d42d5eb92bed2725265a9f2 Mon Sep 17 00:00:00 2001 From: vetalcore Date: Tue, 17 Dec 2024 16:56:34 +0200 Subject: [PATCH] fix(nami): [lw-11967] fix storybook in nami package (#1596) --- packages/nami/.storybook/index.scss | 49 ++++++++++++ packages/nami/.storybook/main.ts | 9 +++ packages/nami/.storybook/preview.tsx | 10 +++ packages/nami/.storybook/theme.scss | 38 +++++++++ .../nami/src/adapters/transactions.mock.ts | 4 +- .../ui/app/components/changePasswordModal.tsx | 2 +- .../nami/src/ui/app/pages/send.stories.tsx | 43 ++++++++++- packages/nami/src/ui/app/pages/send.tsx | 6 +- .../src/ui/app/pages/settings.stories.tsx | 48 +++++++----- packages/nami/src/ui/app/pages/settings.tsx | 2 +- .../nami/src/ui/app/pages/wallet.stories.tsx | 77 ++++++++++++++++--- 11 files changed, 243 insertions(+), 45 deletions(-) create mode 100644 packages/nami/.storybook/index.scss create mode 100644 packages/nami/.storybook/theme.scss diff --git a/packages/nami/.storybook/index.scss b/packages/nami/.storybook/index.scss new file mode 100644 index 0000000000..7f170b23ac --- /dev/null +++ b/packages/nami/.storybook/index.scss @@ -0,0 +1,49 @@ +@import './theme.scss'; + +:global(.ant-radio:hover .ant-radio-inner) { + border-color: var(--light-mode-dark-grey, var(--dark-mode-light-grey)) !important; + background: var(--color-white, var(--dark-mode-grey)); +} +:global(.ant-tooltip) { + color: var(--light-mode-dark-grey, var(--dark-mode-light-grey)) !important; + font-weight: 400 !important; + font-size: var(--bodySmall) !important; +} +:global(.ant-tooltip-inner) { + background-color: var(--dark-mode-mid-grey, #ffffff) !important; + border-radius: 11px !important; + color: var(--dark-mode-light-grey, --light-mode-dark-grey) !important; + padding: size_unit(1) size_unit(2) !important; +} +:global(.ant-tooltip-arrow-content) { + background-color: var(--dark-mode-mid-grey, #ffffff) !important; +} + +:global(.ant-tooltip-arrow-content:before) { + background: var(--dark-mode-mid-grey, #ffffff) !important; +} + +:global(.ant-modal-mask) { + background: var(--light-mode-black, var(--dark-mode-bg-black)) !important; + opacity: 0.9; +} + +:global(.ant-drawer.ant-drawer-open .ant-drawer-mask) { + animation: none; +} + +:global(.ant-drawer) { + transition: none; +} + +:global { + .ant-checkbox-checked .ant-checkbox-inner { + background-color: var(--primary-default) !important; + border-color: var(--primary-default) !important; + } +} + +body { + background-color: var(--bg-color-body, #ffffff) !important; + color: var(--text-color-primary, #3d3b39); +} diff --git a/packages/nami/.storybook/main.ts b/packages/nami/.storybook/main.ts index 58b3ecb8e2..e273958025 100644 --- a/packages/nami/.storybook/main.ts +++ b/packages/nami/.storybook/main.ts @@ -17,6 +17,15 @@ const config: StorybookConfig = { getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@chromatic-com/storybook'), + { + name: '@storybook/addon-styling', + options: { + sass: { + // Require your Sass preprocessor here + implementation: require('sass') + } + } + } ], framework: { name: getAbsolutePath('@storybook/react-webpack5'), diff --git a/packages/nami/.storybook/preview.tsx b/packages/nami/.storybook/preview.tsx index 2399d64bf6..68059ef4ad 100644 --- a/packages/nami/.storybook/preview.tsx +++ b/packages/nami/.storybook/preview.tsx @@ -2,6 +2,7 @@ import React from 'react'; import type { Preview } from '@storybook/react'; import '../src/ui/app/components/styles.css'; import 'focus-visible/dist/focus-visible'; +import { ThemeColorScheme, ThemeProvider, colorSchemaDecorator } from '@input-output-hk/lace-ui-toolkit'; import { ChakraProvider, extendTheme } from '@chakra-ui/react'; import { theme } from '../src/ui/theme'; @@ -12,6 +13,7 @@ import { NetworkConnectionStates, } from '../src/features/common-outside-handles-provider'; import { WalletType } from '@cardano-sdk/web-extension'; +import './index.scss'; const noop = (async () => {}) as any; const mock = {} as any; @@ -133,6 +135,14 @@ export const decorators = [ ), + (Story, args) => { + const { decorators: { theme } = {} } = args.parameters; + return ( + + + + ); + } ]; export default preview; diff --git a/packages/nami/.storybook/theme.scss b/packages/nami/.storybook/theme.scss new file mode 100644 index 0000000000..dff4cee0b2 --- /dev/null +++ b/packages/nami/.storybook/theme.scss @@ -0,0 +1,38 @@ +@import '../../common/src/ui/styles/abstracts/mixins'; +@import '../../common/src/ui/styles/themes/dark'; +@import '../../common/src/ui/styles/themes/light'; + +@mixin dark-theme { + /* + in case the theme provider is not being used, this media query allows us to use the theme set on the user system + */ + @media (prefers-color-scheme: dark) and (data-theme: dark) { + :root { + @include theme-custom-properties($dark-theme); + } + } + + html[data-theme='dark']:not(:has(div[data-theme='light'])), + div[data-theme='dark'] { + @include theme-custom-properties($dark-theme); + } +} + +@mixin light-theme { + /* + in case the theme provider is not being used, this media query allows us to use the theme set on the user system + */ + @media (prefers-color-scheme: light) and (data-theme: light) { + :root { + @include theme-custom-properties($light-theme); + } + } + + html[data-theme='light']:not(:has(div[data-theme='dark'])), + div[data-theme='light'] { + @include theme-custom-properties($light-theme); + } +} + +@include dark-theme; +@include light-theme; diff --git a/packages/nami/src/adapters/transactions.mock.ts b/packages/nami/src/adapters/transactions.mock.ts index 0bddcaf4cc..e965069271 100644 --- a/packages/nami/src/adapters/transactions.mock.ts +++ b/packages/nami/src/adapters/transactions.mock.ts @@ -6,6 +6,6 @@ import * as actualApi from './transactions'; export * from './transactions'; -export const useTxInfo: jest.Mock = fn(actualApi.useTxInfo).mockName( - 'useTxInfo', +export const useWalletTxs: jest.Mock = fn(actualApi.useWalletTxs).mockName( + 'useWalletTxs', ); diff --git a/packages/nami/src/ui/app/components/changePasswordModal.tsx b/packages/nami/src/ui/app/components/changePasswordModal.tsx index 129ec68ea8..6859653df2 100644 --- a/packages/nami/src/ui/app/components/changePasswordModal.tsx +++ b/packages/nami/src/ui/app/components/changePasswordModal.tsx @@ -22,7 +22,7 @@ import { import { Events } from '../../../features/analytics/events'; import { useCaptureEvent } from '../../../features/analytics/hooks'; import { NamiPassword } from './namiPassword'; -import { useOutsideHandles } from 'features/outside-handles-provider'; +import { useOutsideHandles } from '../../../features/outside-handles-provider'; import { noop } from 'lodash'; interface Props { diff --git a/packages/nami/src/ui/app/pages/send.stories.tsx b/packages/nami/src/ui/app/pages/send.stories.tsx index 4c90597afc..f2b0fb5e1b 100644 --- a/packages/nami/src/ui/app/pages/send.stories.tsx +++ b/packages/nami/src/ui/app/pages/send.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Box, useColorMode } from '@chakra-ui/react'; +import { Box, useColorMode, useColorModeValue } from '@chakra-ui/react'; import type { Meta, StoryObj } from '@storybook/react'; import { screen, userEvent, within } from '@storybook/test'; @@ -16,7 +16,9 @@ import { account1, currentAccount } from '../../../mocks/account.mock'; import { store } from '../../../mocks/store.mock'; import { useStoreState, useStoreActions } from '../../store.mock'; import { Cardano } from '../../../../.storybook/mocks/cardano-sdk.mock'; - +import { useOutsideHandles } from '../../../features/outside-handles-provider/useOutsideHandles.mock'; +import { UpgradeToLaceHeader } from '../../UpgradeToLaceHeader'; +import { useLocation } from '../../../../.storybook/mocks/react-router-dom.mock'; import Send from './send'; import { of } from 'rxjs'; import { Wallet } from '@lace/cardano'; @@ -208,14 +210,26 @@ const inMemoryWallet: Wallet.ObservableWallet = { const noop = (async () => {}) as any; +declare global { + interface Window { + chrome: { + runtime: { + getURL: (path: string) => string; + }; + }; + } +} + const SendStory = ({ colorMode, }: Readonly<{ colorMode: 'dark' | 'light' }>): React.ReactElement => { const { setColorMode } = useColorMode(); setColorMode(colorMode); + const containerBg = useColorModeValue('white', 'gray.800'); return ( - + + {}} /> ); @@ -260,6 +277,18 @@ const meta: Meta = { layout: 'centered', }, beforeEach: () => { + useLocation.mockImplementation( + () => + ({ + pathname: '', + }) as any, + ); + useOutsideHandles.mockImplementation(() => { + return { + secretsUtil: { password: {} }, + lockedStakeRewards: BigInt(0), + }; + }); createTab.mockImplementation(async () => { await Promise.resolve(); }); @@ -270,6 +299,7 @@ const meta: Meta = { return callback({ ...store, globalModel: { + laceSwitchStore: { isLaceSwitchInProgress: false }, sendStore: { ...store.globalModel.sendStore, txInfo, @@ -303,6 +333,7 @@ const meta: Meta = { return () => { createTab.mockReset(); + useOutsideHandles.mockReset(); isValidAddress.mockReset(); useStoreState.mockReset(); useStoreActions.mockReset(); @@ -354,6 +385,7 @@ export const AddressSuccessLight: Story = { return callback({ ...store, globalModel: { + laceSwitchStore: {}, sendStore: { ...store.globalModel.sendStore, txInfo, @@ -389,6 +421,7 @@ export const AmountErrorLight: Story = { return callback({ ...store, globalModel: { + laceSwitchStore: {}, sendStore: { ...store.globalModel.sendStore, txInfo, @@ -459,6 +492,7 @@ export const AssetsSetQuantityLight: Story = { return callback({ ...store, globalModel: { + laceSwitchStore: {}, sendStore: { ...store.globalModel.sendStore, txInfo, @@ -515,6 +549,7 @@ export const AssetsWithQuantityLight: Story = { return callback({ ...store, globalModel: { + laceSwitchStore: {}, sendStore: { ...store.globalModel.sendStore, message: '123', diff --git a/packages/nami/src/ui/app/pages/send.tsx b/packages/nami/src/ui/app/pages/send.tsx index 58106993d8..4029127931 100644 --- a/packages/nami/src/ui/app/pages/send.tsx +++ b/packages/nami/src/ui/app/pages/send.tsx @@ -131,9 +131,7 @@ const Send = ({ const { cardanoCoin, walletType, openHWFlow, networkConnection } = useCommonOutsideHandles(); - const { secretsUtil } = useOutsideHandles(); - - const { lockedStakeRewards } = useOutsideHandles(); + const { secretsUtil, lockedStakeRewards } = useOutsideHandles(); const [showSwitchToLaceBanner, setShowSwitchToLaceBanner] = useState(false); const [address, setAddress] = [ useStoreState(state => state.globalModel.sendStore.address), @@ -452,7 +450,7 @@ const Send = ({ () => BigInt(toUnit(value.ada)) > BigInt(BigInt(utxoTotal?.coins || 0) + BigInt(rewards || 0) || '0') - - BigInt(lockedStakeRewards.toString()), + BigInt(lockedStakeRewards?.toString() || 0), [value.ada, utxoTotal?.coins, rewards, lockedStakeRewards], ); diff --git a/packages/nami/src/ui/app/pages/settings.stories.tsx b/packages/nami/src/ui/app/pages/settings.stories.tsx index d347cbc626..6c9e9ab11a 100644 --- a/packages/nami/src/ui/app/pages/settings.stories.tsx +++ b/packages/nami/src/ui/app/pages/settings.stories.tsx @@ -17,6 +17,18 @@ import { } from '../../../../.storybook/mocks/react-router-dom.mock'; import { CurrencyCode } from '../../../adapters/currency'; import { Wallet } from '@lace/cardano'; +import { UpgradeToLaceHeader } from '../../UpgradeToLaceHeader'; +import { useLocation } from '../../../../.storybook/mocks/react-router-dom.mock'; + +declare global { + interface Window { + chrome: { + runtime: { + getURL: (path: string) => string; + }; + }; + } +} const SettingsStory = ({ colorMode, @@ -34,6 +46,7 @@ const SettingsStory = ({ return ( + {}} /> true} availableChains={['Mainnet', 'Preprod', 'Preview', 'Sanchonet']} @@ -61,6 +74,7 @@ const SettingsStory = ({ switchNetwork={async () => {}} enableCustomNode={async () => {}} defaultSubmitApi="" + walletType="InMemory" /> ); @@ -87,8 +101,20 @@ const meta: Meta = { layout: 'centered', }, beforeEach: () => { + useLocation.mockImplementation( + () => + ({ + pathname: '', + }) as any, + ); useStoreState.mockImplementation((callback: any) => { - return callback(store); + return callback({ + ...store, + globalModel: { + ...store.globalModel, + laceSwitchStore: { isLaceSwitchInProgress: false }, + }, + }); }); useStoreActions.mockImplementation(() => { return () => void 0; @@ -159,26 +185,6 @@ export const GeneralChangePasswordDark: Story = { colorMode: 'dark', }, }; -export const GeneralResetWalletLight: Story = { - parameters: { - colorMode: 'light', - path: '/settings/general', - }, - play: async ({ canvasElement, step }) => { - const canvas = within(canvasElement); - await step('Toggle', async () => { - await userEvent.click(canvas.getByText('Reset Wallet')); - }); - }, -}; - -export const GeneralResetWalletDark: Story = { - ...GeneralResetWalletLight, - parameters: { - ...GeneralResetWalletLight.parameters, - colorMode: 'dark', - }, -}; export const WhitelistedLight: Story = { parameters: { diff --git a/packages/nami/src/ui/app/pages/settings.tsx b/packages/nami/src/ui/app/pages/settings.tsx index 3c66471764..54cf665c67 100644 --- a/packages/nami/src/ui/app/pages/settings.tsx +++ b/packages/nami/src/ui/app/pages/settings.tsx @@ -47,7 +47,7 @@ import type { UseAccount } from '../../../adapters/account'; import type { OutsideHandlesContextValue } from '../../../features/outside-handles-provider'; import type { ChangePasswordModalComponentRef } from '../components/changePasswordModal'; import type { Wallet } from '@lace/cardano'; -import type { CommonOutsideHandlesContextValue } from 'features/common-outside-handles-provider'; +import type { CommonOutsideHandlesContextValue } from '../../../features/common-outside-handles-provider'; type Props = Pick< OutsideHandlesContextValue, diff --git a/packages/nami/src/ui/app/pages/wallet.stories.tsx b/packages/nami/src/ui/app/pages/wallet.stories.tsx index 619e538dd3..ae9dd4265e 100644 --- a/packages/nami/src/ui/app/pages/wallet.stories.tsx +++ b/packages/nami/src/ui/app/pages/wallet.stories.tsx @@ -32,7 +32,9 @@ import { useDelegation } from '../../../adapters/delegation.mock'; import { Wallet as CardanoWallet } from '@lace/cardano'; import { useOutsideHandles } from '../../../features/outside-handles-provider/useOutsideHandles.mock'; import { useCollateral } from '../../../adapters/collateral.mock'; -import { useTxInfo } from '../../../adapters/transactions.mock'; +import { useWalletTxs } from '../../../adapters/transactions.mock'; +import { UpgradeToLaceHeader } from '../../UpgradeToLaceHeader'; +import { useLocation } from '../../../../.storybook/mocks/react-router-dom.mock'; const noop = (async () => {}) as any; @@ -45,6 +47,16 @@ const cardanoCoin = { process.env.APP_VERSION = '0.1.0'; +declare global { + interface Window { + chrome: { + runtime: { + getURL: (path: string) => string; + }; + }; + } +} + const WalletStory = ({ colorMode, assets, @@ -58,6 +70,7 @@ const WalletStory = ({ return ( + {}} /> = { layout: 'centered', }, beforeEach: () => { + useLocation.mockImplementation( + () => + ({ + pathname: '', + }) as any, + ); createTab.mockImplementation(async () => { await Promise.resolve(); }); useStoreState.mockImplementation((callback: any) => { - return callback(store); + return callback({ + ...store, + globalModel: { + ...store.globalModel, + laceSwitchStore: { isLaceSwitchInProgress: false }, + }, + }); }); useStoreActions.mockImplementation(() => { // @ts-ignore @@ -164,7 +189,7 @@ export const LayoutLight: Story = { }); useOutsideHandles.mockImplementation(() => { return { - secretsUtil: {}, + secretsUtil: { password: {} }, cardanoCoin, collateralFee: BigInt(0), isInitializingCollateral: false, @@ -478,7 +503,7 @@ export const CollectibleMetadataLight: Story = { const menu = await canvas.findByTestId('collectibles'); await userEvent.click(menu.children[0]); - const nft = await canvas.findByTestId('collectible-0'); + const nft = await canvas.findByTestId('collectible-DAI'); await userEvent.click(nft.children[0]); }); }, @@ -534,7 +559,7 @@ export const StakePoolDelegatingLight: Story = { }); useOutsideHandles.mockImplementation(() => { return { - secretsUtil: {}, + secretsUtil: { password: {} }, cardanoCoin, collateralFee: BigInt(0), isInitializingCollateral: false, @@ -733,7 +758,7 @@ export const RemoveCollateralLight: Story = { }); useOutsideHandles.mockImplementation(() => { return { - secretsUtil: {}, + secretsUtil: { password: {} }, cardanoCoin, collateralFee: BigInt(0), isInitializingCollateral: false, @@ -803,7 +828,7 @@ export const AddCollateralLight: Story = { }); useOutsideHandles.mockImplementation(() => { return { - secretsUtil: {}, + secretsUtil: { password: {} }, cardanoCoin, collateralFee: BigInt(176281), isInitializingCollateral: false, @@ -969,6 +994,34 @@ export const EmptyHistoryListLight: Story = { await userEvent.click(canvas.getByTestId('clockIcon')); }); }, + beforeEach: () => { + useWalletTxs.mockImplementation(() => { + return []; + }); + useDelegation.mockImplementation(() => { + return { + delegation: undefined, + initDelegation: async ( + pool?: Readonly, + ) => { + await pool; + }, + stakeRegistration: '2000000', + }; + }); + useCollateral.mockImplementation(() => { + return { + reclaimCollateral: async () => {}, + submitCollateral: async () => {}, + hasCollateral: false, + }; + }); + return () => { + useDelegation.mockReset(); + useCollateral.mockReset(); + useWalletTxs.mockReset(); + }; + }, parameters: { colorMode: 'light', }, @@ -984,6 +1037,9 @@ export const EmptyHistoryListDark: Story = { export const HistoryLight: Story = { ...LayoutLight, beforeEach: () => { + useWalletTxs.mockImplementation(() => { + return Object.values(txInfo); + }); useDelegation.mockImplementation(() => { return { delegation: undefined, @@ -998,7 +1054,7 @@ export const HistoryLight: Story = { useOutsideHandles.mockImplementation(() => { return useMemo( () => ({ - secretsUtil: {}, + secretsUtil: { password: {} }, cardanoCoin, collateralFee: BigInt(0), isInitializingCollateral: false, @@ -1014,15 +1070,12 @@ export const HistoryLight: Story = { hasCollateral: false, }; }); - useTxInfo.mockImplementation((tx: CardanoWallet.Cardano.HydratedTx) => { - return txInfo[tx.id]; - }); return () => { useDelegation.mockReset(); useOutsideHandles.mockReset(); useCollateral.mockReset(); - useTxInfo.mockReset(); + useWalletTxs.mockReset(); }; }, play: async ({ canvasElement, step }) => {