Commit 621dc684 authored by isstuev's avatar isstuev

tests

parent e43c48b0
/* eslint-disable max-len */
export const apps = [
{
author: 'Hop',
id: 'hop-exchange',
title: 'Hop',
logo: 'https://www.gitbook.com/cdn-cgi/image/width=288,dpr=2.200000047683716,format=auto/https%3A%2F%2Ffiles.gitbook.com%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Lq1XoWGmy8zggj_u2fM%252Fuploads%252FfhJJGsR3RSfFmRoxfvqk%252FHop.png%3Falt%3Dmedia%26token%3D8107e45c-546c-4771-bbfe-e86bb0fe8c1a',
categories: [ 'Bridge' ],
shortDescription: 'Hop is a scalable rollup-to-rollup general token bridge. It allows users to send tokens from one rollup or sidechain to another almost immediately without having to wait for the networks challenge period.',
site: 'https://help.hop.exchange/hc/en-us/articles/4405172445197-What-is-Hop-Protocol-',
description: 'Hop is a scalable rollup-to-rollup general token bridge. It allows users to send tokens from one rollup or sidechain to another almost immediately without having to wait for the networks challenge period.',
external: true,
url: 'https://goerli.hop.exchange/send?token=ETH&sourceNetwork=ethereum',
},
{
author: 'Blockscout',
id: 'token-approval-tracker',
title: 'Token Approval Tracker',
logo: 'https://approval-tracker.apps.blockscout.com/icon-192.png',
categories: [ 'Infra & Dev tooling' ],
shortDescription: 'Token Approval Tracker shows all approvals for any ERC20-compliant tokens and NFTs and lets to revoke them or adjust the approved amount.',
site: 'https://docs.blockscout.com/for-users/blockscout-apps/token-approval-tracker',
description: 'Token Approval Tracker shows all approvals for any ERC20-compliant tokens and NFTs and lets to revoke them or adjust the approved amount.',
url: 'https://approval-tracker.apps.blockscout.com/',
},
];
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import { apps as appsMock } from 'mocks/apps/apps';
import * as searchMock from 'mocks/search/index';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
......@@ -140,3 +142,58 @@ test('search by tx hash +@mobile', async({ mount, page }) => {
await expect(component.locator('main')).toHaveScreenshot();
});
test.describe('with apps', () => {
const MARKETPLACE_CONFIG_URL = 'https://marketplace-config.url';
const extendedTest = test.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', value: MARKETPLACE_CONFIG_URL },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
extendedTest('default view +@mobile', async({ mount, page }) => {
const hooksConfig = {
router: {
query: { q: 'o' },
},
};
const API_URL = buildApiUrl('search') + '?q=o';
await page.route(API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({
items: [
searchMock.token1,
],
next_page_params: { foo: 'bar' },
}),
}));
await page.route(MARKETPLACE_CONFIG_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(appsMock),
}));
await page.route(appsMock[0].logo, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_s.jpg',
});
});
await page.route(appsMock[1].logo as string, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_s.jpg',
});
});
const component = await mount(
<TestApp>
<SearchResults/>
</TestApp>,
{ hooksConfig },
);
await expect(component.locator('main')).toHaveScreenshot();
});
});
......@@ -253,7 +253,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading }: Props) => {
</Skeleton>
</Flex>
{ Boolean(secondRow) && (
<Box w="100%" overflow="hidden">
<Box w="100%" overflow="hidden" whiteSpace={ data.type !== 'app' ? 'nowrap' : undefined }>
{ secondRow }
</Box>
) }
......
......@@ -3,7 +3,9 @@ import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import * as textAdMock from 'mocks/ad/textAd';
import { apps as appsMock } from 'mocks/apps/apps';
import * as searchMock from 'mocks/search/index';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
......@@ -281,3 +283,55 @@ test('recent keywords suggest +@mobile', async({ mount, page }) => {
await page.getByPlaceholder(/search/i).click();
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 1200, height: 500 } });
});
test.describe('with apps', () => {
const MARKETPLACE_CONFIG_URL = 'https://marketplace-config.url';
const extendedTest = test.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', value: MARKETPLACE_CONFIG_URL },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
extendedTest('default view +@mobile', async({ mount, page }) => {
const API_URL = buildApiUrl('search') + '?q=o';
await page.route(API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify({
items: [
searchMock.token1,
],
next_page_params: { foo: 'bar' },
}),
}));
await page.route(MARKETPLACE_CONFIG_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(appsMock),
}));
await page.route(appsMock[0].logo, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_s.jpg',
});
});
await page.route(appsMock[1].logo as string, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_s.jpg',
});
});
await mount(
<TestApp>
<SearchBar/>
</TestApp>,
);
await page.getByPlaceholder(/search/i).type('o');
await page.waitForResponse(API_URL);
await expect(page).toHaveScreenshot({ clip: { x: 0, y: 0, width: 1200, height: 500 } });
});
});
......@@ -8,7 +8,7 @@ import useMarketplaceApps from 'ui/marketplace/useMarketplaceApps';
import TextAd from 'ui/shared/ad/TextAd';
import ContentLoader from 'ui/shared/ContentLoader';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import type { ItemsCategoriesMap } from 'ui/shared/search/utils';
import type { ApiCategory, ItemsCategoriesMap } from 'ui/shared/search/utils';
import { getItemCategory, searchCategories } from 'ui/shared/search/utils';
import SearchBarSuggestApp from './SearchBarSuggestApp';
......@@ -68,7 +68,7 @@ const SearchBarSuggest = ({ query, searchTerm, onItemClick, containerId }: Props
}
const map: Partial<ItemsCategoriesMap> = {};
query.data?.items.forEach(item => {
const cat = getItemCategory(item);
const cat = getItemCategory(item) as ApiCategory;
if (cat) {
if (cat in map) {
map[cat]?.push(item);
......
import { Link, Icon, Image, Flex, Text, useColorModeValue } from '@chakra-ui/react';
import { Icon, Image, Flex, Text, useColorModeValue } from '@chakra-ui/react';
import NextLink from 'next/link';
import React from 'react';
......@@ -16,7 +16,7 @@ interface Props {
onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void;
}
const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) => {
const SearchBarSuggestApp = ({ data, isMobile, searchTerm, onClick }: Props) => {
const logo = (
<Image
......@@ -27,6 +27,8 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
/>
);
const secondaryColor = useColorModeValue('gray.500', 'gray.400');
const content = (() => {
if (isMobile) {
return (
......@@ -81,18 +83,16 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
>
{ data.description }
</Text>
{ data.external && <Icon as={ arrowIcon } boxSize={ 4 } verticalAlign="middle"/> }
{ data.external && <Icon as={ arrowIcon } boxSize={ 4 } verticalAlign="middle" color={ secondaryColor }/> }
</Flex>
);
})();
if (data.external) {
return (
<Link href={ data.url } target="_blank" cursor="auto" _hover={{ textDecoration: 'none' }}>
<SearchBarSuggestItemLink onClick={ onClick }>
{ content }
</SearchBarSuggestItemLink>
</Link>
<SearchBarSuggestItemLink onClick={ onClick } href={ data.url } target="_blank">
{ content }
</SearchBarSuggestItemLink>
);
}
......@@ -105,4 +105,4 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm, onClick }: Props) =>
);
};
export default React.memo(SearchBarSuggestItem);
export default React.memo(SearchBarSuggestApp);
......@@ -3,10 +3,12 @@ import React from 'react';
type Props = {
onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void;
href?: string;
target?: string;
children: React.ReactNode;
}
const SearchBarSuggestItemLink = ({ onClick, children }: Props) => {
const SearchBarSuggestItemLink = ({ onClick, href, target, children }: Props) => {
return (
<chakra.a
py={ 3 }
......@@ -27,6 +29,8 @@ const SearchBarSuggestItemLink = ({ onClick, children }: Props) => {
mt: 2,
}}
onClick={ onClick }
href={ href }
target={ target }
>
{ children }
</chakra.a>
......
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