diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 966eb456..e1b0cd78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: project: - helia-101 - helia-cjs + - helia-create-react-app - helia-electron - helia-esbuild - helia-nextjs @@ -79,6 +80,7 @@ jobs: project: - helia-101 - helia-cjs + - helia-create-react-app - helia-electron - helia-esbuild - helia-parcel diff --git a/examples/helia-create-react-app/.env b/examples/helia-create-react-app/.env new file mode 100644 index 00000000..b23f0db2 --- /dev/null +++ b/examples/helia-create-react-app/.env @@ -0,0 +1,6 @@ +# required because react-scripts scans *up* the tree from this project and finds +# a conflicting version of eslint in the node_modules dir for js-ipfs. +SKIP_PREFLIGHT_CHECK=true + +# Turning these on can cause OOM errors +GENERATE_SOURCEMAP=false diff --git a/examples/helia-create-react-app/.github/pull_request_template.md b/examples/helia-create-react-app/.github/pull_request_template.md new file mode 100644 index 00000000..04bd7d52 --- /dev/null +++ b/examples/helia-create-react-app/.github/pull_request_template.md @@ -0,0 +1,17 @@ +# ⚠️ IMPORTANT ⚠️ + +# Please do not create a Pull Request for this repository + +The contents of this repository are automatically synced from the parent [Helia Examples Project](https://github.com/ipfs-examples/helia-examples) so any changes made to the standalone repository will be lost after the next sync. + +Please open a PR against [IPFS Examples](https://github.com/ipfs-examples/helia-examples) instead. + +## Contributing + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +1. Fork the [Helia Examples Project](https://github.com/ipfs-examples/helia-examples) +2. Create your Feature Branch (`git checkout -b feature/amazing-example`) +3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`) +4. Push to the Branch (`git push origin feature/amazing-example`) +5. Open a Pull Request diff --git a/examples/helia-create-react-app/.github/workflows/sync.yml b/examples/helia-create-react-app/.github/workflows/sync.yml new file mode 100644 index 00000000..3f8b7446 --- /dev/null +++ b/examples/helia-create-react-app/.github/workflows/sync.yml @@ -0,0 +1,19 @@ +name: pull + +on: + workflow_dispatch + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Pull from another repository + uses: ipfs-examples/actions-pull-directory-from-repo@main + with: + source-repo: ipfs-examples/helia-examples + source-folder-path: examples/${{ github.event.repository.name }} + source-branch: main + target-branch: main + git-username: github-actions + git-email: github-actions@github.com diff --git a/examples/helia-create-react-app/README.md b/examples/helia-create-react-app/README.md new file mode 100755 index 00000000..70926b3e --- /dev/null +++ b/examples/helia-create-react-app/README.md @@ -0,0 +1,150 @@ +

+ + Helia logo + +

+ +

Helia React App

+ +

+ Using Helia with `create-react-app` +
+
+ +
+ Explore the docs + · + View Demo + · + Report Bug + · + Request Feature/Example +

