Commit 88c9e4b5 authored by tom's avatar tom

more test fixes

parent 4c868b50
import React from 'react'; import React from 'react';
import getComponentDisplayName from '../utils/getComponentDisplayName';
import { Button, type ButtonProps } from './button'; import { Button, type ButtonProps } from './button';
export interface IconButtonProps extends Omit<ButtonProps, 'size'> { export interface IconButtonProps extends Omit<ButtonProps, 'size'> {
...@@ -8,7 +9,14 @@ export interface IconButtonProps extends Omit<ButtonProps, 'size'> { ...@@ -8,7 +9,14 @@ export interface IconButtonProps extends Omit<ButtonProps, 'size'> {
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>( export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
function IconButton(props, ref) { function IconButton(props, ref) {
const { size, variant = 'plain', ...rest } = props; const { size, variant = 'plain', children, ...rest } = props;
// FIXME: I have to clone the children instead of using _icon props because of style overrides
// in some pw tests for some reason the _icon style will be applied before the style of child (IconSvg component)
const child = React.Children.only<React.ReactElement>(children as React.ReactElement);
const clonedChildren = size && getComponentDisplayName(child.type) === 'IconSvg' ?
React.cloneElement(child, { boxSize: 5 }) :
child;
const sizeStyle = (() => { const sizeStyle = (() => {
switch (size) { switch (size) {
...@@ -38,11 +46,13 @@ export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>( ...@@ -38,11 +46,13 @@ export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
alignItems="center" alignItems="center"
p={ 0 } p={ 0 }
minW="auto" minW="auto"
{ ...sizeStyle }
flexShrink="0" flexShrink="0"
variant={ variant } variant={ variant }
{ ...sizeStyle }
{ ...rest } { ...rest }
/> >
{ clonedChildren }
</Button>
); );
}, },
); );
...@@ -9,11 +9,6 @@ export const recipe = defineRecipe({ ...@@ -9,11 +9,6 @@ export const recipe = defineRecipe({
_disabled: { _disabled: {
opacity: 'control.disabled', opacity: 'control.disabled',
}, },
// FIXME have to override the Chakra UI styles for the SVG icon inside the button
// try to find a better solution
'& svg': {
boxSize: 'auto',
},
_loading: { _loading: {
bgColor: 'unset', bgColor: 'unset',
}, },
......
...@@ -154,7 +154,7 @@ const AddressDetails = ({ addressQuery }: Props) => { ...@@ -154,7 +154,7 @@ const AddressDetails = ({ addressQuery }: Props) => {
</DetailedInfo.ItemValue> </DetailedInfo.ItemValue>
</> </>
) } ) }
{ data.is_contract && data.implementations && data.implementations?.length > 0 && ( { !addressQuery.isPlaceholderData && data.is_contract && data.implementations && data.implementations?.length > 0 && (
<AddressImplementations <AddressImplementations
data={ data.implementations } data={ data.implementations }
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
......
...@@ -144,7 +144,7 @@ test.describe('mobile', () => { ...@@ -144,7 +144,7 @@ test.describe('mobile', () => {
{ hooksConfig }, { hooksConfig },
); );
await component.getByLabel('list').click(); await component.locator('button').filter({ hasText: 'List' }).click();
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
......
...@@ -41,7 +41,7 @@ test.describe('base view', () => { ...@@ -41,7 +41,7 @@ test.describe('base view', () => {
); );
}); });
test('+@mobile', async() => { test('desktop', async() => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
...@@ -55,6 +55,31 @@ test.describe('base view', () => { ...@@ -55,6 +55,31 @@ test.describe('base view', () => {
}); });
}); });
test.describe('base view', () => {
test.use({ viewport: pwConfig.viewport.mobile });
test('mobile', async({ render, mockApiResponse }) => {
await mockApiResponse(
'address_txs',
{
items: [
txMock.base,
{ ...txMock.base, hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3194' },
],
next_page_params: DEFAULT_PAGINATION,
},
{ pathParams: { hash: CURRENT_ADDRESS } },
);
const component = await render(
<Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs/>
</Box>,
{ hooksConfig },
);
await expect(component).toHaveScreenshot();
});
});
test.describe('socket', () => { test.describe('socket', () => {
// FIXME // FIXME
// test cases which use socket cannot run in parallel since the socket server always run on the same port // test cases which use socket cannot run in parallel since the socket server always run on the same port
......
...@@ -64,7 +64,8 @@ const ContractSourceAddressSelector = ({ className, selectedItem, onItemSelect, ...@@ -64,7 +64,8 @@ const ContractSourceAddressSelector = ({ className, selectedItem, onItemSelect,
placeholder="Select contract" placeholder="Select contract"
defaultValue={ [ selectedItem.address ] } defaultValue={ [ selectedItem.address ] }
onValueChange={ handleItemSelect } onValueChange={ handleItemSelect }
maxW={{ base: '180px', lg: 'none' }} maxW={{ base: '180px', lg: '400px' }}
w="fit-content"
loading={ isLoading } loading={ isLoading }
/> />
<Flex alignItems="center"> <Flex alignItems="center">
......
...@@ -18,14 +18,7 @@ const ContractDetailsInfoItem = ({ label, children, className, isLoading, hint } ...@@ -18,14 +18,7 @@ const ContractDetailsInfoItem = ({ label, children, className, isLoading, hint }
<Skeleton loading={ isLoading } w="170px" flexShrink={ 0 } fontWeight={ 500 }> <Skeleton loading={ isLoading } w="170px" flexShrink={ 0 } fontWeight={ 500 }>
<Flex alignItems="center"> <Flex alignItems="center">
{ label } { label }
{ hint && ( { hint && <Hint label={ hint } ml={ 2 }/> }
<Hint
label={ hint }
ml={ 2 }
color={{ _light: 'gray.600', _dark: 'gray.400' }}
tooltipProps={{ positioning: { placement: 'bottom' } }}
/>
) }
</Flex> </Flex>
</Skeleton> </Skeleton>
<Skeleton loading={ isLoading }>{ children }</Skeleton> <Skeleton loading={ isLoading }>{ children }</Skeleton>
......
...@@ -218,7 +218,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -218,7 +218,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
</Flex> </Flex>
) } ) }
<Flex rowGap={ 5 } flexDir="column"> <Flex rowGap={ 5 } flexDir="column">
<div> <Flex flexDir="column">
<CopyToClipboard text={ signingMessage } ml="auto"/> <CopyToClipboard text={ signingMessage } ml="auto"/>
<FormFieldText<Fields> <FormFieldText<Fields>
name="message" name="message"
...@@ -231,7 +231,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -231,7 +231,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
minH: 'auto', minH: 'auto',
}} }}
/> />
</div> </Flex>
{ !noWeb3Provider && ( { !noWeb3Provider && (
<RadioGroup <RadioGroup
onValueChange={ handleSignMethodChange } onValueChange={ handleSignMethodChange }
......
...@@ -7,23 +7,23 @@ import imageBlobWithZeroesBytes from './image_with_zeroes.blob'; ...@@ -7,23 +7,23 @@ import imageBlobWithZeroesBytes from './image_with_zeroes.blob';
test.use({ viewport: { width: 500, height: 300 } }); test.use({ viewport: { width: 500, height: 300 } });
test('text', async({ render }) => { test('text', async({ render, page }) => {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const data = '0xE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A280E2A3A4E2A1B6E2A0BFE2A0BFE2A0B7E2A3B6E2A384E2A080E2A080E2A080E2A080E2A0800AE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3B0E2A1BFE2A081E2A080E2A080E2A280E2A380E2A180E2A099E2A3B7E2A180E2A080E2A080E2A0800AE2A080E2A080E2A080E2A180E2A080E2A080E2A080E2A080E2A080E2A2A0E2A3BFE2A081E2A080E2A080E2A080E2A098E2A0BFE2A083E2A080E2A2B8E2A3BFE2A3BFE2A3BFE2A3BF0AE2A080E2A3A0E2A1BFE2A09BE2A2B7E2A3A6E2A180E2A080E2A080E2A088E2A3BFE2A184E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3B8E2A3BFE2A3BFE2A3BFE2A09F0AE2A2B0E2A1BFE2A081E2A080E2A080E2A099E2A2BFE2A3A6E2A3A4E2A3A4E2A3BCE2A3BFE2A384E2A080E2A080E2A080E2A080E2A080E2A2B4E2A19FE2A09BE2A08BE2A081E2A0800AE2A3BFE2A087E2A080E2A080E2A080E2A080E2A080E2A089E2A089E2A089E2A089E2A089E2A081E2A080E2A080E2A080E2A080E2A080E2A088E2A3BFE2A180E2A080E2A080E2A0800AE2A3BFE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A2B9E2A187E2A080E2A080E2A0800AE2A3BFE2A186E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3BCE2A187E2A080E2A080E2A0800AE2A0B8E2A3B7E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A2A0E2A1BFE2A080E2A080E2A080E2A0800AE2A080E2A0B9E2A3B7E2A3A4E2A380E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A380E2A3B0E2A1BFE2A081E2A080E2A080E2A080E2A0800AE2A080E2A080E2A080E2A089E2A099E2A09BE2A0BFE2A0B6E2A3B6E2A3B6E2A3B6E2A3B6E2A3B6E2A0B6E2A0BFE2A09FE2A09BE2A089E2A080E2A080E2A080E2A080E2A080E2A080'; const data = '0xE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A280E2A3A4E2A1B6E2A0BFE2A0BFE2A0B7E2A3B6E2A384E2A080E2A080E2A080E2A080E2A0800AE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3B0E2A1BFE2A081E2A080E2A080E2A280E2A380E2A180E2A099E2A3B7E2A180E2A080E2A080E2A0800AE2A080E2A080E2A080E2A180E2A080E2A080E2A080E2A080E2A080E2A2A0E2A3BFE2A081E2A080E2A080E2A080E2A098E2A0BFE2A083E2A080E2A2B8E2A3BFE2A3BFE2A3BFE2A3BF0AE2A080E2A3A0E2A1BFE2A09BE2A2B7E2A3A6E2A180E2A080E2A080E2A088E2A3BFE2A184E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3B8E2A3BFE2A3BFE2A3BFE2A09F0AE2A2B0E2A1BFE2A081E2A080E2A080E2A099E2A2BFE2A3A6E2A3A4E2A3A4E2A3BCE2A3BFE2A384E2A080E2A080E2A080E2A080E2A080E2A2B4E2A19FE2A09BE2A08BE2A081E2A0800AE2A3BFE2A087E2A080E2A080E2A080E2A080E2A080E2A089E2A089E2A089E2A089E2A089E2A081E2A080E2A080E2A080E2A080E2A080E2A088E2A3BFE2A180E2A080E2A080E2A0800AE2A3BFE2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A2B9E2A187E2A080E2A080E2A0800AE2A3BFE2A186E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A3BCE2A187E2A080E2A080E2A0800AE2A0B8E2A3B7E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A2A0E2A1BFE2A080E2A080E2A080E2A0800AE2A080E2A0B9E2A3B7E2A3A4E2A380E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A080E2A380E2A3B0E2A1BFE2A081E2A080E2A080E2A080E2A0800AE2A080E2A080E2A080E2A089E2A099E2A09BE2A0BFE2A0B6E2A3B6E2A3B6E2A3B6E2A3B6E2A3B6E2A0B6E2A0BFE2A09FE2A09BE2A089E2A080E2A080E2A080E2A080E2A080E2A080';
const component = await render(<BlobData hash="0x01" data={ data }/>); const component = await render(<BlobData hash="0x01" data={ data }/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
await component.getByRole('button', { name: 'Raw' }).click(); await component.getByRole('combobox').click();
await component.getByText('UTF-8').click(); await page.getByRole('option', { name: /utf/i }).click();
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('image', async({ render }) => { test('image', async({ render, page }) => {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const data = '0x89504E470D0A1A0A0000000D494844520000003C0000003C0403000000C8D2C4410000000467414D410000B18F0BFC6105000000017352474200AECE1CE900000027504C54454C69712B6CB02A6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB0F4205A540000000C74524E5300ED2F788CD91B99475C09B969CFA99D0000004F7A5458745261772070726F66696C65207479706520697074630000789CE3CA2C2849E6520003230B2E630B1323134B9314031320448034C3640323B35420CBD8D4C8C4CCC41CC407CB8048A04A2E0028950EE32A226D1F0000000970485973000084DF000084DF0195C81C33000000F24944415438CB636000018E983367CE482780D90CDA40F6991D0C4820152472A60ACCE6DA03629F4E40929E03961602B39964C09C0624691B24690E88F48461215D03160903B3D962C01C07842C2758C341A80643B0B40484C3646C6C5C78E6E016171723A8E215262EEE31670E161B1B7731304C05AB155EC08002C0D172E6F80206884DBB50651938CF4003FE0CBA4390E3C56064482F53525252C329CD562A2828283A0197340B22AAB0494332C311FCD2C747A547A58996C69998D8F12745B68DA0846C85331B2CEAE8E8681A81D91F8B348C4605D0527B02A4283FA88026CD05163EAAC0900ED21EC9800EC0C2110C002BBA9FE999B920330000000049454E44AE426082'; const data = '0x89504E470D0A1A0A0000000D494844520000003C0000003C0403000000C8D2C4410000000467414D410000B18F0BFC6105000000017352474200AECE1CE900000027504C54454C69712B6CB02A6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB02B6CB0F4205A540000000C74524E5300ED2F788CD91B99475C09B969CFA99D0000004F7A5458745261772070726F66696C65207479706520697074630000789CE3CA2C2849E6520003230B2E630B1323134B9314031320448034C3640323B35420CBD8D4C8C4CCC41CC407CB8048A04A2E0028950EE32A226D1F0000000970485973000084DF000084DF0195C81C33000000F24944415438CB636000018E983367CE482780D90CDA40F6991D0C4820152472A60ACCE6DA03629F4E40929E03961602B39964C09C0624691B24690E88F48461215D03160903B3D962C01C07842C2758C341A80643B0B40484C3646C6C5C78E6E016171723A8E215262EEE31670E161B1B7731304C05AB155EC08002C0D172E6F80206884DBB50651938CF4003FE0CBA4390E3C56064482F53525252C329CD562A2828283A0197340B22AAB0494332C311FCD2C747A547A58996C69998D8F12745B68DA0846C85331B2CEAE8E8681A81D91F8B348C4605D0527B02A4283FA88026CD05163EAAC0900ED21EC9800EC0C2110C002BBA9FE999B920330000000049454E44AE426082';
const component = await render(<BlobData hash="0x01" data={ data }/>); const component = await render(<BlobData hash="0x01" data={ data }/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
await component.getByRole('button', { name: 'Image' }).click(); await component.getByRole('combobox').click();
await component.getByText('Base64').click(); await page.getByRole('option', { name: /base64/i }).click();
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
......
...@@ -33,7 +33,7 @@ interface Props { ...@@ -33,7 +33,7 @@ interface Props {
} }
const BlobData = ({ data, isLoading, hash }: Props) => { const BlobData = ({ data, isLoading, hash }: Props) => {
const [ format, setFormat ] = React.useState<Format>('Raw'); const [ format, setFormat ] = React.useState<Array<Format>>([ 'Raw' ]);
const guessedType = React.useMemo(() => { const guessedType = React.useMemo(() => {
if (isLoading) { if (isLoading) {
...@@ -52,17 +52,17 @@ const BlobData = ({ data, isLoading, hash }: Props) => { ...@@ -52,17 +52,17 @@ const BlobData = ({ data, isLoading, hash }: Props) => {
React.useEffect(() => { React.useEffect(() => {
if (isImage) { if (isImage) {
setFormat('Image'); setFormat([ 'Image' ]);
} }
}, [ isImage ]); }, [ isImage ]);
const handleFormatChange = React.useCallback(({ value }: { value: Array<string> }) => { const handleFormatChange = React.useCallback(({ value }: { value: Array<string> }) => {
setFormat(value[0] as Format); setFormat(value as Array<Format>);
}, []); }, []);
const handleDownloadButtonClick = React.useCallback(() => { const handleDownloadButtonClick = React.useCallback(() => {
const fileBlob = (() => { const fileBlob = (() => {
switch (format) { switch (format[0]) {
case 'Image': { case 'Image': {
const bytes = hexToBytes(data); const bytes = hexToBytes(data);
const filteredBytes = removeNonSignificantZeroBytes(bytes); const filteredBytes = removeNonSignificantZeroBytes(bytes);
...@@ -85,7 +85,7 @@ const BlobData = ({ data, isLoading, hash }: Props) => { ...@@ -85,7 +85,7 @@ const BlobData = ({ data, isLoading, hash }: Props) => {
}, [ data, format, guessedType, hash ]); }, [ data, format, guessedType, hash ]);
const content = (() => { const content = (() => {
switch (format) { switch (format[0]) {
case 'Image': { case 'Image': {
if (!guessedType?.mime?.startsWith('image/')) { if (!guessedType?.mime?.startsWith('image/')) {
return <RawDataSnippet data="Not an image" showCopy={ false } isLoading={ isLoading }/>; return <RawDataSnippet data="Not an image" showCopy={ false } isLoading={ isLoading }/>;
...@@ -119,7 +119,7 @@ const BlobData = ({ data, isLoading, hash }: Props) => { ...@@ -119,7 +119,7 @@ const BlobData = ({ data, isLoading, hash }: Props) => {
<Select <Select
collection={ collection } collection={ collection }
placeholder="Select type" placeholder="Select type"
defaultValue={ [ format ] } value={ format }
onValueChange={ handleFormatChange } onValueChange={ handleFormatChange }
ml={ 5 } ml={ 5 }
w="100px" w="100px"
......
...@@ -103,19 +103,19 @@ const LatestBlocks = () => { ...@@ -103,19 +103,19 @@ const LatestBlocks = () => {
return ( return (
<Box width={{ base: '100%', lg: '280px' }} flexShrink={ 0 }> <Box width={{ base: '100%', lg: '280px' }} flexShrink={ 0 }>
<Heading level="3" mb={ 3 }>Latest blocks</Heading> <Heading level="3">Latest blocks</Heading>
{ statsQueryResult.data?.network_utilization_percentage !== undefined && ( { statsQueryResult.data?.network_utilization_percentage !== undefined && (
<Skeleton loading={ statsQueryResult.isPlaceholderData } mt={ 1 } display="inline-block"> <Skeleton loading={ statsQueryResult.isPlaceholderData } mt={ 2 } display="inline-block" textStyle="sm">
<Text as="span" fontSize="sm"> <Text as="span">
Network utilization:{ nbsp } Network utilization:{ nbsp }
</Text> </Text>
<Text as="span" fontSize="sm" color="blue.400" fontWeight={ 700 }> <Text as="span" color="blue.400" fontWeight={ 700 }>
{ statsQueryResult.data?.network_utilization_percentage.toFixed(2) }% { statsQueryResult.data?.network_utilization_percentage.toFixed(2) }%
</Text> </Text>
</Skeleton> </Skeleton>
) } ) }
{ statsQueryResult.data?.celo && ( { statsQueryResult.data?.celo && (
<Box whiteSpace="pre-wrap" fontSize="sm"> <Box whiteSpace="pre-wrap" textStyle="sm" mt={ 2 }>
<span>Current epoch: </span> <span>Current epoch: </span>
<chakra.span fontWeight={ 700 }>#{ statsQueryResult.data.celo.epoch_number }</chakra.span> <chakra.span fontWeight={ 700 }>#{ statsQueryResult.data.celo.epoch_number }</chakra.span>
</Box> </Box>
......
...@@ -54,7 +54,7 @@ const LatestBlocksItem = ({ block, isLoading, animation }: Props) => { ...@@ -54,7 +54,7 @@ const LatestBlocksItem = ({ block, isLoading, animation }: Props) => {
ml={ 2 } ml={ 2 }
/> />
</Flex> </Flex>
<Grid gridGap={ 2 } templateColumns="auto minmax(0, 1fr)" fontSize="sm"> <Grid gridGap={ 2 } templateColumns="auto minmax(0, 1fr)" textStyle="sm">
<Skeleton loading={ isLoading }>Txn</Skeleton> <Skeleton loading={ isLoading }>Txn</Skeleton>
<Skeleton loading={ isLoading } color="text.secondary"><span>{ block.transaction_count }</span></Skeleton> <Skeleton loading={ isLoading } color="text.secondary"><span>{ block.transaction_count }</span></Skeleton>
......
...@@ -44,7 +44,7 @@ const InteropMessagesTableItem = ({ item, isLoading }: Props) => { ...@@ -44,7 +44,7 @@ const InteropMessagesTableItem = ({ item, isLoading }: Props) => {
</TableCell> </TableCell>
<TableCell> <TableCell>
{ item.init_chain !== undefined ? { item.init_chain !== undefined ?
<AddressEntityInterop address={{ hash: item.target }} isLoading={ isLoading } truncation="constant" chain={ item.init_chain }/> : <AddressEntityInterop address={{ hash: item.target }} isLoading={ isLoading } truncation="constant" chain={ item.init_chain } w="min-content"/> :
<AddressEntity address={{ hash: item.target }} isLoading={ isLoading } truncation="constant"/> <AddressEntity address={{ hash: item.target }} isLoading={ isLoading } truncation="constant"/>
} }
</TableCell> </TableCell>
...@@ -56,7 +56,7 @@ const InteropMessagesTableItem = ({ item, isLoading }: Props) => { ...@@ -56,7 +56,7 @@ const InteropMessagesTableItem = ({ item, isLoading }: Props) => {
</TableCell> </TableCell>
<TableCell> <TableCell>
{ item.relay_chain !== undefined ? { item.relay_chain !== undefined ?
<AddressEntityInterop address={{ hash: item.target }} isLoading={ isLoading } truncation="constant" chain={ item.relay_chain }/> : <AddressEntityInterop address={{ hash: item.target }} isLoading={ isLoading } truncation="constant" chain={ item.relay_chain } w="min-content"/> :
<AddressEntity address={{ hash: item.target }} isLoading={ isLoading } truncation="constant"/> <AddressEntity address={{ hash: item.target }} isLoading={ isLoading } truncation="constant"/>
} }
</TableCell> </TableCell>
......
...@@ -2,26 +2,41 @@ import React from 'react'; ...@@ -2,26 +2,41 @@ import React from 'react';
import * as interopMessageMock from 'mocks/interop/interop'; import * as interopMessageMock from 'mocks/interop/interop';
import { test, expect } from 'playwright/lib'; import { test, expect } from 'playwright/lib';
import * as pwConfig from 'playwright/utils/config';
import InteropMessages from './InteropMessages'; import InteropMessages from './InteropMessages';
test('default view +@mobile', async({ render, mockTextAd, mockAssetResponse, mockApiResponse }) => { const MESSAGES_RESPONSE = {
await mockTextAd();
await mockAssetResponse(interopMessageMock.chain.chain_logo as string, './playwright/mocks/image_s.jpg');
await mockApiResponse('optimistic_l2_interop_messages', {
items: [ items: [
interopMessageMock.interopMessageIn, interopMessageMock.interopMessageIn,
interopMessageMock.interopMessageIn1, interopMessageMock.interopMessageIn1,
interopMessageMock.interopMessageOut, interopMessageMock.interopMessageOut,
interopMessageMock.interopMessageOut1, interopMessageMock.interopMessageOut1,
], ].map((item, index) => ({ ...item, init_transaction_hash: `${ item.init_transaction_hash.slice(0, -1) }${ index }` })),
next_page_params: { next_page_params: {
init_transaction_hash: '1', init_transaction_hash: '1',
items_count: 4, items_count: 4,
timestamp: 1719456000, timestamp: 1719456000,
}, },
}); };
test('default view', async({ render, mockTextAd, mockAssetResponse, mockApiResponse }) => {
await mockTextAd();
await mockAssetResponse(interopMessageMock.chain.chain_logo as string, './playwright/mocks/image_s.jpg');
await mockApiResponse('optimistic_l2_interop_messages', MESSAGES_RESPONSE);
await mockApiResponse('optimistic_l2_interop_messages_count', 4000000);
const component = await render(<InteropMessages/>);
await expect(component).toHaveScreenshot();
});
test.describe('mobile', () => {
test.use({ viewport: pwConfig.viewport.mobile });
test('default view', async({ render, mockTextAd, mockAssetResponse, mockApiResponse }) => {
await mockTextAd();
await mockAssetResponse(interopMessageMock.chain.chain_logo as string, './playwright/mocks/image_s.jpg');
await mockApiResponse('optimistic_l2_interop_messages', MESSAGES_RESPONSE);
await mockApiResponse('optimistic_l2_interop_messages_count', 4000000); await mockApiResponse('optimistic_l2_interop_messages_count', 4000000);
const component = await render(<InteropMessages/>); const component = await render(<InteropMessages/>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
});
}); });
...@@ -63,7 +63,7 @@ const NameDomain = () => { ...@@ -63,7 +63,7 @@ const NameDomain = () => {
variant="subheading" variant="subheading"
/> />
{ infoQuery.data?.resolved_address && ( { infoQuery.data?.resolved_address && (
<Flex alignItems="center" maxW="100%" columnGap={ 3 }> <Flex alignItems="center" maxW="100%" columnGap={ 2 }>
<AddressEntity <AddressEntity
address={ infoQuery.data?.resolved_address } address={ infoQuery.data?.resolved_address }
isLoading={ isLoading } isLoading={ isLoading }
......
...@@ -51,11 +51,10 @@ const RewardsDashboard = () => { ...@@ -51,11 +51,10 @@ const RewardsDashboard = () => {
title="Dashboard" title="Dashboard"
secondRow={ ( secondRow={ (
<span> <span>
The Blockscout Merits Program is just getting started! Learn more about the details,
features, and future plans in our{ ' ' }
<Link external href={ `https://merits.blockscout.com/?tab=users&utm_source=${ config.chain.id }&utm_medium=text-banner` }> <Link external href={ `https://merits.blockscout.com/?tab=users&utm_source=${ config.chain.id }&utm_medium=text-banner` }>
blog post Explore the Merits Hub
</Link>. </Link>{ ' ' }
to learn more info about a program, spend your Merits, learn how to earn more, and much more.
</span> </span>
) } ) }
/> />
......
...@@ -41,7 +41,7 @@ const UserOpsListItem = ({ item, isLoading }: Props) => { ...@@ -41,7 +41,7 @@ const UserOpsListItem = ({ item, isLoading }: Props) => {
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
<Skeleton loading={ isLoading }> <Skeleton loading={ isLoading }>
{ externalLinks.map((link) => ( { externalLinks.map((link) => (
<Link external noIcon href={ link.url } key={ link.url } display="inline-flex"> <Link external href={ link.url } key={ link.url } display="inline-flex">
<Image src={ link.image } alt={ link.title } boxSize={ 5 } mr={ 2 }/> <Image src={ link.image } alt={ link.title } boxSize={ 5 } mr={ 2 }/>
{ link.title } { link.title }
</Link> </Link>
......
...@@ -71,13 +71,13 @@ const PublicTagsSubmitResult = ({ data }: Props) => { ...@@ -71,13 +71,13 @@ const PublicTagsSubmitResult = ({ data }: Props) => {
<Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 6 } mt={ 8 } rowGap={ 3 }> <Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 6 } mt={ 8 } rowGap={ 3 }>
{ hasErrors && ( { hasErrors && (
<Link href={ route({ pathname: '/public-tags/submit', query: startOverButtonQuery }) } asChild> <Link href={ route({ pathname: '/public-tags/submit', query: startOverButtonQuery }) } asChild>
<Button variant="outline"> <Button variant="outline" w={{ base: '100%', lg: 'auto' }}>
Start over Start over
</Button> </Button>
</Link> </Link>
) } ) }
<Link href={ route({ pathname: '/public-tags/submit' }) } asChild> <Link href={ route({ pathname: '/public-tags/submit' }) } asChild>
<Button>Add new tag</Button> <Button w={{ base: '100%', lg: 'auto' }}>Add new tag</Button>
</Link> </Link>
</Flex> </Flex>
</div> </div>
......
...@@ -21,8 +21,8 @@ const ButtonItem = ({ className, label, onClick, icon, isDisabled }: Props) => { ...@@ -21,8 +21,8 @@ const ButtonItem = ({ className, label, onClick, icon, isDisabled }: Props) => {
className={ className } className={ className }
onClick={ onClick } onClick={ onClick }
disabled={ isDisabled } disabled={ isDisabled }
size="md"
variant="icon_secondary" variant="icon_secondary"
boxSize={ 8 }
_icon={{ boxSize: 6 }} _icon={{ boxSize: 6 }}
> >
{ typeof icon === 'string' ? <IconSvg name={ icon }/> : icon } { typeof icon === 'string' ? <IconSvg name={ icon }/> : icon }
......
import type { FlexProps } from '@chakra-ui/react'; import type { FlexProps } from '@chakra-ui/react';
import { Flex } from '@chakra-ui/react'; import { Flex, useToken } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
export interface Props extends FlexProps { export interface Props extends FlexProps {
...@@ -10,6 +10,7 @@ export interface Props extends FlexProps { ...@@ -10,6 +10,7 @@ export interface Props extends FlexProps {
const ContainerWithScrollY = ({ gradientHeight, children, onScrollVisibilityChange, ...rest }: Props) => { const ContainerWithScrollY = ({ gradientHeight, children, onScrollVisibilityChange, ...rest }: Props) => {
const ref = React.useRef<HTMLDivElement>(null); const ref = React.useRef<HTMLDivElement>(null);
const [ hasScroll, setHasScroll ] = React.useState(false); const [ hasScroll, setHasScroll ] = React.useState(false);
const gradientStopColor = useToken('colors', 'global.body.bg');
React.useEffect(() => { React.useEffect(() => {
if (!ref.current) { if (!ref.current) {
...@@ -29,11 +30,11 @@ const ContainerWithScrollY = ({ gradientHeight, children, onScrollVisibilityChan ...@@ -29,11 +30,11 @@ const ContainerWithScrollY = ({ gradientHeight, children, onScrollVisibilityChan
_after={ hasScroll ? { _after={ hasScroll ? {
position: 'absolute', position: 'absolute',
content: '""', content: '""',
bottom: 0, bottom: 1,
left: 0, left: 0,
right: '20px', right: '20px',
height: `${ gradientHeight }px`, height: `${ gradientHeight }px`,
bgGradient: { _light: `linear(to-b, transparent, {colors.white}`, _dark: `linear(to-b, transparent, {colors.black})` }, bg: `linear-gradient(to bottom, transparent, ${ gradientStopColor })`,
} : undefined } } : undefined }
pr={ hasScroll ? 5 : 0 } pr={ hasScroll ? 5 : 0 }
pb={ hasScroll ? `${ gradientHeight }px` : 0 } pb={ hasScroll ? `${ gradientHeight }px` : 0 }
......
...@@ -15,7 +15,8 @@ interface Props extends HTMLChakraProps<'div'> { ...@@ -15,7 +15,8 @@ interface Props extends HTMLChakraProps<'div'> {
isLoading?: boolean; isLoading?: boolean;
} }
const IconSvg = ({ name, isLoading = false, ...props }: Props, ref: React.ForwardedRef<HTMLDivElement>) => { const IconSvg = React.forwardRef(
function IconSvg({ name, isLoading = false, ...props }: Props, ref: React.ForwardedRef<HTMLDivElement>) {
return ( return (
<Skeleton loading={ isLoading } display="inline-block" asChild { ...props } ref={ ref }> <Skeleton loading={ isLoading } display="inline-block" asChild { ...props } ref={ ref }>
<chakra.svg w="100%" h="100%"> <chakra.svg w="100%" h="100%">
...@@ -23,6 +24,9 @@ const IconSvg = ({ name, isLoading = false, ...props }: Props, ref: React.Forwar ...@@ -23,6 +24,9 @@ const IconSvg = ({ name, isLoading = false, ...props }: Props, ref: React.Forwar
</chakra.svg> </chakra.svg>
</Skeleton> </Skeleton>
); );
}; },
);
export default React.forwardRef(IconSvg); IconSvg.displayName = 'IconSvg';
export default IconSvg;
...@@ -14,10 +14,9 @@ interface Props extends IconButtonProps { ...@@ -14,10 +14,9 @@ interface Props extends IconButtonProps {
const ButtonBackTo = ({ href, hint, ...rest }: Props) => { const ButtonBackTo = ({ href, hint, ...rest }: Props) => {
const button = ( const button = (
<IconButton { ...rest }> <IconButton { ...rest } boxSize={ 6 }>
<IconSvg <IconSvg
name="arrows/east" name="arrows/east"
boxSize={ 6 }
transform="rotate(180deg)" transform="rotate(180deg)"
color="icon.backTo" color="icon.backTo"
_hover={{ color: 'link.primary.hover' }} _hover={{ color: 'link.primary.hover' }}
......
...@@ -39,7 +39,7 @@ test('base view +@dark-mode', async({ render, page }) => { ...@@ -39,7 +39,7 @@ test('base view +@dark-mode', async({ render, page }) => {
}); });
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
await component.locator('.chakra-menu__menu-button').click(); await component.getByLabel('Open chart options menu').click();
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
await page.mouse.move(0, 0); await page.mouse.move(0, 0);
......
...@@ -74,7 +74,7 @@ const AddressEntryInterop = (props: Props) => { ...@@ -74,7 +74,7 @@ const AddressEntryInterop = (props: Props) => {
); );
return ( return (
<AddressEntity.Container> <AddressEntity.Container className={ props.className }>
{ props.chain && ( { props.chain && (
<Tooltip content={ `Address on ${ props.chain.chain_name ? props.chain.chain_name : 'external chain' } (chain id ${ props.chain.chain_id })` }> <Tooltip content={ `Address on ${ props.chain.chain_name ? props.chain.chain_name : 'external chain' } (chain id ${ props.chain.chain_id })` }>
{ addressIcon } { addressIcon }
......
...@@ -22,7 +22,7 @@ type Props = { ...@@ -22,7 +22,7 @@ type Props = {
const IconStub = ({ isLoading }: { isLoading?: boolean }) => { const IconStub = ({ isLoading }: { isLoading?: boolean }) => {
return ( return (
<Skeleton <Skeleton
loading={ !isLoading } loading={ isLoading }
display="flex" display="flex"
minWidth="20px" minWidth="20px"
h="20px" h="20px"
......
...@@ -40,7 +40,7 @@ const GasInfoTooltip = ({ children, data, dataUpdatedAt, placement }: Props) => ...@@ -40,7 +40,7 @@ const GasInfoTooltip = ({ children, data, dataUpdatedAt, placement }: Props) =>
3 : 2; 3 : 2;
const content = ( const content = (
<Flex flexDir="column" textStyle="xs" rowGap={ 3 }> <Flex flexDir="column" textStyle="xs" rowGap={ 3 } className="dark">
{ data.gas_price_updated_at && ( { data.gas_price_updated_at && (
<Flex justifyContent="space-between" alignItems="center"> <Flex justifyContent="space-between" alignItems="center">
<Box color="text.secondary">Last update</Box> <Box color="text.secondary">Last update</Box>
...@@ -56,7 +56,7 @@ const GasInfoTooltip = ({ children, data, dataUpdatedAt, placement }: Props) => ...@@ -56,7 +56,7 @@ const GasInfoTooltip = ({ children, data, dataUpdatedAt, placement }: Props) =>
<GasInfoTooltipRow name="Normal" info={ data.gas_prices.average }/> <GasInfoTooltipRow name="Normal" info={ data.gas_prices.average }/>
<GasInfoTooltipRow name="Slow" info={ data.gas_prices.slow }/> <GasInfoTooltipRow name="Slow" info={ data.gas_prices.slow }/>
</Grid> </Grid>
<Link href={ route({ pathname: '/gas-tracker' }) } className="dark"> <Link href={ route({ pathname: '/gas-tracker' }) }>
Gas tracker overview Gas tracker overview
</Link> </Link>
</Flex> </Flex>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment