diff --git a/web/e.cash/data/__mocks__/scoresMock.js b/web/e.cash/data/__mocks__/scoresMock.js --- a/web/e.cash/data/__mocks__/scoresMock.js +++ b/web/e.cash/data/__mocks__/scoresMock.js @@ -7084,397 +7084,6 @@ }, score: 60, }, - { - id: 35, - name: 'HitBTC', - published_at: '2022-11-11T06:40:56.000Z', - created_at: '2022-02-15T23:48:16.000Z', - updated_at: '2022-11-21T23:29:30.000Z', - ecash_brand: true, - decimal_places: 0, - ecash_deposit_address_format: false, - url: 'https://hitbtc.com/xec-to-usdt', - deposits_working: true, - withdrawals_working: true, - deposit_confirmations: 10, - trading_pairs: ['BTC', 'USDT'], - withdrawal_fee: 150000, - xec_withdrawal_fee: null, - quirks_issues: null, - withdrawal_fee_currency: 'XEC', - fiat_deposit_options: [''], - logo: { - id: 31, - name: 'hitbtc.png', - alternativeText: '', - caption: '', - width: 400, - height: 184, - formats: { - thumbnail: { - name: 'thumbnail_hitbtc.png', - hash: 'thumbnail_hitbtc_7016491270', - ext: '.png', - mime: 'image/png', - width: 245, - height: 113, - size: 9.34, - path: null, - url: '/uploads/thumbnail_hitbtc_7016491270.png', - }, - }, - hash: 'hitbtc_7016491270', - ext: '.png', - mime: 'image/png', - size: 10.19, - url: '/uploads/hitbtc_7016491270.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:51.000Z', - updated_at: '2022-02-10T21:24:51.000Z', - }, - score: 50, - }, - { - id: 23, - name: 'Ascendex', - published_at: '2022-02-15T23:26:01.000Z', - created_at: '2022-02-15T23:25:59.000Z', - updated_at: '2022-10-21T08:13:43.000Z', - ecash_brand: true, - decimal_places: 0, - ecash_deposit_address_format: false, - url: 'https://ascendex.com/en/cashtrade-spottrading/usdt/xec', - deposits_working: true, - withdrawals_working: true, - deposit_confirmations: 15, - trading_pairs: ['USDT'], - withdrawal_fee: 10000, - xec_withdrawal_fee: null, - quirks_issues: null, - withdrawal_fee_currency: 'XEC', - fiat_deposit_options: [ - 'AED', - 'ARS', - 'AUD', - 'AZN', - 'BGN', - 'BRL', - 'CAD', - 'CHF', - 'CLP', - 'COP', - 'CRC', - 'CZK', - 'DKK', - 'DOP', - 'EGP', - 'EUR', - 'GBP', - 'GEL', - 'GHS', - 'HKD', - 'HRK', - 'HUF', - 'IDR', - 'ILS', - 'INR', - 'JOD', - 'JPY', - 'KES', - 'KRW', - 'KWD', - 'KZT', - 'LKR', - 'MDL', - 'MXN', - 'MYR', - 'NAD', - 'NGN', - 'NOK', - 'NZD', - 'OMR', - 'PEN', - 'PHP', - 'PKR', - 'PLN', - 'QAR', - 'RON', - 'RUB', - 'SAR', - 'SEK', - 'SGD', - 'THB', - 'TRY', - 'TWD', - 'TZS', - 'UAH', - 'UGX', - 'USD', - 'UYU', - 'UZS', - 'VND', - 'ZAR', - ], - logo: { - id: 5, - name: 'ascendex.png', - alternativeText: '', - caption: '', - width: 500, - height: 100, - formats: { - thumbnail: { - name: 'thumbnail_ascendex.png', - hash: 'thumbnail_ascendex_68ea0e377c', - ext: '.png', - mime: 'image/png', - width: 245, - height: 49, - size: 5.81, - path: null, - url: '/uploads/thumbnail_ascendex_68ea0e377c.png', - }, - }, - hash: 'ascendex_68ea0e377c', - ext: '.png', - mime: 'image/png', - size: 4.92, - url: '/uploads/ascendex_68ea0e377c.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:49.000Z', - updated_at: '2022-10-21T08:15:24.000Z', - }, - score: 40, - }, - { - id: 34, - name: 'Bybit', - published_at: '2022-02-15T23:47:02.000Z', - created_at: '2022-02-15T23:47:00.000Z', - updated_at: '2022-10-21T08:22:39.000Z', - ecash_brand: true, - decimal_places: 1, - ecash_deposit_address_format: false, - url: 'https://www.bybit.com/trade/spot/XEC/USDT', - deposits_working: true, - withdrawals_working: true, - deposit_confirmations: 60, - trading_pairs: ['USDT'], - withdrawal_fee: 10000, - xec_withdrawal_fee: null, - quirks_issues: null, - withdrawal_fee_currency: 'XEC', - fiat_deposit_options: [''], - logo: { - id: 18, - name: 'bybit.png', - alternativeText: 'Bybit', - caption: '', - width: 767, - height: 266, - formats: { - thumbnail: { - name: 'thumbnail_bybit.png', - hash: 'thumbnail_bybit_303e7734d1', - ext: '.png', - mime: 'image/png', - width: 245, - height: 85, - size: 4.97, - path: null, - url: '/uploads/thumbnail_bybit_303e7734d1.png', - }, - medium: { - name: 'medium_bybit.png', - hash: 'medium_bybit_303e7734d1', - ext: '.png', - mime: 'image/png', - width: 750, - height: 260, - size: 16.96, - path: null, - url: '/uploads/medium_bybit_303e7734d1.png', - }, - small: { - name: 'small_bybit.png', - hash: 'small_bybit_303e7734d1', - ext: '.png', - mime: 'image/png', - width: 500, - height: 173, - size: 10.32, - path: null, - url: '/uploads/small_bybit_303e7734d1.png', - }, - }, - hash: 'bybit_303e7734d1', - ext: '.png', - mime: 'image/png', - size: 3.66, - url: '/uploads/bybit_303e7734d1.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:50.000Z', - updated_at: '2022-10-21T08:22:33.000Z', - }, - score: 40, - }, - { - id: 40, - name: 'Hotcoin', - published_at: '2022-09-17T01:55:47.000Z', - created_at: '2022-06-23T05:44:32.000Z', - updated_at: '2022-11-18T21:33:12.000Z', - ecash_brand: true, - decimal_places: 0, - ecash_deposit_address_format: true, - url: 'https://www.hotcoin.com/currencyExchange/xec_usdt', - deposits_working: false, - withdrawals_working: false, - deposit_confirmations: 11, - trading_pairs: ['USDT'], - withdrawal_fee: null, - xec_withdrawal_fee: null, - quirks_issues: null, - withdrawal_fee_currency: 'XEC', - fiat_deposit_options: [ - 'CNY', - 'USD', - 'EUR', - 'GBP', - 'AED', - 'AMD', - 'ARS', - 'AUD', - 'BDT', - 'BHD', - 'BND', - 'BOB', - 'RSL', - 'CAD', - 'CLP', - 'COP', - 'DOP', - 'EGP', - 'GHS', - 'HKD', - 'IDR', - 'INR', - 'JPY', - 'KES', - 'KHR', - 'KWD', - 'KZT', - 'LAK', - 'LKR', - 'MAD', - 'MMK', - 'MNT', - 'MXN', - 'NGN', - 'NPR', - 'PAB', - 'PEN', - 'PHP', - 'PKR', - 'PLN', - 'PYG', - 'RON', - 'RUB', - 'VND', - 'THB', - 'TRY', - ], - logo: { - id: 78, - name: 'hotcoin logo-1.png', - alternativeText: 'Hotcoin', - caption: '', - width: 334, - height: 50, - formats: { - thumbnail: { - name: 'thumbnail_hotcoin logo-1.png', - hash: 'thumbnail_hotcoin_logo_1_7cd6c68edc', - ext: '.png', - mime: 'image/png', - width: 245, - height: 37, - size: 5.14, - path: null, - url: '/uploads/thumbnail_hotcoin_logo_1_7cd6c68edc.png', - }, - }, - hash: 'hotcoin_logo_1_7cd6c68edc', - ext: '.png', - mime: 'image/png', - size: 3.63, - url: '/uploads/hotcoin_logo_1_7cd6c68edc.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-09-17T01:00:35.000Z', - updated_at: '2022-11-18T21:33:09.000Z', - }, - score: 20, - }, - { - id: 45, - name: 'XT.com', - published_at: '2022-11-30T20:14:13.000Z', - created_at: '2022-11-29T06:28:27.000Z', - updated_at: '2022-11-30T20:14:13.000Z', - ecash_brand: true, - decimal_places: 0, - ecash_deposit_address_format: null, - url: 'https://www.xt.com/tradePro/xec_usdt', - deposits_working: false, - withdrawals_working: false, - deposit_confirmations: null, - trading_pairs: ['USDT'], - withdrawal_fee: null, - xec_withdrawal_fee: null, - quirks_issues: null, - withdrawal_fee_currency: 'XEC', - fiat_deposit_options: [''], - logo: { - id: 92, - name: 'xt_com_logo-freelogovectors.net_.png', - alternativeText: '', - caption: '', - width: 320, - height: 92, - formats: { - thumbnail: { - name: 'thumbnail_xt_com_logo-freelogovectors.net_.png', - hash: 'thumbnail_xt_com_logo_freelogovectors_net_274dddb9b6', - ext: '.png', - mime: 'image/png', - width: 245, - height: 70, - size: 7.3, - path: null, - url: '/uploads/thumbnail_xt_com_logo_freelogovectors_net_274dddb9b6.png', - }, - }, - hash: 'xt_com_logo_freelogovectors_net_274dddb9b6', - ext: '.png', - mime: 'image/png', - size: 7.65, - url: '/uploads/xt_com_logo_freelogovectors_net_274dddb9b6.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-11-29T06:34:39.000Z', - updated_at: '2022-11-29T06:34:39.000Z', - }, - score: 0, - }, ]; export const sortedMockInstantExchanges = [ @@ -7846,54 +7455,6 @@ ], score: 70, }, - { - id: 3, - name: 'SimpleSwap', - published_at: '2022-02-16T03:32:23.000Z', - created_at: '2022-02-16T03:32:18.000Z', - updated_at: '2022-10-21T11:12:58.000Z', - trading_open: true, - ecash_brand: true, - ecash_address_format: null, - deposit_confirmations: 11, - decimal_place: 8, - ecash_deposit_address_format: false, - url: 'https://simpleswap.io/?to=xec', - logo: [ - { - id: 49, - name: 'simpleswap.png', - alternativeText: 'SimpleSwap', - caption: '', - width: 400, - height: 77, - formats: { - thumbnail: { - name: 'thumbnail_simpleswap.png', - hash: 'thumbnail_simpleswap_5e3be28a36', - ext: '.png', - mime: 'image/png', - width: 245, - height: 47, - size: 6.38, - path: null, - url: '/uploads/thumbnail_simpleswap_5e3be28a36.png', - }, - }, - hash: 'simpleswap_5e3be28a36', - ext: '.png', - mime: 'image/png', - size: 3.11, - url: '/uploads/simpleswap_5e3be28a36.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:52.000Z', - updated_at: '2022-10-21T11:12:56.000Z', - }, - ], - score: 40, - }, ]; export const sortedMockServices = [ @@ -8702,98 +8263,4 @@ ], score: 70, }, - { - id: 9, - name: 'CoinCap.io', - url: 'https://coincap.io/assets/ecash', - ecash_brand: true, - ecash_address_format: true, - decimal_place: null, - issues: 'Missing key exchange trading pairs (Upbit, Bithumb, etc).', - published_at: '2022-02-16T19:21:34.000Z', - created_at: '2022-02-16T19:21:33.000Z', - updated_at: '2022-10-21T11:10:43.000Z', - fiat_deposit_options: [''], - logo: [ - { - id: 20, - name: 'coincap-io.png', - alternativeText: 'CoinCap', - caption: '', - width: 500, - height: 219, - formats: { - thumbnail: { - name: 'thumbnail_coincap-io.png', - hash: 'thumbnail_coincap_io_5bbe710c86', - ext: '.png', - mime: 'image/png', - width: 245, - height: 107, - size: 7.07, - path: null, - url: '/uploads/thumbnail_coincap_io_5bbe710c86.png', - }, - }, - hash: 'coincap_io_5bbe710c86', - ext: '.png', - mime: 'image/png', - size: 4.4, - url: '/uploads/coincap_io_5bbe710c86.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:51.000Z', - updated_at: '2022-10-21T11:10:42.000Z', - }, - ], - score: 40, - }, - { - id: 10, - name: 'Matrixport', - url: 'https://www.matrixport.com/en', - ecash_brand: true, - ecash_address_format: false, - decimal_place: 2, - issues: 'No proper eCash services (only supporting deposit and withdrawal) and a high withdrawal fee of 10,000 bits (XEC).', - published_at: '2022-02-16T19:26:32.000Z', - created_at: '2022-02-16T19:26:30.000Z', - updated_at: '2022-02-18T21:39:29.000Z', - fiat_deposit_options: null, - logo: [ - { - id: 44, - name: 'matrixport.png', - alternativeText: '', - caption: '', - width: 400, - height: 83, - formats: { - thumbnail: { - name: 'thumbnail_matrixport.png', - hash: 'thumbnail_matrixport_b76e44ecb7', - ext: '.png', - mime: 'image/png', - width: 245, - height: 51, - size: 5.57, - path: null, - url: '/uploads/thumbnail_matrixport_b76e44ecb7.png', - }, - }, - hash: 'matrixport_b76e44ecb7', - ext: '.png', - mime: 'image/png', - size: 5.33, - url: '/uploads/matrixport_b76e44ecb7.png', - previewUrl: null, - provider: 'local', - provider_metadata: null, - created_at: '2022-02-10T21:24:52.000Z', - updated_at: '2022-02-10T21:24:52.000Z', - }, - ], - score: 30, - }, ]; diff --git a/web/e.cash/data/__tests__/scores.test.js b/web/e.cash/data/__tests__/scores.test.js --- a/web/e.cash/data/__tests__/scores.test.js +++ b/web/e.cash/data/__tests__/scores.test.js @@ -43,17 +43,73 @@ }); describe('sortExchanges', () => { - it('should sort a given array of exchange objects by name, then deposit confirmations, then score', () => { - const exchangesResult = sortExchanges(scoredMockExchanges); - expect(exchangesResult).toEqual(sortedMockExchanges); - - const instantExchangesResult = sortExchanges( - scoredMockInstantExchanges, - ); - expect(instantExchangesResult).toEqual(sortedMockInstantExchanges); - - const servicesResult = sortExchanges(scoredMockServices); - expect(servicesResult).toEqual(sortedMockServices); + it('should sort a given array of exchange objects by name, then deposit confirmations, then score. Then will filter out any items with scores below the scoreThreshold or with invalid scores', () => { + const testCases = [ + { scoreThreshold: -45, resultSlice: 5 }, + { scoreThreshold: 0, resultSlice: 5 }, + { scoreThreshold: 40.01, resultSlice: 4 }, + { scoreThreshold: 70, resultSlice: 3 }, + { scoreThreshold: 100, resultSlice: 1 }, + ]; + const exchangesMock = [ + { + name: 'Exchange_A', + deposit_confirmations: 1, + score: 100, + }, + { + name: 'Exchange_C', + deposit_confirmations: 1, + score: 80, + }, + { + name: 'Exchange_B', + deposit_confirmations: 3, + score: 80, + }, + { + name: 'Exchange_D', + deposit_confirmations: 3, + score: 40.453, + }, + { + name: 'Exchange_E', + deposit_confirmations: 6, + score: 0, + }, + { + name: 'Exchange_F', + deposit_confirmations: 6, + score: -10, + }, + { + name: 'Exchange_G', + score: null, + }, + { + name: 'Exchange_H', + score: undefined, + }, + { + name: 'Exchange_I', + }, + ]; + const shuffleArray = array => { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; + }; + for (let i = 0; i < testCases.length; i++) { + const result = sortExchanges( + shuffleArray(exchangesMock), + testCases[i].scoreThreshold, + ); + expect(result).toEqual( + exchangesMock.slice(0, testCases[i].resultSlice), + ); + } }); }); @@ -152,7 +208,7 @@ .mockResolvedValueOnce({ json: () => Promise.resolve(mockInstantExchanges), }) // Mock an empty object response - .mockResolvedValueOnce({ json: () => Promise.resolve([]) }); //empty array for example + .mockResolvedValueOnce({ json: () => Promise.resolve(undefined) }); //undefined for example await expect(getScoreCardData()).rejects.toThrow( "TypeError: Cannot read properties of undefined (reading 'length')", diff --git a/web/e.cash/data/scores.js b/web/e.cash/data/scores.js --- a/web/e.cash/data/scores.js +++ b/web/e.cash/data/scores.js @@ -15,7 +15,12 @@ * * The two special cases are trading_pairs, just requires a min number * And issues, which does not require a value to check against + * + * The scoreThreshold is the minimum score an item must meet */ + +const scoreThreshold = 60; + export const exchangeScoringCriteria = [ { attribute: 'withdrawals_working', @@ -148,15 +153,26 @@ }; /** - * Return a sorted array based on name, score, and deposit confimations + * Return a sorted array based on name, deposit confimations, and score * @param {array} data - The array of data + * @param {number} scoreThreshold - The minimum score required to not be filtered out * @returns {array} The same array, sorted alphabetically, then by deposit - * confirmations, then by score + * confirmations, then by score, and then removing items with scores below the + * threshold or invalid score values. Scoring is the primary sort */ -export const sortExchanges = data => { +export const sortExchanges = (data, scoreThreshold) => { data.sort((a, b) => a.name.localeCompare(b.name)); data.sort((a, b) => a.deposit_confirmations - b.deposit_confirmations); data.sort((a, b) => b.score - a.score); + + // Filter out items with a score below the scoreThreshold + data = data.filter( + item => + item.score >= scoreThreshold && + item.score !== undefined && + item.score !== null && + item.score >= 0, + ); return data; }; @@ -201,16 +217,19 @@ exchanges: makeDivisibleByThree( sortExchanges( getScores(responses[0], exchangeScoringCriteria), + scoreThreshold, ), ), instantExchanges: makeDivisibleByThree( sortExchanges( getScores(responses[1], instantExchangeScoringCriteria), + scoreThreshold, ), ), services: makeDivisibleByThree( sortExchanges( getScores(responses[2], servicesScoringCriteria), + scoreThreshold, ), ), },