mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Handle provider error & showing Retry button (#1770)
* adding error handling for button onCLick * Updating butoon to show retry & updating toast message * Logging provider error * Removing unused imports * Using early return when provider fees are present to prevent unneccessary nesting * Adding retry logic for compute * Removing duplicate teast message * Adding tests for rendering Buy button * Additional tests for BuyButton * Refactoring BuyButton tests for download * Fix failing tests * Refactoring compute tests * Refactoring tests Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
parent
4b4a926f89
commit
4ff84b0871
@ -8,7 +8,8 @@ import {
|
||||
OrderParams,
|
||||
ProviderComputeInitialize,
|
||||
ProviderFees,
|
||||
ProviderInstance
|
||||
ProviderInstance,
|
||||
ProviderInitialize
|
||||
} from '@oceanprotocol/lib'
|
||||
import Web3 from 'web3'
|
||||
import { getOceanConfig } from './ocean'
|
||||
@ -20,6 +21,26 @@ import {
|
||||
} from '../../app.config'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
async function initializeProvider(
|
||||
asset: AssetExtended,
|
||||
accountId: string,
|
||||
providerFees?: ProviderFees
|
||||
): Promise<ProviderInitialize> {
|
||||
if (providerFees) return
|
||||
try {
|
||||
const provider = await ProviderInstance.initialize(
|
||||
asset.id,
|
||||
asset.services[0].id,
|
||||
0,
|
||||
accountId,
|
||||
asset.services[0].serviceEndpoint
|
||||
)
|
||||
return provider
|
||||
} catch (error) {
|
||||
LoggerInstance.log('[Initialize Provider] Error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param web3
|
||||
* @param asset
|
||||
@ -40,15 +61,11 @@ export async function order(
|
||||
const datatoken = new Datatoken(web3)
|
||||
const config = getOceanConfig(asset.chainId)
|
||||
|
||||
const initializeData =
|
||||
!providerFees &&
|
||||
(await ProviderInstance.initialize(
|
||||
asset.id,
|
||||
asset.services[0].id,
|
||||
0,
|
||||
const initializeData = await initializeProvider(
|
||||
asset,
|
||||
accountId,
|
||||
asset.services[0].serviceEndpoint
|
||||
))
|
||||
providerFees
|
||||
)
|
||||
|
||||
const orderParams = {
|
||||
consumer: computeConsumerAddress || accountId,
|
||||
@ -130,15 +147,11 @@ export async function reuseOrder(
|
||||
providerFees?: ProviderFees
|
||||
): Promise<TransactionReceipt> {
|
||||
const datatoken = new Datatoken(web3)
|
||||
const initializeData =
|
||||
!providerFees &&
|
||||
(await ProviderInstance.initialize(
|
||||
asset.id,
|
||||
asset.services[0].id,
|
||||
0,
|
||||
const initializeData = await initializeProvider(
|
||||
asset,
|
||||
accountId,
|
||||
asset.services[0].serviceEndpoint
|
||||
))
|
||||
providerFees
|
||||
)
|
||||
|
||||
const tx = await datatoken.reuseOrder(
|
||||
asset.accessDetails.datatoken.address,
|
||||
|
143
src/components/Asset/AssetActions/ButtonBuy/index.test.tsx
Normal file
143
src/components/Asset/AssetActions/ButtonBuy/index.test.tsx
Normal file
@ -0,0 +1,143 @@
|
||||
import React from 'react'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import ButtonBuy, { ButtonBuyProps } from './'
|
||||
|
||||
const downloadProps: ButtonBuyProps = {
|
||||
action: 'download',
|
||||
disabled: false,
|
||||
hasPreviousOrder: false,
|
||||
hasDatatoken: false,
|
||||
btSymbol: 'btSymbol',
|
||||
dtSymbol: 'dtSymbol',
|
||||
dtBalance: '100000000000',
|
||||
assetTimeout: '1 day',
|
||||
assetType: 'Dataset',
|
||||
stepText: 'TEST',
|
||||
priceType: 'fixed',
|
||||
isConsumable: true,
|
||||
isBalanceSufficient: true,
|
||||
consumableFeedback: 'TEST: consumableFeedback'
|
||||
}
|
||||
|
||||
const computeProps: ButtonBuyProps = {
|
||||
action: 'compute',
|
||||
disabled: false,
|
||||
hasPreviousOrder: false,
|
||||
hasDatatoken: true,
|
||||
btSymbol: 'btSymbol',
|
||||
dtSymbol: 'dtSymbol',
|
||||
dtBalance: '100000000000',
|
||||
assetTimeout: '1 day',
|
||||
assetType: 'algorithm',
|
||||
hasPreviousOrderSelectedComputeAsset: false,
|
||||
hasDatatokenSelectedComputeAsset: true,
|
||||
dtSymbolSelectedComputeAsset: 'dtSymbol',
|
||||
dtBalanceSelectedComputeAsset: 'dtBalance',
|
||||
selectedComputeAssetType: 'selectedComputeAssetType',
|
||||
stepText: ' ',
|
||||
isLoading: false,
|
||||
type: 'submit',
|
||||
priceType: 'fixed',
|
||||
algorithmPriceType: 'free',
|
||||
isBalanceSufficient: true,
|
||||
isConsumable: true,
|
||||
consumableFeedback: 'consumableFeedback',
|
||||
isAlgorithmConsumable: true,
|
||||
hasProviderFee: false,
|
||||
retry: false
|
||||
}
|
||||
|
||||
describe('Asset/AssetActions/ButtonBuy', () => {
|
||||
// TESTS FOR LOADING
|
||||
it('Renders Buy button without crashing', () => {
|
||||
render(<ButtonBuy {...downloadProps} isLoading />)
|
||||
const button = screen.getByText('TEST')
|
||||
expect(button).toContainHTML('<Loader')
|
||||
})
|
||||
|
||||
// TESTS FOR DOWNLOAD
|
||||
it('Renders Buy button without crashing', () => {
|
||||
render(<ButtonBuy {...downloadProps} />)
|
||||
const button = screen.getByText('Buy for 1 day')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders Buy button without crashing when hasPreviousOrder=true', () => {
|
||||
render(<ButtonBuy {...downloadProps} hasPreviousOrder />)
|
||||
const button = screen.getByText('Download')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders retry button for download without crashing', () => {
|
||||
render(<ButtonBuy {...downloadProps} retry />)
|
||||
const button = screen.getByText('Retry')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders get button for free download without crashing', () => {
|
||||
render(<ButtonBuy {...downloadProps} priceType="free" hasPreviousOrder />)
|
||||
const button = screen.getByText('Download')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "Get" button for free assets without crashing', () => {
|
||||
render(<ButtonBuy {...downloadProps} priceType="free" />)
|
||||
const button = screen.getByText('Get')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders Buy button without crashing', () => {
|
||||
render(
|
||||
<ButtonBuy
|
||||
{...downloadProps}
|
||||
assetTimeout="Forever"
|
||||
isConsumable={false}
|
||||
/>
|
||||
)
|
||||
const button = screen.getByText('Buy')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
// TESTS FOR COMPUTE
|
||||
it('Renders "Buy Compute Job" button for compute without crashing', () => {
|
||||
render(<ButtonBuy {...computeProps} />)
|
||||
const button = screen.getByText('Buy Compute Job')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "Buy Compute Job" button for compute without crashing', () => {
|
||||
render(<ButtonBuy {...computeProps} hasDatatokenSelectedComputeAsset />)
|
||||
const button = screen.getByText('Buy Compute Job')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "Start Compute Job" button', () => {
|
||||
render(
|
||||
<ButtonBuy
|
||||
{...computeProps}
|
||||
hasPreviousOrder
|
||||
hasPreviousOrderSelectedComputeAsset
|
||||
/>
|
||||
)
|
||||
const button = screen.getByText('Start Compute Job')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "Order Compute Job" button', () => {
|
||||
render(<ButtonBuy {...computeProps} priceType="free" hasProviderFee />)
|
||||
const button = screen.getByText('Order Compute Job')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "Order Compute Job" button', () => {
|
||||
render(<ButtonBuy {...computeProps} priceType="free" hasProviderFee />)
|
||||
const button = screen.getByText('Order Compute Job')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
|
||||
it('Renders "retry" button for compute without crashing', () => {
|
||||
render(<ButtonBuy {...computeProps} retry />)
|
||||
const button = screen.getByText('Retry')
|
||||
expect(button).toContainHTML('<button')
|
||||
})
|
||||
})
|
@ -3,7 +3,7 @@ import Button from '../../../@shared/atoms/Button'
|
||||
import styles from './index.module.css'
|
||||
import Loader from '../../../@shared/atoms/Loader'
|
||||
|
||||
interface ButtonBuyProps {
|
||||
export interface ButtonBuyProps {
|
||||
action: 'download' | 'compute'
|
||||
disabled: boolean
|
||||
hasPreviousOrder: boolean
|
||||
@ -29,6 +29,7 @@ interface ButtonBuyProps {
|
||||
algorithmPriceType?: string
|
||||
isAlgorithmConsumable?: boolean
|
||||
hasProviderFee?: boolean
|
||||
retry?: boolean
|
||||
}
|
||||
|
||||
// TODO: we need to take a look at these messages
|
||||
@ -131,10 +132,12 @@ export default function ButtonBuy({
|
||||
priceType,
|
||||
algorithmPriceType,
|
||||
isAlgorithmConsumable,
|
||||
hasProviderFee
|
||||
hasProviderFee,
|
||||
retry
|
||||
}: ButtonBuyProps): ReactElement {
|
||||
const buttonText =
|
||||
action === 'download'
|
||||
const buttonText = retry
|
||||
? 'Retry'
|
||||
: action === 'download'
|
||||
? hasPreviousOrder
|
||||
? 'Download'
|
||||
: priceType === 'free'
|
||||
|
@ -43,7 +43,8 @@ export default function FormStartCompute({
|
||||
datasetOrderPriceAndFees,
|
||||
algoOrderPriceAndFees,
|
||||
providerFeeAmount,
|
||||
validUntil
|
||||
validUntil,
|
||||
retry
|
||||
}: {
|
||||
algorithms: AssetSelectionAsset[]
|
||||
ddoListAlgorithms: Asset[]
|
||||
@ -71,6 +72,7 @@ export default function FormStartCompute({
|
||||
algoOrderPriceAndFees?: OrderPriceAndFees
|
||||
providerFeeAmount?: string
|
||||
validUntil?: string
|
||||
retry: boolean
|
||||
}): ReactElement {
|
||||
const { siteContent } = useMarketMetadata()
|
||||
const { accountId, balance } = useWeb3()
|
||||
@ -294,6 +296,7 @@ export default function FormStartCompute({
|
||||
selectedAlgorithmAsset?.accessDetails?.isPurchasable
|
||||
}
|
||||
hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'}
|
||||
retry={retry}
|
||||
/>
|
||||
</Form>
|
||||
)
|
||||
|
@ -97,6 +97,7 @@ export default function Compute({
|
||||
const [refetchJobs, setRefetchJobs] = useState(false)
|
||||
const [isLoadingJobs, setIsLoadingJobs] = useState(false)
|
||||
const [jobs, setJobs] = useState<ComputeJobMetaData[]>([])
|
||||
const [retry, setRetry] = useState<boolean>(false)
|
||||
|
||||
const hasDatatoken = Number(dtBalance) >= 1
|
||||
const isComputeButtonDisabled =
|
||||
@ -291,7 +292,8 @@ export default function Compute({
|
||||
useEffect(() => {
|
||||
const newError = error
|
||||
if (!newError) return
|
||||
toast.error(newError)
|
||||
const errorMsg = newError + '. Please retry.'
|
||||
toast.error(errorMsg)
|
||||
}, [error])
|
||||
|
||||
async function startJob(): Promise<void> {
|
||||
@ -386,6 +388,7 @@ export default function Compute({
|
||||
initPriceAndFees()
|
||||
} catch (error) {
|
||||
setError(error.message)
|
||||
setRetry(true)
|
||||
LoggerInstance.error(`[compute] ${error.message} `)
|
||||
} finally {
|
||||
setIsOrdering(false)
|
||||
@ -477,6 +480,7 @@ export default function Compute({
|
||||
algoOrderPriceAndFees={algoOrderPriceAndFees}
|
||||
providerFeeAmount={providerFeeAmount}
|
||||
validUntil={computeValidUntil}
|
||||
retry={retry}
|
||||
/>
|
||||
</Formik>
|
||||
)}
|
||||
|
@ -48,6 +48,7 @@ export default function Download({
|
||||
const [isOrderDisabled, setIsOrderDisabled] = useState(false)
|
||||
const [orderPriceAndFees, setOrderPriceAndFees] =
|
||||
useState<OrderPriceAndFees>()
|
||||
const [retry, setRetry] = useState<boolean>(false)
|
||||
|
||||
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED'
|
||||
|
||||
@ -155,9 +156,10 @@ export default function Download({
|
||||
}
|
||||
} catch (error) {
|
||||
LoggerInstance.error(error)
|
||||
setRetry(true)
|
||||
const message = isOwned
|
||||
? 'Failed to download file!'
|
||||
: 'An error occurred. Check console for more information.'
|
||||
: 'An error occurred, please retry. Check console for more information.'
|
||||
toast.error(message)
|
||||
}
|
||||
setIsLoading(false)
|
||||
@ -181,6 +183,7 @@ export default function Download({
|
||||
isConsumable={asset.accessDetails?.isPurchasable}
|
||||
isBalanceSufficient={isBalanceSufficient}
|
||||
consumableFeedback={consumableFeedback}
|
||||
retry={retry}
|
||||
/>
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user