From dad38ff4f65f737df14269d0d33a8643f318b328 Mon Sep 17 00:00:00 2001 From: Jo Murgel Date: Wed, 4 Sep 2024 22:25:04 -0600 Subject: [PATCH] attempts to add some additional testing --- App.tsx | 2 +- .../async-storage.js | 11 + babel.config.js | 8 +- jest.config.js | 15 +- package-lock.json | 322 +++++++++++++++++- package.json | 7 + src/hooks/useAuth.test.temp | 50 --- src/lib/supabaseClient.ts | 2 +- src/redux/slices/todoSlice.ts | 2 +- tests/AppNavigation.test.temp | 47 +++ tests/hooks/useAuth.test.temp | 50 +++ {src => tests}/services/getNextStatus.test.ts | 2 +- 12 files changed, 447 insertions(+), 71 deletions(-) create mode 100644 __mocks__/@react-native-async-storage/async-storage.js delete mode 100644 src/hooks/useAuth.test.temp create mode 100644 tests/AppNavigation.test.temp create mode 100644 tests/hooks/useAuth.test.temp rename {src => tests}/services/getNextStatus.test.ts (90%) diff --git a/App.tsx b/App.tsx index 955a1bf..357ec4c 100644 --- a/App.tsx +++ b/App.tsx @@ -12,7 +12,7 @@ import useAuth from './src/hooks/useAuth' /** * Determines visibility of features based on user authentication. */ -function AppNavigation(): ReactElement { +export function AppNavigation(): ReactElement { const { session } = useAuth() return ( session && session.user ? : ) } diff --git a/__mocks__/@react-native-async-storage/async-storage.js b/__mocks__/@react-native-async-storage/async-storage.js new file mode 100644 index 0000000..9b755db --- /dev/null +++ b/__mocks__/@react-native-async-storage/async-storage.js @@ -0,0 +1,11 @@ +// __mocks__/@react-native-async-storage/async-storage.js +import { jest } from '@jest/globals' + +const mockAsyncStorage = { + getItem: jest.fn( () => Promise.resolve( null ) ), + setItem: jest.fn( () => Promise.resolve() ), + removeItem: jest.fn( () => Promise.resolve() ), + clear: jest.fn( () => Promise.resolve() ), +} + +export default mockAsyncStorage diff --git a/babel.config.js b/babel.config.js index 50f2163..1b3e117 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,11 +1,13 @@ -function config( api ) { +module.exports = ( api ) => { api.cache( true ) return { presets: [ 'babel-preset-expo', '@babel/preset-typescript', + '@babel/preset-react', + ], + plugins: [ + '@babel/plugin-transform-runtime', ], } } - -module.exports = config diff --git a/jest.config.js b/jest.config.js index b280bcf..e0ef7be 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,18 +1,9 @@ module.exports = { preset: 'jest-expo', - setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'], transform: { - '^.+\\.tsx?$': [ 'ts-jest', { - jsx: 'react', - module: 'commonjs', - target: 'es6', - strict: true, - esModuleInterop: true, - skipLibCheck: true, - forceConsistentCasingInFileNames: true, - types: [ 'jest', 'node' ], - } ], + '^.+\\.tsx?$': ['babel-jest'], }, testPathIgnorePatterns: [ '/node_modules/', '/android/', '/ios/' ], - testEnvironment: 'node', + testEnvironment: 'jsdom', + moduleFileExtensions: [ 'js', 'jsx', 'ts', 'tsx' ], } diff --git a/package-lock.json b/package-lock.json index d8a2aa3..ba37857 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,8 +41,10 @@ "@types/jest": "^29.5.12", "@types/react": "~18.2.45", "@types/react-native": "^0.72.8", + "@types/react-test-renderer": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.4.0", "@typescript-eslint/parser": "^8.4.0", + "babel-jest": "^29.7.0", "babel-plugin-module-resolver": "^5.0.2", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", @@ -54,9 +56,11 @@ "eslint-plugin-typescript": "^0.14.0", "install": "^0.13.0", "jest": "^29.7.0", + "jest-coverage-badges": "^1.1.2", "jest-expo": "^51.0.4", "module-resolver": "^1.0.0", "npm": "^10.8.3", + "react-native-mock": "^0.3.1", "ts-jest": "^29.2.5", "typescript": "^5.5.4" } @@ -8052,6 +8056,16 @@ "react-native": "*" } }, + "node_modules/@types/react-test-renderer": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz", + "integrity": "sha512-HW4MuEYxfDbOHQsVlY/XtOvNHftCVEPhJF2pQXXwcUiUF+Oyb0usgp48HSgpK5rt8m9KZb22yqOeZm+rrVG8gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -10042,6 +10056,14 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, + "node_modules/core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "license": "MIT" + }, "node_modules/core-js-compat": { "version": "3.38.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", @@ -10277,6 +10299,15 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/cubic-bezier": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cubic-bezier/-/cubic-bezier-0.1.2.tgz", + "integrity": "sha512-kIojIIJQ9QZ5kYaeEeFG+a9oCgPtw1CHqF8Y52enHzu2Cz3NjwfbDdbO7MOxXvVjEZ4tSU3sCGykpZrnoHYtQA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -10851,6 +10882,16 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -13229,7 +13270,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -14084,6 +14125,28 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch/node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -14914,6 +14977,44 @@ "node": ">=8" } }, + "node_modules/jest-coverage-badges": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/jest-coverage-badges/-/jest-coverage-badges-1.1.2.tgz", + "integrity": "sha512-44A7i2xR6os8+fWk8ZRM6W4fKiD2jwKOLU9eB3iTIIWACd9RbdvmiCNpQZTOsUBhKvz7aQ/ASFhu5JOEhWUOlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "0.5.1" + }, + "bin": { + "jest-coverage-badges": "cli.js" + }, + "engines": { + "node": ">=6.11", + "npm": ">=5.3" + } + }, + "node_modules/jest-coverage-badges/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-coverage-badges/node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", @@ -17145,6 +17246,12 @@ "node": ">=4.0" } }, + "node_modules/keymirror": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz", + "integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg==", + "dev": true + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -21788,6 +21895,13 @@ "node": ">=8" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", @@ -22407,6 +22521,16 @@ ], "license": "MIT" }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "performance-now": "^2.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -22443,6 +22567,78 @@ "node": ">=0.10.0" } }, + "node_modules/react-addons-create-fragment": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react-addons-create-fragment/-/react-addons-create-fragment-15.6.2.tgz", + "integrity": "sha512-O9+cXwMGcMF7WfpZHw+Lt8+jkRhyQBgihOVz9xfGMRORMdMf40HLeQQbdwPUQB7G73+/Zc+hB77A/UyE58n9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "fbjs": "^0.8.4", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.0" + } + }, + "node_modules/react-addons-create-fragment/node_modules/fbjs": { + "version": "0.8.18", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz", + "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "node_modules/react-addons-create-fragment/node_modules/ua-parser-js": { + "version": "0.7.38", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", + "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/react-addons-pure-render-mixin": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/react-addons-pure-render-mixin/-/react-addons-pure-render-mixin-15.6.3.tgz", + "integrity": "sha512-e7F2OsLiyYGr9SHWHGlI/FfHRh+kbYx0hNfdN5zivHIf4vzeno7gsRJKXg71E35CpUCnre+JfM6UgWWgsvJBzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0" + } + }, + "node_modules/react-addons-update": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/react-addons-update/-/react-addons-update-15.6.3.tgz", + "integrity": "sha512-wBkjgx5cR0XTjZEz5jl2kScChrjI9T7rWVdaM0dLiIdHSgeHycLRdHPPiTgKk7vK18Od4rXmLJv91qofBXlE0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0" + } + }, "node_modules/react-devtools-core": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-5.3.1.tgz", @@ -22610,6 +22806,111 @@ "react-native": "*" } }, + "node_modules/react-native-mock": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/react-native-mock/-/react-native-mock-0.3.1.tgz", + "integrity": "sha512-DoonXsALIHuRYw6nO/ILwqe40rcqZPNyEws/LuybHnYWxYp9j8YCqOQzwdCAtGNTRcPBMR4bPOLPf06Gqkm8JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cubic-bezier": "^0.1.2", + "invariant": "^2.2.1", + "keymirror": "^0.1.1", + "raf": "^3.2.0", + "react-addons-create-fragment": "^15.4.0", + "react-addons-perf": "^15.4.0", + "react-addons-pure-render-mixin": "^15.4.0", + "react-addons-test-utils": "^15.4.0", + "react-addons-update": "^15.4.0", + "react-dom": "^15.4.0", + "react-timer-mixin": "^0.13.3", + "warning": "^2.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-mock/node_modules/fbjs": { + "version": "0.8.18", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz", + "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, + "node_modules/react-native-mock/node_modules/react-addons-perf": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-addons-perf/-/react-addons-perf-15.4.2.tgz", + "integrity": "sha512-8WppccO6ygQBw8WpUk5gDus/JzOyjh3uCmVKHnzr32BuDM6rqWJSYuu3M3+yo3GLMverXKoWqNN4jLEWT4KkNg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fbjs": "^0.8.4", + "object-assign": "^4.1.0" + }, + "peerDependencies": { + "react-dom": "^15.4.2" + } + }, + "node_modules/react-native-mock/node_modules/react-addons-test-utils": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz", + "integrity": "sha512-6IUCnLp7jQRBftm2anf8rP8W+8M2PsC7GPyMFe2Wef3Wfml7j2KybVL//Ty7bRDBqLh8AG4m/zNZbFlwulldFw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react-dom": "^15.4.2" + } + }, + "node_modules/react-native-mock/node_modules/react-dom": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.7.0.tgz", + "integrity": "sha512-mpjXqC2t1FuYsILOLCj0kg6pbg460byZkVA/80VtDmKU/pYmoTdHOtaMcTRIDiyXLz4sIur0cQ04nOC6iGndJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fbjs": "^0.8.9", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^15.7.0" + } + }, + "node_modules/react-native-mock/node_modules/ua-parser-js": { + "version": "0.7.38", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", + "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/react-native-ratings": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-8.1.0.tgz", @@ -22996,6 +23297,13 @@ "loose-envify": "^1.1.0" } }, + "node_modules/react-timer-mixin": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz", + "integrity": "sha512-4+ow23tp/Tv7hBM5Az5/Be/eKKF7DIvJ09voz5LyHGQaqqz9WV8YMs31eFvcYQs7d451LSg7kDJV70XYN/Ug/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -23438,7 +23746,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/sax": { @@ -25370,6 +25678,16 @@ "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", "license": "MIT" }, + "node_modules/warning": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz", + "integrity": "sha512-O9pvum8nlCqIT5pRGo2WRQJPRG2bW/ZBeCzl7/8CWREjUW693juZpGup7zbRtuVcSKyGiRAIZLYsh3C0vq7FAg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/package.json b/package.json index 88a5882..a0d736b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,9 @@ "ios": "expo start --ios", "web": "expo start --web", "test": "jest", + "test:watch": "npm run test --watch", + "test:ci": "npm run test --coverage", + "test:badges": "npm run test:ci && jest-coverage-badges --input coverage/coverage-summary.json --output __badges__", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix" }, @@ -46,8 +49,10 @@ "@types/jest": "^29.5.12", "@types/react": "~18.2.45", "@types/react-native": "^0.72.8", + "@types/react-test-renderer": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.4.0", "@typescript-eslint/parser": "^8.4.0", + "babel-jest": "^29.7.0", "babel-plugin-module-resolver": "^5.0.2", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", @@ -59,9 +64,11 @@ "eslint-plugin-typescript": "^0.14.0", "install": "^0.13.0", "jest": "^29.7.0", + "jest-coverage-badges": "^1.1.2", "jest-expo": "^51.0.4", "module-resolver": "^1.0.0", "npm": "^10.8.3", + "react-native-mock": "^0.3.1", "ts-jest": "^29.2.5", "typescript": "^5.5.4" }, diff --git a/src/hooks/useAuth.test.temp b/src/hooks/useAuth.test.temp deleted file mode 100644 index f0b1bc4..0000000 --- a/src/hooks/useAuth.test.temp +++ /dev/null @@ -1,50 +0,0 @@ -// @todo: need to adjust testing configs to support imports an file types. -// import { renderHook } from '@testing-library/react' -// import React, { ReactNode } from 'react' -// import { -// expect, describe, it, jest, -// } from '@jest/globals' -// import { User } from '@supabase/supabase-js' -// import useAuth from './useAuth' -// import { AuthContext } from '../providers/AuthProvider' -// import { AuthContextType } from '../types/auth' - -// describe( 'useAuth', () => { -// it( 'should throw an error if used outside of AuthProvider', () => { -// const { result } = renderHook( () => useAuth() ) - -// // Expect the hook to throw an error when used outside the AuthProvider -// expect( result.current.error ).toEqual( -// new Error( 'useAuth must be used within an AuthProvider' ), -// ) -// } ) - -// it( 'should return the context value when used within AuthProvider', () => { -// // @todo: need to setup a different parser for this. -// // Mock the context value conforming to AuthContextType -// const mockAuthContextValue: AuthContextType = { -// error: null, -// loading: false, -// session: null, -// // @ts-expect-error ignore for testing, not important. -// signUpNewUser: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), -// // @ts-expect-error ignore for testing, not important. -// signInWithEmail: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), -// // @ts-expect-error ignore for testing, not important. -// signOut: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), -// user: { id: '1', email: 'test@example.com' } as User, // Mocking user object -// } - -// // Define the wrapper component with the correct context value -// const wrapper = ( { children }: { children: ReactNode } ) => ( -// -// {children} -// -// ) - -// const { result } = renderHook( () => useAuth(), { wrapper } ) - -// // Expect the hook to return the correct context value -// expect( result.current ).toEqual( mockAuthContextValue ) -// } ) -// } ) diff --git a/src/lib/supabaseClient.ts b/src/lib/supabaseClient.ts index d11dae2..7545fb8 100644 --- a/src/lib/supabaseClient.ts +++ b/src/lib/supabaseClient.ts @@ -6,7 +6,7 @@ import { AppState } from 'react-native' const supabaseUrl = 'https://uybhrwvodlxtcfgfzezq.supabase.co' // @ts-expect-error @todo: expoConfig not being recognized in definition. -const { SUPABASE_KEY } = Constants.expoConfig.extra +const { SUPABASE_KEY = 'default-key' } = Constants.expoConfig.extra || {} const supabase = createClient( supabaseUrl, SUPABASE_KEY, { auth: { diff --git a/src/redux/slices/todoSlice.ts b/src/redux/slices/todoSlice.ts index 30bdf75..3cb0632 100644 --- a/src/redux/slices/todoSlice.ts +++ b/src/redux/slices/todoSlice.ts @@ -2,7 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { Todo, TodoList } from '../../types/todos' import todoReducers from '../reducers/todoReducers' -interface TodosState { +export interface TodosState { lists: TodoList[]; todos: Todo[]; status: 'idle' | 'loading' | 'succeeded' | 'failed'; diff --git a/tests/AppNavigation.test.temp b/tests/AppNavigation.test.temp new file mode 100644 index 0000000..de8d80a --- /dev/null +++ b/tests/AppNavigation.test.temp @@ -0,0 +1,47 @@ +import React from 'react' +import { render } from '@testing-library/react-native' +import { Provider } from 'react-redux' +import { NavigationContainer } from '@react-navigation/native' +import { SafeAreaProvider } from 'react-native-safe-area-context' +import { jest, it, expect } from '@jest/globals' +import { AppNavigation } from '../App' +import store from '../src/redux/store' +import useAuth from '../src/hooks/useAuth' + +jest.mock( '../src/hooks/useAuth', () => ( { + __esModule: true, + default: jest.fn(), +} ) ) + +it( 'renders AppStack when user is authenticated', () => { + ( useAuth as jest.Mock ).mockReturnValue( { session: { user: {} } } ) + + const { getByText } = render( + + + + + + + , + ) + // Check for text that is unique to AppStack + expect( getByText( 'Main' ) ).toBeTruthy() +} ) + +it( 'renders AuthStack when user is not authenticated', () => { + ( useAuth as jest.Mock ).mockReturnValue( { session: null } ) + + const { getByText } = render( + + + + + + + , + ) + + // Check for text that is unique to AuthStack + expect( getByText( 'SignUp' ) ).toBeTruthy() +} ) diff --git a/tests/hooks/useAuth.test.temp b/tests/hooks/useAuth.test.temp new file mode 100644 index 0000000..6df2393 --- /dev/null +++ b/tests/hooks/useAuth.test.temp @@ -0,0 +1,50 @@ +// @todo: need to adjust testing configs to support imports an file types. +import { renderHook } from '@testing-library/react' +import React, { ReactNode } from 'react' +import { + expect, describe, it, jest, +} from '@jest/globals' +import { User } from '@supabase/supabase-js' +import useAuth from '../../src/hooks/useAuth' +import { AuthContext } from '../../src/providers/AuthProvider' +import { AuthContextType } from '../../src/types/auth' + +describe( 'useAuth', () => { + it( 'should throw an error if used outside of AuthProvider', () => { + const { result } = renderHook( () => useAuth() ) + + // Expect the hook to throw an error when used outside the AuthProvider + expect( result.current.error ).toEqual( + new Error( 'useAuth must be used within an AuthProvider' ), + ) + } ) + + it( 'should return the context value when used within AuthProvider', () => { + // @todo: need to setup a different parser for this. + // Mock the context value conforming to AuthContextType + const mockAuthContextValue: AuthContextType = { + error: null, + loading: false, + session: null, + // @ts-expect-error ignore for testing, not important. + signUpNewUser: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), + // @ts-expect-error ignore for testing, not important. + signInWithEmail: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), + // @ts-expect-error ignore for testing, not important. + signOut: ( jest.fn().mockResolvedValue( undefined ) as jest.Mock ), + user: { id: '1', email: 'test@example.com' } as User, // Mocking user object + } + + // Define the wrapper component with the correct context value + const wrapper = ( { children }: { children: ReactNode } ) => ( + + {children} + + ) + + const { result } = renderHook( () => useAuth(), { wrapper } ) + + // Expect the hook to return the correct context value + expect( result.current ).toEqual( mockAuthContextValue ) + } ) +} ) diff --git a/src/services/getNextStatus.test.ts b/tests/services/getNextStatus.test.ts similarity index 90% rename from src/services/getNextStatus.test.ts rename to tests/services/getNextStatus.test.ts index 4e3571b..d36ed4d 100644 --- a/src/services/getNextStatus.test.ts +++ b/tests/services/getNextStatus.test.ts @@ -1,5 +1,5 @@ import { expect, describe, it } from '@jest/globals' -import getNextStatus, { Status } from './getNextStatus' +import getNextStatus, { Status } from '../../src/services/getNextStatus' describe( 'getNextStatus', () => { it( 'should return PARTIAL when the current status is INCOMPLETE', () => {