+ +## Table of Contents + +- [Table of Contents](#table-of-contents) +- [About The Project](#about-the-project) +- [Getting Started](#getting-started) + - [Pre requisites](#pre-requisites) + - [Installation and Running example](#installation-and-running-example) + - [Available Scripts from create-react-app](#available-scripts-from-create-react-app) + - [`npm start`](#npm-start) + - [`npm test`](#npm-test) + - [`npm run build`](#npm-run-build) +- [Usage](#usage) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Want to hack on IPFS?](#want-to-hack-on-ipfs) + +## About The Project + +- Read the [docs](https://ipfs.github.io/helia/modules/helia.html) +- Look into other [examples](https://github.com/ipfs-examples/helia-examples) to learn how to spawn a Helia node in Node.js and in the Browser +- Visit https://dweb-primer.ipfs.io to learn about IPFS and the concepts that underpin it +- Head over to https://proto.school to take interactive tutorials that cover core IPFS APIs +- Check out https://docs.ipfs.io for tips, how-tos and more +- See https://blog.ipfs.io for news and more +- Need help? Please ask 'How do I?' questions on https://discuss.ipfs.io + +## Getting Started + +### Pre requisites + +Make sure you have installed all of the following prerequisites on your development machine: + +- Git - [Download & Install Git](https://git-scm.com/downloads). OSX and Linux machines typically have this already installed. +- Node.js - [Download & Install Node.js](https://nodejs.org/en/download/) and the npm package manager. + +### Installation and Running example + +```console +> npm install +> npm start +``` + +Now open your browser at `http://localhost:3000` + +### Available Scripts from create-react-app + +In the project directory, you can run: + +#### `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +#### `npm test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +#### `npm run build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! Read how to host a [single page](https://docs.ipfs.io/how-to/websites-on-ipfs/single-page-website/) or an [entire website](https://docs.ipfs.io/how-to/websites-on-ipfs/multipage-website/#prerequisites) on IPFS. + +But with modern hosting services like Heroku, Netlity or Fleek, you can skip the build because they will do a complete github deployment for you. See the React official page about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +## Usage + +This is a minimal demonstration of how to use `js-ipfs` in a `create-react-app` generated app. + +It boots up a `js-ipfs` instance (an IPFS node) via a custom React hook in `./src/hooks/use-ipfs-factory.js`, which is called from `./src/App.js`. Once the IPFS node is set up, `./src/App.js` displays the [PeerId](https://docs.libp2p.io/concepts/peer-id/) of this node and the version number of `js-ipfs` used to spawn it. + +All React applications store their main logic in `App.js`: + +- `App.js` renders the cosmetics of the demo and calls `useIpfs` to retrieve the `id` of the node +- `useIpfsFactory.js` initialises and closes the IPFS local node +- `useIpfs.js` does the actual calls to IPFS to retrieve the property specified in argument (here the retrieved property is `id`, requested from `App.js`) + +Once the IPFS node is set up, `App.js` displays its ident and its version number. + +> _Side note: The PeerId of the IPFS node is [the multihash of the public key of this node](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids). The public-private key pair of a node is generated by typing `ipfs init`._ + +![Screen shot of the js ipfs node id info](./img/screenshot.png) + +**Note**: this example is useful to learn how to spawn IPFS from a web page. It is also possible to [spawn an IPFS daemon from the command line](https://docs.ipfs.io/install/command-line/) with `ipfs daemon`. While self-hosting is advised, one can also delegate IPFS operations to a third-party like Infura. See tutorials [here](https://blog.infura.io/part-2-getting-started-with-ipfs-on-infura/) and [here](https://blog.infura.io/part-2-getting-started-with-ipfs-on-infura/). + +_For more examples, please refer to the [Documentation](#documentation)_ + +## Documentation + +- [IPFS Primer](https://dweb-primer.ipfs.io/) +- [IPFS Docs](https://docs.ipfs.io/) +- [Tutorials](https://proto.school) +- [More examples](https://github.com/ipfs-examples/helia-examples) +- [API - Helia](https://ipfs.github.io/helia/modules/helia.html) +- [API - @helia/unixfs](https://ipfs.github.io/helia-unixfs/modules/helia.html) + +## Contributing + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +1. Fork the IPFS Project +2. Create your Feature Branch (`git checkout -b feature/amazing-feature`) +3. Commit your Changes (`git commit -a -m 'feat: add some amazing feature'`) +4. Push to the Branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) + +The IPFS implementation in JavaScript needs your help! There are a few things you can do right now to help out: + +Read the [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md) and [JavaScript Contributing Guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING_JS.md). + +- **Check out existing issues** The [issue list](https://github.com/ipfs/helia/issues) has many that are marked as ['help wanted'](https://github.com/ipfs/helia/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22) or ['difficulty:easy'](https://github.com/ipfs/helia/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Adifficulty%3Aeasy) which make great starting points for development, many of which can be tackled with no prior IPFS knowledge +- **Look at the [Helia Roadmap](https://github.com/ipfs/helia/blob/main/ROADMAP.md)** This are the high priority items being worked on right now +- **Perform code reviews** More eyes will help + a. speed the project along + b. ensure quality, and + c. reduce possible future bugs +- **Add tests**. There can never be enough tests \ No newline at end of file diff --git a/examples/helia-create-react-app/img/screenshot.png b/examples/helia-create-react-app/img/screenshot.png new file mode 100644 index 00000000..d24d4251 Binary files /dev/null and b/examples/helia-create-react-app/img/screenshot.png differ diff --git a/examples/helia-create-react-app/package.json b/examples/helia-create-react-app/package.json new file mode 100644 index 00000000..53295891 --- /dev/null +++ b/examples/helia-create-react-app/package.json @@ -0,0 +1,64 @@ +{ + "name": "helia-create-react-app", + "version": "1.0.0", + "private": true, + "description": "Using Helia with `create-react-app`", + "license": "MIT", + "scripts": { + "clean": "rimraf ./build", + "build": "react-scripts build", + "eject": "react-scripts eject", + "start": "react-scripts start", + "test:react": "react-scripts test", + "test": "npm run build && playwright test tests" + }, + "browserslist": { + "production": [ + ">0.2%", + "not ie <= 99", + "not android <= 4.4.4", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^11.0.4", + "@chainsafe/libp2p-yamux": "^3.0.7", + "@helia/unixfs": "^1.2.1", + "@libp2p/bootstrap": "^6.0.3", + "@libp2p/websockets": "^5.0.8", + "@libp2p/webtransport": "^1.0.11", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^12.1.2", + "@testing-library/user-event": "^13.5.0", + "blockstore-core": "^4.1.0", + "datastore-core": "^9.1.1", + "dot-prop": "^7.1.1", + "helia": "^1.0.0", + "ipfs-css": "^1.3.0", + "libp2p": "^0.43.3", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-scripts": "5.0.1", + "tachyons": "^4.12.0", + "web-vitals": "^2.1.2" + }, + "devDependencies": { + "@playwright/test": "^1.12.3", + "playwright": "^1.12.3", + "rimraf": "^4.4.1", + "test-util-ipfs-example": "^1.0.2", + "util": "^0.12.4" + } +} diff --git a/examples/helia-create-react-app/public/favicon.ico b/examples/helia-create-react-app/public/favicon.ico new file mode 100644 index 00000000..b2f1f968 Binary files /dev/null and b/examples/helia-create-react-app/public/favicon.ico differ diff --git a/examples/helia-create-react-app/public/index.html b/examples/helia-create-react-app/public/index.html new file mode 100644 index 00000000..4a535326 --- /dev/null +++ b/examples/helia-create-react-app/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + IPFS React App + + + +
+ + + diff --git a/examples/helia-create-react-app/public/logo192.png b/examples/helia-create-react-app/public/logo192.png new file mode 100644 index 00000000..fc44b0a3 Binary files /dev/null and b/examples/helia-create-react-app/public/logo192.png differ diff --git a/examples/helia-create-react-app/public/logo512.png b/examples/helia-create-react-app/public/logo512.png new file mode 100644 index 00000000..a4e47a65 Binary files /dev/null and b/examples/helia-create-react-app/public/logo512.png differ diff --git a/examples/helia-create-react-app/public/manifest.json b/examples/helia-create-react-app/public/manifest.json new file mode 100644 index 00000000..f3b03a48 --- /dev/null +++ b/examples/helia-create-react-app/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "IPFS React App", + "name": "IPFS Create React App Example", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/examples/helia-create-react-app/public/robots.txt b/examples/helia-create-react-app/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/examples/helia-create-react-app/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/examples/helia-create-react-app/src/App.css b/examples/helia-create-react-app/src/App.css new file mode 100644 index 00000000..d2a0dc80 --- /dev/null +++ b/examples/helia-create-react-app/src/App.css @@ -0,0 +1,28 @@ +.react-logo { + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .react-logo { + animation: react-logo-spin infinite 20s linear; + } +} + +.react-header { + text-align: center; + font-size: calc(10px + 2vmin); + color: #282c34; +} + +.react-link { + color: #61dafb; +} + +@keyframes react-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/examples/helia-create-react-app/src/App.js b/examples/helia-create-react-app/src/App.js new file mode 100644 index 00000000..171c02ba --- /dev/null +++ b/examples/helia-create-react-app/src/App.js @@ -0,0 +1,87 @@ +import { useState, useEffect } from 'react' +import useHeliaFactory from './hooks/use-helia-factory.js' +import useHelia from './hooks/use-helia.js' +import logo from './logo.svg' +import ipfsLogo from './ipfs-logo.svg' +import './App.css' + +function App () { + const { helia, heliaInitError } = useHeliaFactory({ commands: ['id'] }) + const id = useHelia(helia, 'libp2p.peerId') + const [version, setVersion] = useState(null) + + useEffect(() => { + if (!helia) return + + const getVersion = async () => { + const nodeId = await helia.version() + setVersion(nodeId) + } + + getVersion() + }, [helia]) + + return ( +
+
+ + Helia logo + + logo + +

Helia React

+
+
+ {heliaInitError && ( +
+ Error: {heliaInitError.message ?? heliaInitError} +
+ )} + {(id || version) && +
+

Connected to Helia

+
+ {id && } + {version && } +
+
+ } +
+ +
+ ) +} + +const Title = ({ children }) => { + return ( +

{children}

+ ) +} + +const HeliaId = ({ keys, obj }) => { + if (!obj || !keys || keys.length === 0) return null + return ( + <> + {keys?.map((key) => ( +
+ {key} +
{obj[key].toString()}
+
+ ))} + + ) +} + +export default App diff --git a/examples/helia-create-react-app/src/App.test.js b/examples/helia-create-react-app/src/App.test.js new file mode 100644 index 00000000..4741580c --- /dev/null +++ b/examples/helia-create-react-app/src/App.test.js @@ -0,0 +1,8 @@ +import { render, screen } from '@testing-library/react' +import App from './App' + +test('renders learn react link', () => { + render() + const linkElement = screen.getByText(/learn react/i) + expect(linkElement).toBeInTheDocument() +}) diff --git a/examples/helia-create-react-app/src/hooks/use-helia-factory.js b/examples/helia-create-react-app/src/hooks/use-helia-factory.js new file mode 100644 index 00000000..eed497fe --- /dev/null +++ b/examples/helia-create-react-app/src/hooks/use-helia-factory.js @@ -0,0 +1,97 @@ +/* eslint-disable no-console */ + +import { useEffect, useState } from 'react' +import { createHelia } from 'helia' +import { createLibp2p } from 'libp2p' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { webSockets } from '@libp2p/websockets' +import { webTransport } from '@libp2p/webtransport' +import { bootstrap } from '@libp2p/bootstrap' +import { MemoryBlockstore } from 'blockstore-core' +import { MemoryDatastore } from 'datastore-core' + +async function createNode () { + // the blockstore is where we store the blocks that make up files + const blockstore = new MemoryBlockstore() + + // application-specific data lives in the datastore + const datastore = new MemoryDatastore() + + // libp2p is the networking layer that underpins Helia + const libp2p = await createLibp2p({ + datastore, + transports: [ + webSockets(), + webTransport() + ], + connectionEncryption: [ + noise() + ], + streamMuxers: [ + yamux() + ], + peerDiscovery: [ + bootstrap({ + list: [ + '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN', + '/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa', + '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', + '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt' + ] + }) + ] + }) + + return await createHelia({ + datastore, + blockstore, + libp2p + }) +} + +let helia = null + +/* + * A quick demo using React hooks to create a Helia instance + */ +export default function useHeliaFactory () { + const [isHeliaReady, setHeliaReady] = useState(Boolean(helia)) + const [heliaInitError, setHeliaInitError] = useState(null) + + useEffect(() => { + // The fn to useEffect should not return anything other than a cleanup fn, + // So it cannot be marked async, which causes it to return a promise, + // Hence we delegate to a async fn rather than making the param an async fn. + + startHelia() + return function cleanup () { + if (helia && helia.stop) { + console.log('Stopping Helia') + helia.stop().catch(err => console.error(err)) + helia = null + setHeliaReady(false) + } + } + }, []) + + async function startHelia () { + if (helia) { + console.log('Helia already started') + } else { + try { + console.time('Helia Starting') + helia = await createNode() + console.timeEnd('Helia Started') + } catch (error) { + console.error('Helia init error:', error) + helia = null + setHeliaInitError(error) + } + } + + setHeliaReady(Boolean(helia)) + } + + return { helia, isHeliaReady, heliaInitError } +} diff --git a/examples/helia-create-react-app/src/hooks/use-helia.js b/examples/helia-create-react-app/src/hooks/use-helia.js new file mode 100644 index 00000000..2bb82b51 --- /dev/null +++ b/examples/helia-create-react-app/src/hooks/use-helia.js @@ -0,0 +1,31 @@ +/* eslint-disable no-console */ + +import { useState, useEffect } from 'react' +import { getProperty } from 'dot-prop' +// dot-prop: used to obtain a property of an object when the name of property is a string +// here we get ipfs.id when calling dotProp.get(ipfs, cmd), with cmd = 'id' +// and we get ipfs.hash when calling with cmd = 'hash' etc. + +/* + * Pass the command you'd like to call on an ipfs instance. + * +* callIpfs uses setState write the response as a state variable, so that your component + * will re-render when the result 'res' turns up from the call await ipfsCmd. + * + */ +export default function useHelia (ipfs, cmd, opts) { + const [res, setRes] = useState(null) + useEffect(() => { + callHelia(ipfs, cmd, setRes, opts) + }, [ipfs, cmd, opts]) + return res +} + +async function callHelia (ipfs, cmd, setRes, ...opts) { + if (!ipfs) return null + console.log(`Call helia.${cmd}`) + const heliaCmd = getProperty(ipfs, cmd) + const res = await heliaCmd(...opts) + console.log(`Result helia.${cmd}`, res) + setRes(res) +} diff --git a/examples/helia-create-react-app/src/index.css b/examples/helia-create-react-app/src/index.css new file mode 100644 index 00000000..4a1df4db --- /dev/null +++ b/examples/helia-create-react-app/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/examples/helia-create-react-app/src/index.js b/examples/helia-create-react-app/src/index.js new file mode 100644 index 00000000..ca4f1ab8 --- /dev/null +++ b/examples/helia-create-react-app/src/index.js @@ -0,0 +1,21 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import 'tachyons' +import 'ipfs-css' +import './index.css' + +import App from './App.js' +import reportWebVitals from './reportWebVitals.js' + +ReactDOM.render( + + + , + document.getElementById('root') +) + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals() diff --git a/examples/helia-create-react-app/src/ipfs-logo.svg b/examples/helia-create-react-app/src/ipfs-logo.svg new file mode 100644 index 00000000..5d24074b --- /dev/null +++ b/examples/helia-create-react-app/src/ipfs-logo.svg @@ -0,0 +1 @@ +IPFS logo (new) \ No newline at end of file diff --git a/examples/helia-create-react-app/src/logo.svg b/examples/helia-create-react-app/src/logo.svg new file mode 100644 index 00000000..9dfc1c05 --- /dev/null +++ b/examples/helia-create-react-app/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/helia-create-react-app/src/reportWebVitals.js b/examples/helia-create-react-app/src/reportWebVitals.js new file mode 100644 index 00000000..9381231d --- /dev/null +++ b/examples/helia-create-react-app/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry) + getFID(onPerfEntry) + getFCP(onPerfEntry) + getLCP(onPerfEntry) + getTTFB(onPerfEntry) + }) + } +} + +export default reportWebVitals diff --git a/examples/helia-create-react-app/src/setupTests.js b/examples/helia-create-react-app/src/setupTests.js new file mode 100644 index 00000000..52aaef1d --- /dev/null +++ b/examples/helia-create-react-app/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom' diff --git a/examples/helia-create-react-app/tests/test.mjs b/examples/helia-create-react-app/tests/test.mjs new file mode 100644 index 00000000..328adc35 --- /dev/null +++ b/examples/helia-create-react-app/tests/test.mjs @@ -0,0 +1,31 @@ +import { test, expect } from '@playwright/test'; +import { playwright } from 'test-util-ipfs-example'; + +// Setup +const play = test.extend({ + ...playwright.servers([{ + portToUse: 3000, + folderToServe: 'build' + }]), +}); + +play.describe('integrate ipfs with react:', () => { + // DOM + const title = "[data-test=title]" + const id = "[data-test=id]" + const agentVersion = "[data-test=agentVersion]" + const version = "[data-test=version]" + + play.beforeEach(async ({servers, page}) => { + await page.goto(`http://localhost:${servers[0].port}/`); + }) + + play('should properly initialize a Helia node and print some properties', async ({ page }) => { + await page.waitForSelector(title) + + expect(await page.textContent(title)).toContain("Connected to Helia"); + expect(await page.isVisible(id)).toBeTruthy(); + expect(await page.isVisible(agentVersion)).toBeTruthy(); + expect(await page.isVisible(version)).toBeTruthy(); + }); +});