mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge pull request #93 from oceanprotocol/feature/publish-feedback
Publish flow changes
This commit is contained in:
commit
93a981e013
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"title": "Publish Data",
|
"title": "Publish",
|
||||||
"description": "Highlight the important features of your data set to make it more discoverable and catch the interest of data consumers.",
|
"description": "Highlight the important features of your data set to make it more discoverable and catch the interest of data consumers.",
|
||||||
"form": {
|
"form": {
|
||||||
"title": "Publish",
|
"title": "Publish",
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -12911,6 +12911,11 @@
|
|||||||
"integrity": "sha512-yfqzAi1GFxK6EoJIZKgxqJyK6j/OjEFEUi2qkNThD/kUhoCFSG1izq31B5xuxzbJBGw9/67uPtkPMYAzWL7L7Q==",
|
"integrity": "sha512-yfqzAi1GFxK6EoJIZKgxqJyK6j/OjEFEUi2qkNThD/kUhoCFSG1izq31B5xuxzbJBGw9/67uPtkPMYAzWL7L7Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"dom-confetti": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-confetti/-/dom-confetti-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-+UVH9Y85qmpTnbmFURwLWjqLIykyIrsNSRkPX/eFlBuOURz9RDX8JoZHnajZHyFuCV0w/K3+tZK0ztfoTw6ejg=="
|
||||||
|
},
|
||||||
"dom-converter": {
|
"dom-converter": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"decimal.js": "^10.2.1",
|
"decimal.js": "^10.2.1",
|
||||||
|
"dom-confetti": "^0.2.2",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
||||||
"filesize": "^6.1.0",
|
"filesize": "^6.1.0",
|
||||||
|
@ -10,14 +10,19 @@ interface TabsItem {
|
|||||||
export default function Tabs({
|
export default function Tabs({
|
||||||
items,
|
items,
|
||||||
className,
|
className,
|
||||||
handleTabChange
|
handleTabChange,
|
||||||
|
defaultIndex
|
||||||
}: {
|
}: {
|
||||||
items: TabsItem[]
|
items: TabsItem[]
|
||||||
className?: string
|
className?: string
|
||||||
handleTabChange?: (tabName: string) => void
|
handleTabChange?: (tabName: string) => void
|
||||||
|
defaultIndex?: number
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<ReactTabs className={`${className && className}`}>
|
<ReactTabs
|
||||||
|
className={`${className && className}`}
|
||||||
|
defaultIndex={defaultIndex}
|
||||||
|
>
|
||||||
<TabList className={styles.tabList}>
|
<TabList className={styles.tabList}>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<Tab
|
<Tab
|
||||||
|
@ -5,7 +5,7 @@ import styles from './index.module.css'
|
|||||||
import Tabs from '../../../atoms/Tabs'
|
import Tabs from '../../../atoms/Tabs'
|
||||||
import Fixed from './Fixed'
|
import Fixed from './Fixed'
|
||||||
import Dynamic from './Dynamic'
|
import Dynamic from './Dynamic'
|
||||||
import { useField } from 'formik'
|
import { useField, useFormikContext } from 'formik'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
||||||
@ -68,8 +68,9 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
helpers.setValue({ ...field.value, tokensToMint })
|
helpers.setValue({ ...field.value, tokensToMint })
|
||||||
}, [price])
|
}, [price])
|
||||||
|
|
||||||
// Generate new DT name & symbol
|
// Generate new DT name & symbol, but only once automatically
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!ocean || typeof field?.value?.datatoken?.name !== 'undefined') return
|
||||||
generateName()
|
generateName()
|
||||||
}, [ocean])
|
}, [ocean])
|
||||||
|
|
||||||
@ -100,7 +101,11 @@ export default function Price(props: InputProps): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.price}>
|
<div className={styles.price}>
|
||||||
<Tabs items={tabs} handleTabChange={handleTabChange} />
|
<Tabs
|
||||||
|
items={tabs}
|
||||||
|
handleTabChange={handleTabChange}
|
||||||
|
defaultIndex={field?.value?.type === 'fixed' ? 0 : 1}
|
||||||
|
/>
|
||||||
{debug === true && (
|
{debug === true && (
|
||||||
<pre>
|
<pre>
|
||||||
<code>{JSON.stringify(field.value, null, 2)}</code>
|
<code>{JSON.stringify(field.value, null, 2)}</code>
|
||||||
|
30
src/components/pages/Publish/Debug.tsx
Normal file
30
src/components/pages/Publish/Debug.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import { MetadataPublishForm } from '../../../@types/MetaData'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
import { transformPublishFormToMetadata } from './utils'
|
||||||
|
|
||||||
|
export default function Debug({
|
||||||
|
values
|
||||||
|
}: {
|
||||||
|
values: Partial<MetadataPublishForm>
|
||||||
|
}): ReactElement {
|
||||||
|
return (
|
||||||
|
<div className={styles.grid}>
|
||||||
|
<div>
|
||||||
|
<h5>Collected Form Values</h5>
|
||||||
|
<pre>
|
||||||
|
<code>{JSON.stringify(values, null, 2)}</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h5>Transformed Values</h5>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
{JSON.stringify(transformPublishFormToMetadata(values), null, 2)}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
40
src/components/pages/Publish/Feedback.module.css
Normal file
40
src/components/pages/Publish/Feedback.module.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
.feedback {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 40vh;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
composes: box from '../../atoms/Box.module.css';
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback h3 {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback h3 + div {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 40rem) {
|
||||||
|
.feedback {
|
||||||
|
max-width: 30rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback [class*='loaderWrap'] {
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action {
|
||||||
|
margin-top: calc(var(--spacer) / 1.5);
|
||||||
|
}
|
45
src/components/pages/Publish/Feedback.tsx
Normal file
45
src/components/pages/Publish/Feedback.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import Alert from '../../atoms/Alert'
|
||||||
|
import Success from './Success'
|
||||||
|
import Button from '../../atoms/Button'
|
||||||
|
import Loader from '../../atoms/Loader'
|
||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import styles from './Feedback.module.css'
|
||||||
|
|
||||||
|
export default function Feedback({
|
||||||
|
error,
|
||||||
|
success,
|
||||||
|
did,
|
||||||
|
publishStepText,
|
||||||
|
setError
|
||||||
|
}: {
|
||||||
|
error: string
|
||||||
|
success: string
|
||||||
|
did: string
|
||||||
|
publishStepText: string
|
||||||
|
setError: (error: string) => void
|
||||||
|
}): ReactElement {
|
||||||
|
return (
|
||||||
|
<div className={styles.feedback}>
|
||||||
|
<div className={styles.box}>
|
||||||
|
<h3>Publishing Data Set</h3>
|
||||||
|
{error ? (
|
||||||
|
<>
|
||||||
|
<Alert text={error} state="error" />
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
size="small"
|
||||||
|
className={styles.action}
|
||||||
|
onClick={() => setError(undefined)}
|
||||||
|
>
|
||||||
|
Try Again
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : success ? (
|
||||||
|
<Success success={success} did={did} />
|
||||||
|
) : (
|
||||||
|
<Loader message={publishStepText} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -5,17 +5,11 @@ import { useFormikContext, Form, Field } from 'formik'
|
|||||||
import Input from '../../atoms/Input'
|
import Input from '../../atoms/Input'
|
||||||
import Button from '../../atoms/Button'
|
import Button from '../../atoms/Button'
|
||||||
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||||
import Loader from '../../atoms/Loader'
|
|
||||||
import { Persist } from '../../atoms/FormikPersist'
|
|
||||||
|
|
||||||
export default function PublishForm({
|
export default function PublishForm({
|
||||||
content,
|
content
|
||||||
publishStepText,
|
|
||||||
isLoading
|
|
||||||
}: {
|
}: {
|
||||||
content: FormContent
|
content: FormContent
|
||||||
publishStepText?: string
|
|
||||||
isLoading: boolean
|
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ocean, account } = useOcean()
|
const { ocean, account } = useOcean()
|
||||||
const {
|
const {
|
||||||
@ -27,7 +21,6 @@ export default function PublishForm({
|
|||||||
resetForm,
|
resetForm,
|
||||||
initialValues
|
initialValues
|
||||||
} = useFormikContext()
|
} = useFormikContext()
|
||||||
const formName = 'ocean-publish-form'
|
|
||||||
|
|
||||||
// reset form validation on every mount
|
// reset form validation on every mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -52,30 +45,22 @@ export default function PublishForm({
|
|||||||
{content.data.map((field: FormFieldProps) => (
|
{content.data.map((field: FormFieldProps) => (
|
||||||
<Field key={field.name} {...field} component={Input} />
|
<Field key={field.name} {...field} component={Input} />
|
||||||
))}
|
))}
|
||||||
{isLoading ? (
|
|
||||||
<Loader message={publishStepText} />
|
|
||||||
) : (
|
|
||||||
<footer className={styles.actions}>
|
|
||||||
<Button
|
|
||||||
style="primary"
|
|
||||||
type="submit"
|
|
||||||
disabled={!ocean || !account || !isValid || status === 'empty'}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{status !== 'empty' && (
|
<footer className={styles.actions}>
|
||||||
<Button
|
<Button
|
||||||
style="text"
|
style="primary"
|
||||||
size="small"
|
type="submit"
|
||||||
onClick={resetFormAndClearStorage}
|
disabled={!ocean || !account || !isValid || status === 'empty'}
|
||||||
>
|
>
|
||||||
Reset Form
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
</footer>
|
{status !== 'empty' && (
|
||||||
)}
|
<Button style="text" size="small" onClick={resetFormAndClearStorage}>
|
||||||
<Persist name={formName} ignoreFields={['isSubmitting']} />
|
Reset Form
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</footer>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
3
src/components/pages/Publish/Success.module.css
Normal file
3
src/components/pages/Publish/Success.module.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.action {
|
||||||
|
margin-top: calc(var(--spacer) / 1.5);
|
||||||
|
}
|
56
src/components/pages/Publish/Success.tsx
Normal file
56
src/components/pages/Publish/Success.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import Alert from '../../atoms/Alert'
|
||||||
|
import Button from '../../atoms/Button'
|
||||||
|
import React, { ReactElement, useEffect } from 'react'
|
||||||
|
import { confetti } from 'dom-confetti'
|
||||||
|
import styles from './Success.module.css'
|
||||||
|
|
||||||
|
const confettiConfig = {
|
||||||
|
angle: 90,
|
||||||
|
spread: 360,
|
||||||
|
startVelocity: 40,
|
||||||
|
elementCount: 70,
|
||||||
|
dragFriction: 0.12,
|
||||||
|
duration: 3000,
|
||||||
|
stagger: 3,
|
||||||
|
width: '10px',
|
||||||
|
height: '10px',
|
||||||
|
perspective: '500px',
|
||||||
|
colors: [
|
||||||
|
'var(--brand-pink)',
|
||||||
|
'var(--brand-purple)',
|
||||||
|
'var(--brand-violet)',
|
||||||
|
'var(--brand-grey-light)',
|
||||||
|
'var(--brand-grey-lighter)'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Success({
|
||||||
|
success,
|
||||||
|
did
|
||||||
|
}: {
|
||||||
|
success: string
|
||||||
|
did: string
|
||||||
|
}): ReactElement {
|
||||||
|
// Have some confetti upon success
|
||||||
|
useEffect(() => {
|
||||||
|
if (!success || typeof window === 'undefined') return
|
||||||
|
|
||||||
|
const startElement: HTMLElement = document.querySelector('a[data-confetti]')
|
||||||
|
confetti(startElement, confettiConfig)
|
||||||
|
}, [success])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Alert text={success} state="success" />
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
size="small"
|
||||||
|
href={`/asset/${did}`}
|
||||||
|
className={styles.action}
|
||||||
|
data-confetti
|
||||||
|
>
|
||||||
|
Go to data set →
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement, useState } from 'react'
|
||||||
import { useNavigate } from '@reach/router'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import { Formik } from 'formik'
|
import { Formik } from 'formik'
|
||||||
import { usePublish } from '@oceanprotocol/react'
|
import { usePublish } from '@oceanprotocol/react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
@ -10,9 +8,14 @@ import { FormContent } from '../../../@types/Form'
|
|||||||
import { initialValues, validationSchema } from '../../../models/FormPublish'
|
import { initialValues, validationSchema } from '../../../models/FormPublish'
|
||||||
import { transformPublishFormToMetadata } from './utils'
|
import { transformPublishFormToMetadata } from './utils'
|
||||||
import Preview from './Preview'
|
import Preview from './Preview'
|
||||||
import { MetadataMarket, MetadataPublishForm } from '../../../@types/MetaData'
|
import { MetadataPublishForm } from '../../../@types/MetaData'
|
||||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||||
import { Logger, Metadata } from '@oceanprotocol/lib'
|
import { Logger, Metadata } from '@oceanprotocol/lib'
|
||||||
|
import { Persist } from '../../atoms/FormikPersist'
|
||||||
|
import Debug from './Debug'
|
||||||
|
import Feedback from './Feedback'
|
||||||
|
|
||||||
|
const formName = 'ocean-publish-form'
|
||||||
|
|
||||||
export default function PublishPage({
|
export default function PublishPage({
|
||||||
content
|
content
|
||||||
@ -21,7 +24,12 @@ export default function PublishPage({
|
|||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||||
const navigate = useNavigate()
|
|
||||||
|
const [success, setSuccess] = useState<string>()
|
||||||
|
const [error, setError] = useState<string>()
|
||||||
|
const [did, setDid] = useState<string>()
|
||||||
|
|
||||||
|
const hasFeedback = isLoading || error || success
|
||||||
|
|
||||||
async function handleSubmit(
|
async function handleSubmit(
|
||||||
values: Partial<MetadataPublishForm>,
|
values: Partial<MetadataPublishForm>,
|
||||||
@ -36,80 +44,70 @@ export default function PublishPage({
|
|||||||
|
|
||||||
const ddo = await publish(
|
const ddo = await publish(
|
||||||
(metadata as unknown) as Metadata,
|
(metadata as unknown) as Metadata,
|
||||||
{
|
{ ...price, swapFee: `${price.swapFee}` },
|
||||||
...price,
|
|
||||||
swapFee: `${price.swapFee}`
|
|
||||||
},
|
|
||||||
serviceType,
|
serviceType,
|
||||||
price.datatoken
|
price.datatoken
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Publish failed
|
||||||
if (publishError) {
|
if (publishError) {
|
||||||
toast.error(publishError) && console.error(publishError)
|
setError(publishError)
|
||||||
return null
|
Logger.error(publishError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// User feedback and redirect to new asset detail page
|
// Publish succeeded
|
||||||
ddo && toast.success('Asset created successfully.') && resetForm()
|
if (ddo) {
|
||||||
// Go to new asset detail page
|
setDid(ddo.id)
|
||||||
navigate(`/asset/${ddo.id}`)
|
setSuccess('🎉 Successfully published your data set. 🎉')
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message)
|
setError(error.message)
|
||||||
toast.error(error.message)
|
Logger.error(error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className={styles.grid}>
|
<Formik
|
||||||
<Formik
|
initialValues={initialValues}
|
||||||
initialValues={initialValues}
|
initialStatus="empty"
|
||||||
initialStatus="empty"
|
validationSchema={validationSchema}
|
||||||
validationSchema={validationSchema}
|
onSubmit={async (values, { setSubmitting, resetForm }) => {
|
||||||
onSubmit={async (values, { setSubmitting, resetForm }) => {
|
// move user's focus to top of screen
|
||||||
await handleSubmit(values, resetForm)
|
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||||
setSubmitting(false)
|
// kick off publishing
|
||||||
}}
|
await handleSubmit(values, resetForm)
|
||||||
>
|
setSubmitting(false)
|
||||||
{({ values }) => (
|
}}
|
||||||
<>
|
>
|
||||||
<PublishForm
|
{({ values }) => (
|
||||||
content={content.form}
|
<>
|
||||||
isLoading={isLoading}
|
<Persist name={formName} ignoreFields={['isSubmitting']} />
|
||||||
|
|
||||||
|
{hasFeedback ? (
|
||||||
|
<Feedback
|
||||||
|
error={error}
|
||||||
|
success={success}
|
||||||
publishStepText={publishStepText}
|
publishStepText={publishStepText}
|
||||||
|
did={did}
|
||||||
|
setError={setError}
|
||||||
/>
|
/>
|
||||||
<aside>
|
) : (
|
||||||
<div className={styles.sticky}>
|
<article className={styles.grid}>
|
||||||
<Preview values={values} />
|
<PublishForm content={content.form} />
|
||||||
<Web3Feedback />
|
<aside>
|
||||||
</div>
|
<div className={styles.sticky}>
|
||||||
</aside>
|
<Preview values={values} />
|
||||||
|
<Web3Feedback />
|
||||||
{debug === true && (
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<h5>Collected Form Values</h5>
|
|
||||||
<pre>
|
|
||||||
<code>{JSON.stringify(values, null, 2)}</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
</div>
|
||||||
|
</aside>
|
||||||
|
</article>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
{debug === true && <Debug values={values} />}
|
||||||
<h5>Transformed Values</h5>
|
</>
|
||||||
<pre>
|
)}
|
||||||
<code>
|
</Formik>
|
||||||
{JSON.stringify(
|
|
||||||
transformPublishFormToMetadata(values),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
</article>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,7 @@ import content from '../../../content/pages/publish.json'
|
|||||||
|
|
||||||
describe('PublishForm', () => {
|
describe('PublishForm', () => {
|
||||||
it('renders without crashing', async () => {
|
it('renders without crashing', async () => {
|
||||||
const { container } = render(
|
const { container } = render(<PublishForm content={content.form} />)
|
||||||
<PublishForm content={content.form} isLoading={null} />
|
|
||||||
)
|
|
||||||
expect(container.firstChild).toBeInTheDocument()
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user