From 52659efa971b8d8a4c440a346c0696b5f3345f9f Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Mon, 13 Sep 2021 23:55:29 +0200 Subject: [PATCH] test tweaks --- .eslintrc.json | 17 +- .github/workflows/ci.yml | 14 + README.md | 2 + jest/babel.config.js | 3 - jest/jest.config.js | 22 -- package-lock.json | 294 +++++++++++++++++- package.json | 6 +- src/components/Add.module.css | 26 -- src/components/Add.tsx | 99 ------ src/components/{ => Add}/Dropzone.module.css | 0 src/components/{ => Add}/Dropzone.tsx | 0 src/components/Add/FileLink.module.css | 10 + src/components/Add/FileLink.tsx | 30 ++ src/components/Add/Files.module.css | 8 + src/components/Add/Files.tsx | 28 ++ src/components/Add/index.module.css | 6 + src/components/Add/index.tsx | 49 +++ src/hooks/use-ipfs-api.tsx | 2 +- src/utils.ts | 6 - test/Files.test.tsx | 25 ++ {src/__tests__ => test}/Layout.test.tsx | 2 +- {src/__tests__ => test}/Loader.test.tsx | 2 +- test/Typekit.test.tsx | 9 + test/__config__/jest.config.js | 27 ++ test/__config__/jest.env.ts | 18 ++ .../setup.ts => test/__config__/jest.setup.ts | 0 {jest => test}/__mocks__/fileMock.js | 0 {jest => test}/__mocks__/styleMock.js | 0 {jest => test}/__mocks__/svgrMock.js | 0 {src/__tests__ => test}/index.test.tsx | 7 +- test/use-ipfs.test.tsx | 22 ++ 31 files changed, 569 insertions(+), 165 deletions(-) delete mode 100644 jest/babel.config.js delete mode 100644 jest/jest.config.js delete mode 100644 src/components/Add.module.css delete mode 100644 src/components/Add.tsx rename src/components/{ => Add}/Dropzone.module.css (100%) rename src/components/{ => Add}/Dropzone.tsx (100%) create mode 100644 src/components/Add/FileLink.module.css create mode 100644 src/components/Add/FileLink.tsx create mode 100644 src/components/Add/Files.module.css create mode 100644 src/components/Add/Files.tsx create mode 100644 src/components/Add/index.module.css create mode 100644 src/components/Add/index.tsx create mode 100644 test/Files.test.tsx rename {src/__tests__ => test}/Layout.test.tsx (88%) rename {src/__tests__ => test}/Loader.test.tsx (85%) create mode 100644 test/Typekit.test.tsx create mode 100644 test/__config__/jest.config.js create mode 100644 test/__config__/jest.env.ts rename jest/setup.ts => test/__config__/jest.setup.ts (100%) rename {jest => test}/__mocks__/fileMock.js (100%) rename {jest => test}/__mocks__/styleMock.js (100%) rename {jest => test}/__mocks__/svgrMock.js (100%) rename {src/__tests__ => test}/index.test.tsx (61%) create mode 100644 test/use-ipfs.test.tsx diff --git a/.eslintrc.json b/.eslintrc.json index afb6b42..889b97f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,18 @@ { - "extends": ["prettier", "plugin:prettier/recommended", "next/core-web-vitals"] + "extends": [ + "prettier", + "plugin:prettier/recommended", + "next/core-web-vitals" + ], + "plugins": ["prettier", "testing-library"], + "overrides": [ + // Only uses Testing Library lint rules in test files + { + "files": [ + "**/__tests__/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[jt]s?(x)" + ], + "extends": ["plugin:testing-library/react"] + } + ] } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48d800e..17aebc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,3 +29,17 @@ jobs: - run: npm run build env: NEXT_PUBLIC_TYPEKIT_ID: ${{ secrets.NEXT_PUBLIC_TYPEKIT_ID }} + + coverage: + runs-on: ubuntu-latest + needs: [test] + if: ${{ success() && github.actor != 'dependabot[bot]' }} + steps: + - uses: actions/checkout@v2 + - uses: actions/download-artifact@v2 + with: + name: coverage + + - uses: paambaati/codeclimate-action@v2.7.5 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} diff --git a/README.md b/README.md index fc203ee..7144757 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ > [ipfs.kretschmann.io](https://ipfs.kretschmann.io) [![CI](https://github.com/kremalicious/ipfs/actions/workflows/ci.yml/badge.svg)](https://github.com/kremalicious/ipfs/actions/workflows/ci.yml) +[![Maintainability](https://api.codeclimate.com/v1/badges/c43bcf37192f95f3a154/maintainability)](https://codeclimate.com/github/kremalicious/ipfs/maintainability) +[![Test Coverage](https://api.codeclimate.com/v1/badges/c43bcf37192f95f3a154/test_coverage)](https://codeclimate.com/github/kremalicious/ipfs/test_coverage) This repo holds a React app built with [Next.js](https://nextjs.org) serving as the frontpage of [ipfs.kretschmann.io](https://ipfs.kretschmann.io) from where you can add files to IPFS via drag and drop. diff --git a/jest/babel.config.js b/jest/babel.config.js deleted file mode 100644 index de36614..0000000 --- a/jest/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: ['next/babel', '@babel/preset-typescript'] -} diff --git a/jest/jest.config.js b/jest/jest.config.js deleted file mode 100644 index 0fb9cd1..0000000 --- a/jest/jest.config.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - rootDir: '../', - transform: { - '^.+\\.[jt]sx?$': ['babel-jest', { configFile: './jest/babel.config.js' }] - }, - moduleNameMapper: { - '.+\\.(css|styl|less|sass|scss)$': '/jest/__mocks__/styleMock.js', - '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/jest/__mocks__/fileMock.js', - '\\.svg': '/jest/__mocks__/svgrMock.js' - }, - testPathIgnorePatterns: [ - '/.next', - '/node_modules', - '/build', - '/coverage' - ], - setupFilesAfterEnv: ['/jest/setup.ts'], - collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/@types/**/*'], - collectCoverage: true, - testEnvironment: 'jsdom' -} diff --git a/package-lock.json b/package-lock.json index 4ad7cf9..836fb00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,8 +30,9 @@ "eslint": "^7.32.0", "eslint-config-next": "11.1.2", "eslint-config-prettier": "^8.3.0", - "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-testing-library": "^4.12.2", + "identity-obj-proxy": "^3.0.0", "jest": "^27.1.1", "prettier": "^2.4.0", "typescript": "^4.4.3" @@ -3532,6 +3533,12 @@ "pretty-format": "^27.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -3617,6 +3624,146 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz", + "integrity": "sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.31.1", + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/typescript-estree": "4.31.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz", + "integrity": "sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/visitor-keys": "4.31.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.1.tgz", + "integrity": "sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz", + "integrity": "sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/visitor-keys": "4.31.1", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz", + "integrity": "sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.31.1", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/parser": { "version": "4.31.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.31.0.tgz", @@ -6120,6 +6267,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-testing-library": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-4.12.2.tgz", + "integrity": "sha512-lcysxW7I3oXmZIyFP2N1dFMPfuB3qyl3iDcDboCl7U+TAaeG9OOycNSkZUAsDWQLsfEtXYmRbwTH98qSgk6peA==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^4.30.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -6889,6 +7052,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -7091,6 +7260,18 @@ "node": ">=0.10.0" } }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "dev": true, + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -16122,6 +16303,12 @@ "pretty-format": "^27.0.0" } }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -16207,6 +16394,87 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, + "@typescript-eslint/experimental-utils": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz", + "integrity": "sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.31.1", + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/typescript-estree": "4.31.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz", + "integrity": "sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/visitor-keys": "4.31.1" + } + }, + "@typescript-eslint/types": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.1.tgz", + "integrity": "sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz", + "integrity": "sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.1", + "@typescript-eslint/visitor-keys": "4.31.1", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz", + "integrity": "sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.31.1", + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "@typescript-eslint/parser": { "version": "4.31.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.31.0.tgz", @@ -18249,6 +18517,15 @@ "dev": true, "requires": {} }, + "eslint-plugin-testing-library": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-4.12.2.tgz", + "integrity": "sha512-lcysxW7I3oXmZIyFP2N1dFMPfuB3qyl3iDcDboCl7U+TAaeG9OOycNSkZUAsDWQLsfEtXYmRbwTH98qSgk6peA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^4.30.0" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -18710,6 +18987,12 @@ "duplexer": "^0.1.2" } }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -18855,6 +19138,15 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "dev": true, + "requires": { + "harmony-reflect": "^1.4.6" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", diff --git a/package.json b/package.json index 3966472..dddee39 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "start": "next dev", "build": "next build", "serve": "next start", - "test": "npm run lint && npm run type-check && NODE_ENV=test jest -c jest/jest.config.js", - "test:watch": "npm run lint && npm run type-check && NODE_ENV=test jest -c jest/jest.config.js --watch", + "test": "npm run lint && npm run type-check && NODE_ENV=test jest -c test/__config__/jest.config.js", + "test:watch": "npm run lint && npm run type-check && NODE_ENV=test jest -c test/__config__/jest.config.js --watch", "lint": "next lint", "type-check": "tsc --noEmit", "format": "prettier --ignore-path .gitignore '**/*.{css,yml,js,jsx,ts,tsx,json}' --write", @@ -38,6 +38,8 @@ "eslint-config-next": "11.1.2", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-testing-library": "^4.12.2", + "identity-obj-proxy": "^3.0.0", "jest": "^27.1.1", "prettier": "^2.4.0", "typescript": "^4.4.3" diff --git a/src/components/Add.module.css b/src/components/Add.module.css deleted file mode 100644 index fae47cb..0000000 --- a/src/components/Add.module.css +++ /dev/null @@ -1,26 +0,0 @@ -.add { - width: 100%; - overflow-wrap: break-word; - word-wrap: break-word; - word-break: break-all; -} - -.files { - text-align: left; -} - -.title { - margin-bottom: calc(var(--spacer) / 4); - font-size: var(--font-size-base); -} - -.link { - color: var(--color-text); - font-size: var(--font-size-small); - margin-bottom: calc(var(--spacer) / 4); - display: inline-block; -} - -.link:hover { - color: var(--brand-cyan); -} diff --git a/src/components/Add.tsx b/src/components/Add.tsx deleted file mode 100644 index 23c1bb0..0000000 --- a/src/components/Add.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useState, ReactElement } from 'react' -import { ipfsGateway } from '../../site.config' -import Dropzone from './Dropzone' -import styles from './Add.module.css' -import Loader from './Loader' -import useIpfsApi from '../hooks/use-ipfs-api' -import { FileIpfs } from '../@types/ipfs' -import { FileWithPath } from 'react-dropzone' - -function FileLink({ - file, - cidFolder, - cid -}: { - file: FileIpfs - cidFolder: string - cid?: string -}) { - const title = cid ? `ipfs://${cid}` : `ipfs://${cidFolder}/${file.path}` - const href = cid - ? `${ipfsGateway}/ipfs/${cid}` - : `${ipfsGateway}/ipfs/${cidFolder}/${file.path}` - - return cidFolder !== cid ? ( - - {title} - - ) : null -} - -function Files({ files }: { files: FileIpfs[] }) { - const cidFolder = files.filter((file) => file.path === '')[0].cid.toString() - - return ( -
    - {files?.map((file) => ( -
  • -

    - {file.path === '' ? 'Folder with all files' : file.path} -

    - -

    - -

    -
  • - ))} -
- ) -} - -export default function Add(): ReactElement { - const { ipfs, isIpfsReady, ipfsError, addFiles } = useIpfsApi() - const [files, setFiles] = useState() - const [loading, setLoading] = useState(false) - const [message] = useState() - const [error, setError] = useState() - - async function handleOnDrop(acceptedFiles: FileWithPath[]): Promise { - if (!acceptedFiles || !ipfs || !isIpfsReady) return - - setLoading(true) - setError(undefined) - - try { - const addedFiles = await addFiles(acceptedFiles) - setFiles(addedFiles) - setLoading(false) - } catch (error) { - setError(`Adding to IPFS failed: ${(error as Error).message}`) - return - } - } - - return ( -
- {loading ? ( - - ) : files?.length ? ( - - ) : ( - - )} -
- ) -} diff --git a/src/components/Dropzone.module.css b/src/components/Add/Dropzone.module.css similarity index 100% rename from src/components/Dropzone.module.css rename to src/components/Add/Dropzone.module.css diff --git a/src/components/Dropzone.tsx b/src/components/Add/Dropzone.tsx similarity index 100% rename from src/components/Dropzone.tsx rename to src/components/Add/Dropzone.tsx diff --git a/src/components/Add/FileLink.module.css b/src/components/Add/FileLink.module.css new file mode 100644 index 0000000..657833c --- /dev/null +++ b/src/components/Add/FileLink.module.css @@ -0,0 +1,10 @@ +.link { + color: var(--color-text); + font-size: var(--font-size-small); + margin-bottom: calc(var(--spacer) / 4); + display: inline-block; +} + +.link:hover { + color: var(--brand-cyan); +} diff --git a/src/components/Add/FileLink.tsx b/src/components/Add/FileLink.tsx new file mode 100644 index 0000000..c58fc6f --- /dev/null +++ b/src/components/Add/FileLink.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import { ipfsGateway } from '../../../site.config' +import { FileIpfs } from '../../@types/ipfs' +import styles from './FileLink.module.css' + +export default function FileLink({ + file, + cidFolder, + cid +}: { + file: FileIpfs + cidFolder: string + cid?: string +}) { + const title = cid ? `ipfs://${cid}` : `ipfs://${cidFolder}/${file.path}` + const href = cid + ? `${ipfsGateway}/ipfs/${cid}` + : `${ipfsGateway}/ipfs/${cidFolder}/${file.path}` + + return cidFolder !== cid ? ( + + {title} + + ) : null +} diff --git a/src/components/Add/Files.module.css b/src/components/Add/Files.module.css new file mode 100644 index 0000000..5b90f0e --- /dev/null +++ b/src/components/Add/Files.module.css @@ -0,0 +1,8 @@ +.files { + text-align: left; +} + +.title { + margin-bottom: calc(var(--spacer) / 4); + font-size: var(--font-size-base); +} diff --git a/src/components/Add/Files.tsx b/src/components/Add/Files.tsx new file mode 100644 index 0000000..3f7f730 --- /dev/null +++ b/src/components/Add/Files.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { FileIpfs } from '../../@types/ipfs' +import FileLink from './FileLink' +import styles from './Files.module.css' + +export default function Files({ files }: { files: FileIpfs[] }) { + const cidFolder = files.filter((file) => file.path === '')[0].cid.toString() + + return ( +
    + {files?.map((file) => ( +
  • +

    + {file.path === '' ? 'Folder with all files' : file.path} +

    + +

    + +

    +
  • + ))} +
+ ) +} diff --git a/src/components/Add/index.module.css b/src/components/Add/index.module.css new file mode 100644 index 0000000..ec84bc1 --- /dev/null +++ b/src/components/Add/index.module.css @@ -0,0 +1,6 @@ +.add { + width: 100%; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; +} diff --git a/src/components/Add/index.tsx b/src/components/Add/index.tsx new file mode 100644 index 0000000..e904bed --- /dev/null +++ b/src/components/Add/index.tsx @@ -0,0 +1,49 @@ +import React, { useState, ReactElement } from 'react' +import Dropzone from './Dropzone' +import Loader from '../Loader' +import useIpfsApi from '../../hooks/use-ipfs-api' +import { FileIpfs } from '../../@types/ipfs' +import { FileWithPath } from 'react-dropzone' +import Files from './Files' +import styles from './index.module.css' + +export default function Add(): ReactElement { + const { ipfs, isIpfsReady, ipfsError, addFiles } = useIpfsApi() + const [files, setFiles] = useState() + const [loading, setLoading] = useState(false) + const [message] = useState() + const [error, setError] = useState() + + async function handleOnDrop(acceptedFiles: FileWithPath[]): Promise { + if (!acceptedFiles || !ipfs || !isIpfsReady) return + + setLoading(true) + setError(undefined) + + try { + const addedFiles = await addFiles(acceptedFiles) + setFiles(addedFiles) + setLoading(false) + } catch (error) { + setError(`Adding to IPFS failed: ${(error as Error).message}`) + return + } + } + + return ( +
+ {loading ? ( + + ) : files?.length ? ( + + ) : ( + + )} +
+ ) +} diff --git a/src/hooks/use-ipfs-api.tsx b/src/hooks/use-ipfs-api.tsx index fd27c87..047ef93 100644 --- a/src/hooks/use-ipfs-api.tsx +++ b/src/hooks/use-ipfs-api.tsx @@ -66,7 +66,7 @@ export default function useIpfsApi(): IpfsApiValue { setIpfs(ipfs) const version = await ipfs.version() setVersion(version.version) - setIpfsReady(Boolean(ipfs && (await ipfs.id()))) + setIpfsReady(ipfs?.isOnline()) } catch (e) { setIpfsError(`IPFS connection error: ${(e as Error).message}`) setIpfsReady(false) diff --git a/src/utils.ts b/src/utils.ts index 408a9be..ea42f1a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -19,9 +19,3 @@ export async function pingUrl(url: string): Promise { return false } } - -export function parseHTML(str: string): HTMLCollection { - const tmp = document.implementation.createHTMLDocument() - tmp.body.innerHTML = str - return tmp.body.children -} diff --git a/test/Files.test.tsx b/test/Files.test.tsx new file mode 100644 index 0000000..f9854a0 --- /dev/null +++ b/test/Files.test.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import { render, screen } from '@testing-library/react' +import Files from '../src/components/Add/Files' +import { CID } from 'multiformats/cid' + +const files = [ + { + path: 'hello', + cid: { toString: () => 'xxx' } as CID, + size: 1000 + }, + { + path: '', + cid: { toString: () => 'xxx' } as CID, + size: 1000 + } +] + +describe('Files', () => { + it('renders without crashing', async () => { + render() + const element = await screen.findByText('ipfs://xxx/') + expect(element).toBeInTheDocument() + }) +}) diff --git a/src/__tests__/Layout.test.tsx b/test/Layout.test.tsx similarity index 88% rename from src/__tests__/Layout.test.tsx rename to test/Layout.test.tsx index 31edc9f..d577829 100644 --- a/src/__tests__/Layout.test.tsx +++ b/test/Layout.test.tsx @@ -1,6 +1,6 @@ import React from 'react' import { render, screen } from '@testing-library/react' -import Layout from '../Layout' +import Layout from '../src/Layout' describe('Layout', () => { it('renders without crashing', () => { diff --git a/src/__tests__/Loader.test.tsx b/test/Loader.test.tsx similarity index 85% rename from src/__tests__/Loader.test.tsx rename to test/Loader.test.tsx index 4a3090c..d010590 100644 --- a/src/__tests__/Loader.test.tsx +++ b/test/Loader.test.tsx @@ -1,6 +1,6 @@ import React from 'react' import { render, screen } from '@testing-library/react' -import Loader from '../components/Loader' +import Loader from '../src/components/Loader' describe('Loader', () => { it('renders without crashing', async () => { diff --git a/test/Typekit.test.tsx b/test/Typekit.test.tsx new file mode 100644 index 0000000..03e5ff8 --- /dev/null +++ b/test/Typekit.test.tsx @@ -0,0 +1,9 @@ +import React from 'react' +import { render } from '@testing-library/react' +import Typekit from '../src/components/Typekit' + +describe('Typekit', () => { + it('renders without crashing', async () => { + render() + }) +}) diff --git a/test/__config__/jest.config.js b/test/__config__/jest.config.js new file mode 100644 index 0000000..d521732 --- /dev/null +++ b/test/__config__/jest.config.js @@ -0,0 +1,27 @@ +module.exports = { + rootDir: '../../', + transform: { + '^.+\\.[jt]sx?$': ['babel-jest', { presets: ['next/babel'] }] + }, + transformIgnorePatterns: [ + '/node_modules/', + '^.+\\.module\\.(css|sass|scss)$' + ], + moduleNameMapper: { + '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy', + '^.+\\.(css|sass|scss)$': '/test/__mocks__/styleMock.js', + '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/test/__mocks__/fileMock.js', + '\\.svg': '/test/__mocks__/svgrMock.js' + }, + testPathIgnorePatterns: [ + '/.next', + '/node_modules', + '/build', + '/coverage' + ], + setupFilesAfterEnv: ['/test/__config__/jest.setup.ts'], + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/@types/**/*'], + collectCoverage: true, + testEnvironment: '/test/__config__/jest.env.ts' +} diff --git a/test/__config__/jest.env.ts b/test/__config__/jest.env.ts new file mode 100644 index 0000000..cdeed53 --- /dev/null +++ b/test/__config__/jest.env.ts @@ -0,0 +1,18 @@ +import Environment from 'jest-environment-jsdom' + +/** + * A custom environment to set the TextEncoder required by ipfs-http-client. + */ +module.exports = class CustomTestEnvironment extends Environment { + async setup() { + await super.setup() + if (typeof this.global.TextEncoder === 'undefined') { + const { TextEncoder } = require('util') + this.global.TextEncoder = TextEncoder + } + if (typeof this.global.TextDecoder === 'undefined') { + const { TextDecoder } = require('util') + this.global.TextDecoder = TextDecoder + } + } +} diff --git a/jest/setup.ts b/test/__config__/jest.setup.ts similarity index 100% rename from jest/setup.ts rename to test/__config__/jest.setup.ts diff --git a/jest/__mocks__/fileMock.js b/test/__mocks__/fileMock.js similarity index 100% rename from jest/__mocks__/fileMock.js rename to test/__mocks__/fileMock.js diff --git a/jest/__mocks__/styleMock.js b/test/__mocks__/styleMock.js similarity index 100% rename from jest/__mocks__/styleMock.js rename to test/__mocks__/styleMock.js diff --git a/jest/__mocks__/svgrMock.js b/test/__mocks__/svgrMock.js similarity index 100% rename from jest/__mocks__/svgrMock.js rename to test/__mocks__/svgrMock.js diff --git a/src/__tests__/index.test.tsx b/test/index.test.tsx similarity index 61% rename from src/__tests__/index.test.tsx rename to test/index.test.tsx index b5137da..dd80591 100644 --- a/src/__tests__/index.test.tsx +++ b/test/index.test.tsx @@ -1,11 +1,14 @@ import React from 'react' import { render, screen } from '@testing-library/react' -import Home from '../pages' +import Home from '../src/pages' describe('Home', () => { it('renders without crashing', async () => { render() - await screen.findAllByTitle('Online', undefined, { timeout: 10000 }) + const online = await screen.findAllByTitle('Online', undefined, { + timeout: 10000 + }) expect(screen.getByText('A public IPFS Gateway')).toBeInTheDocument() + expect(online).toBeDefined() }) }) diff --git a/test/use-ipfs.test.tsx b/test/use-ipfs.test.tsx new file mode 100644 index 0000000..d4c50eb --- /dev/null +++ b/test/use-ipfs.test.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import { render, screen } from '@testing-library/react' +import useIpfs from '../src/hooks/use-ipfs-api' + +export default function TestComponent() { + const { version, isIpfsReady, ipfsError } = useIpfs() + + return ( +
+ {isIpfsReady && Ready} + {version} - {ipfsError} +
+ ) +} + +describe('use-ipfs', () => { + it('renders without crashing', async () => { + render() + const element = await screen.findByText('Ready') + expect(element).toBeInTheDocument() + }) +})