From 04ea18058082b0ebec2233c748f1dcc24428d353 Mon Sep 17 00:00:00 2001 From: Max Klenk Date: Sat, 1 Jul 2023 08:50:36 +0200 Subject: [PATCH] fix: validate chain with custom matchers --- src/chains/supported.chains.ts | 4 +- src/coins.ts | 2 +- test/coins.logo.test.ts | 43 ++++++++++++------- test/matchers.ts | 76 ++++++++++++++++++++++++++++++++++ test/types.unit.test.ts | 26 +++++++++++- 5 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 test/matchers.ts diff --git a/src/chains/supported.chains.ts b/src/chains/supported.chains.ts index 0894dc94..4eb3118f 100644 --- a/src/chains/supported.chains.ts +++ b/src/chains/supported.chains.ts @@ -904,7 +904,7 @@ export const supportedEVMChains: EVMChain[] = [ metamask: { chainId: prefixChainId(1101), - blockExplorerUrls: ['https://zkevm.polygonscan.com'], + blockExplorerUrls: ['https://zkevm.polygonscan.com/'], chainName: 'Polygon zkEVM', nativeCurrency: { name: 'ETH', @@ -1054,7 +1054,7 @@ export const supportedEVMChains: EVMChain[] = [ multicallAddress: multicallAddresses[ChainId.OPTG], metamask: { - chainId: prefixChainId(69), + chainId: prefixChainId(420), blockExplorerUrls: ['https://blockscout.com/optimism/goerli/'], chainName: 'Optimistic Ethereum Testnet Goerli', nativeCurrency: { diff --git a/src/coins.ts b/src/coins.ts index e21c1450..50757785 100644 --- a/src/coins.ts +++ b/src/coins.ts @@ -1884,7 +1884,7 @@ export const wrappedTokens: { [ChainId: string]: StaticToken } = { coinKey: 'WBNB' as CoinKey, name: 'WBNB', logoURI: - 'https://zapper.fi/images/networks/binance-smart-chain/0x0000000000000000000000000000000000000000.png', + 'https://static.debank.com/image/coin/logo_url/bnb/9784283a36f23a58982fc964574ea530.png', }, [ChainId.LNAT]: { // https://explorer.prealpha.zkevm.consensys.net/address/0x2C1b868d6596a18e32E61B901E4060C872647b6C diff --git a/test/coins.logo.test.ts b/test/coins.logo.test.ts index 7117baec..3bfb5633 100644 --- a/test/coins.logo.test.ts +++ b/test/coins.logo.test.ts @@ -1,20 +1,31 @@ -import axios from "axios" -import { defaultCoins } from "../src" +import { expect, test } from '@jest/globals' +import './matchers' +import { defaultCoins, wrappedTokens } from "../src" jest.setTimeout(20_000) describe('Coin logo test', () => { - test.each(defaultCoins)( - 'that the links for logoURI are working', async (coin) => { - const baseURL = coin.logoURI - const tokenSpecificURLs = Object.values(coin.chains).flatMap(({ logoURI }) => logoURI ? [logoURI] : []) - const failing: string[] = [] - await Promise.allSettled([...new Set([ - baseURL, - ...tokenSpecificURLs - ])] - .map(url => axios.get(url).catch(_ => failing.push(url)))) - expect(failing).toHaveLength(0) - } - ) -}) \ No newline at end of file + const allImages : string[] = [] + + // default coins + allImages.push( + ...defaultCoins.map((coin) => { + const baseURL = coin.logoURI + const tokenSpecificURLs = Object.values(coin.chains).flatMap(({ logoURI }) => logoURI ? [logoURI] : []) + return [ + baseURL, + ...tokenSpecificURLs + ] + }).flat() + ) + + // wrapped tokens + allImages.push( + ...Object.values(wrappedTokens).map((token: any) => token.logoURI) + ) + + test.each([...new Set(allImages)])('that the links for logoURI are working', async (image) => { + expect(image).httpsUrl() + await expect(image).canGetUrl() + }) +}) diff --git a/test/matchers.ts b/test/matchers.ts new file mode 100644 index 00000000..6169195a --- /dev/null +++ b/test/matchers.ts @@ -0,0 +1,76 @@ +import axios from 'axios' +import type { MatcherFunction } from 'expect' + +const httpsUrl: MatcherFunction<[url: unknown]> = function (url) { + if (typeof url !== 'string') { + throw new Error('Url must be of type string!') + } + + if (url.startsWith('https://')) { + return { + message: () => `Url ${url} is a secure https url`, + pass: true + } + } else { + return { + message: () => `Url ${url} is not a secure https url`, + pass: false + } + } +} + +const endsWith: MatcherFunction<[value: unknown, check: unknown]> = function (value, check) { + if (typeof value !== 'string') { + throw new Error('Passed value must be of type string!') + } + if (typeof check !== 'string') { + throw new Error('Passed check must be of type string!') + } + + if (value.endsWith(check)) { + return { + message: () => `Value ${value} ends with ${check}`, + pass: true + } + } else { + return { + message: () => `Value ${value} does not end with ${check}`, + pass: false + } + } +} + +const canGetUrl: MatcherFunction<[value: unknown, check: unknown]> = async function (url) { + if (typeof url !== 'string') { + throw new Error('Url must be of type string!') + } + + return axios.get(url) + .then(() => ({ + message: () => `Was able to get ${url}`, + pass: true + })) + .catch(() => ({ + message: () => `Not able to GET url: ${url}`, + pass: false + })) +} + +expect.extend({ + httpsUrl, + endsWith, + canGetUrl, +}) + +declare module 'expect' { + interface AsymmetricMatchers { + httpsUrl(): void + endsWith(check: string): void + canGetUrl(): Promise + } + interface Matchers { + httpsUrl(): R + endsWith(check: string): R + canGetUrl(): Promise + } +} diff --git a/test/types.unit.test.ts b/test/types.unit.test.ts index 5009a60e..7ae79e4f 100644 --- a/test/types.unit.test.ts +++ b/test/types.unit.test.ts @@ -1,4 +1,7 @@ -import { ChainId, ChainKey, getChainByKey, getChainById, supportedEVMChains, findDefaultToken, findWrappedGasOnChain, CoinKey } from '../src' +import { expect, test } from '@jest/globals' +import './matchers' + +import { ChainId, ChainKey, getChainByKey, getChainById, supportedEVMChains, findDefaultToken, findWrappedGasOnChain, CoinKey, prefixChainId } from '../src' import { findTokenByChainIdAndAddress } from '../src/coins'; test('getChainById', () => { expect(getChainById(ChainId.ETH)).toBeDefined() @@ -64,4 +67,23 @@ describe('findTokenByChainIdAndAddress', () => { ).toEqual('Goerli CXTT') }) }) -}) \ No newline at end of file +}) + +describe('validate chains', () => { + supportedEVMChains.forEach(chain => { + it(`validate chain ${chain.name}`, () => { + // blockExplorerUrls + expect(chain.metamask.blockExplorerUrls.length).toBeGreaterThan(0) + chain.metamask.blockExplorerUrls.forEach(blockExplorerUrl => { + expect(blockExplorerUrl).httpsUrl() + expect(blockExplorerUrl).endsWith('/') + }) + + // chain ids match + expect(prefixChainId(chain.id)).toEqual(chain.metamask.chainId) + + // rpcs defined + expect(chain.metamask.rpcUrls.length).toBeGreaterThan(0) + }) + }) +})