diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 96eebfc..66e15fe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,11 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18.18.0' + - name: Install modules run: npm install @@ -21,3 +26,16 @@ jobs: - name: Build run: npm run build + + - name: Start MySQL service + run: sudo systemctl start mysql.service + + - name: Test + # This is just the default settings for GH Actions MySQL + # Nothing secret here aside from the hashed API key + env: + DB_TEST_HOSTNAME: 127.0.0.1 + DB_TEST_USERNAME: root + DB_TEST_PASSWORD: root + HASHED_API_KEY: ${{ secrets.HASHED_API_KEY }} + run: npm run test diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..3929f00 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,14 @@ +import type { Config } from "jest"; + +const config: Config = { + verbose: true, + silent: false, + preset: "ts-jest", + testEnvironment: "node", + coveragePathIgnorePatterns: [ + "/node_modules/", + "/dist", + ] +}; + +export default config; diff --git a/package-lock.json b/package-lock.json index 4330bbe..8de19ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,8 @@ "sequelize": "^6.37.1", "sha3": "^2.1.4", "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", "typescript": "^5.4.2", "uuid": "^8.3.2", "winston": "^3.10.0" @@ -622,6 +624,26 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@dabh/diagnostics": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", @@ -1221,6 +1243,26 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1928,6 +1970,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2011,6 +2064,11 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2291,6 +2349,17 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -2698,6 +2767,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2836,6 +2910,14 @@ "wrappy": "1" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -2898,6 +2980,20 @@ "integrity": "sha512-YsoMB/EGCohGKFyTPYqaFe2B7UCU2MM303dkoowF8DNOdks/4q/00cyhTbBUmM/0FMDoUPmUi/AJ0Aj3E7vO1A==", "peer": true }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.18", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", @@ -3757,6 +3853,33 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -4416,6 +4539,23 @@ "node": ">=8" } }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -5232,6 +5372,11 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5285,6 +5430,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -6252,12 +6402,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -6854,6 +7001,95 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "dependencies": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6998,6 +7234,11 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -7280,6 +7521,14 @@ "node": ">=12" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7708,6 +7957,25 @@ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@dabh/diagnostics": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", @@ -8168,6 +8436,26 @@ "@sinonjs/commons": "^3.0.0" } }, + "@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, "@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -8769,6 +9057,14 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "requires": {} }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "requires": { + "acorn": "^8.11.0" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -8824,6 +9120,11 @@ "picomatch": "^2.0.4" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -9031,6 +9332,14 @@ "update-browserslist-db": "^1.1.0" } }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -9321,6 +9630,11 @@ "prompts": "^2.0.1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -9410,6 +9724,11 @@ "wrappy": "1" } }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, "diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -9460,6 +9779,14 @@ "integrity": "sha512-YsoMB/EGCohGKFyTPYqaFe2B7UCU2MM303dkoowF8DNOdks/4q/00cyhTbBUmM/0FMDoUPmUi/AJ0Aj3E7vO1A==", "peer": true }, + "ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "requires": { + "jake": "^10.8.5" + } + }, "electron-to-chromium": { "version": "1.5.18", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", @@ -10139,6 +10466,32 @@ "flat-cache": "^3.0.4" } }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10596,6 +10949,17 @@ "istanbul-lib-report": "^3.0.0" } }, + "jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + } + }, "jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -11225,6 +11589,11 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11269,6 +11638,11 @@ "semver": "^7.5.3" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -11922,12 +12296,9 @@ } }, "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "send": { "version": "0.18.0", @@ -12345,6 +12716,42 @@ "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "requires": {} }, + "ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "requires": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + } + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -12437,6 +12844,11 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -12646,6 +13058,11 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 71af991..4601642 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "scripts": { "build": "tsc", "lint": "node_modules/.bin/eslint src --ext .ts", - "serve": "node dist/main.js", + "serve": "node dist/src/main.js", "start": "npm run serve", - "test": "jest" + "test": "jest --config jest.config.ts --forceExit --verbose" }, "dependencies": { "@effect/schema": "^0.63.2", @@ -37,6 +37,8 @@ "sequelize": "^6.37.1", "sha3": "^2.1.4", "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", "typescript": "^5.4.2", "uuid": "^8.3.2", "winston": "^3.10.0" @@ -49,11 +51,5 @@ }, "engines": { "node": "18.18.0" - }, - "jest": { - "testEnvironment": "node", - "coveragePathIgnorePatterns": [ - "/node_modules/" - ] } } diff --git a/src/app.ts b/src/app.ts index fe5540e..fa5c4f4 100644 --- a/src/app.ts +++ b/src/app.ts @@ -60,7 +60,7 @@ export function setupApp(app: Express, db: Sequelize) { secure: PRODUCTION } })); - store.sync(); + // store.sync(); app.use(apiKeyMiddleware); diff --git a/src/database.ts b/src/database.ts index 6a05045..b78b66e 100644 --- a/src/database.ts +++ b/src/database.ts @@ -62,18 +62,27 @@ export enum UserType { Admin } -export function getDatabaseConnection() { +export interface DBConnectionOptions { + dbName?: string; + username?: string; + password?: string; + host?: string; +} + +export function getDatabaseConnection(options?: DBConnectionOptions) { // Grab any environment variables dotenv.config(); - const dbName = process.env.DB_NAME as string; - const username = process.env.DB_USERNAME as string; - const password = process.env.DB_PASSWORD; + const dbName = options?.dbName ?? process.env.DB_NAME as string; + const username = options?.username ?? process.env.DB_USERNAME as string; + const password = options?.password ?? process.env.DB_PASSWORD as string; + const host = options?.host ?? process.env.DB_HOSTNAME as string; const database = new Sequelize(dbName, username, password, { - host: process.env.DB_HOSTNAME as string, + host, dialect: "mysql", define: { - timestamps: false + timestamps: false, + engine: "InnoDB", } }); diff --git a/src/models/api_key.ts b/src/models/api_key.ts index 81cceed..a1f4f0d 100644 --- a/src/models/api_key.ts +++ b/src/models/api_key.ts @@ -35,6 +35,5 @@ export function initializeAPIKeyModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/class.ts b/src/models/class.ts index 0b6dd62..887058d 100644 --- a/src/models/class.ts +++ b/src/models/class.ts @@ -64,6 +64,5 @@ export function initializeClassModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/dashboard_class_group.ts b/src/models/dashboard_class_group.ts index 4e0e28d..e3f9221 100644 --- a/src/models/dashboard_class_group.ts +++ b/src/models/dashboard_class_group.ts @@ -31,6 +31,5 @@ export function initializeDashboardClassGroupModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/dummy_class.ts b/src/models/dummy_class.ts index 4309472..c395955 100644 --- a/src/models/dummy_class.ts +++ b/src/models/dummy_class.ts @@ -29,6 +29,5 @@ export function initializeDummyClassModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); -} \ No newline at end of file +} diff --git a/src/models/educator.ts b/src/models/educator.ts index 6c43f12..cdd226d 100644 --- a/src/models/educator.ts +++ b/src/models/educator.ts @@ -101,7 +101,6 @@ export function initializeEducatorModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", indexes: [ { unique: true, diff --git a/src/models/ignore_student.ts b/src/models/ignore_student.ts index d5b067c..aa8412a 100644 --- a/src/models/ignore_student.ts +++ b/src/models/ignore_student.ts @@ -29,6 +29,5 @@ export function initializeIgnoreStudentModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/question.ts b/src/models/question.ts index 72a52ce..a28cbc3 100644 --- a/src/models/question.ts +++ b/src/models/question.ts @@ -67,7 +67,6 @@ export function initializeQuestionModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", indexes: [ { fields: ["tag"] diff --git a/src/models/session.ts b/src/models/session.ts index 7d15920..275138a 100644 --- a/src/models/session.ts +++ b/src/models/session.ts @@ -29,7 +29,6 @@ export function initializeSessionModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", tableName: "Sessions" }); } diff --git a/src/models/stage.ts b/src/models/stage.ts index 8bc5a82..b475c48 100644 --- a/src/models/stage.ts +++ b/src/models/stage.ts @@ -33,7 +33,6 @@ export function initializeStageModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", indexes: [ { unique: true, diff --git a/src/models/stage_state.ts b/src/models/stage_state.ts index 8e224a6..2508a28 100644 --- a/src/models/stage_state.ts +++ b/src/models/stage_state.ts @@ -46,6 +46,5 @@ export function initializeStageStateModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/story.ts b/src/models/story.ts index 372ae42..041fbd9 100644 --- a/src/models/story.ts +++ b/src/models/story.ts @@ -26,6 +26,5 @@ export function initializeStoryModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/story_class.ts b/src/models/story_class.ts index 62425cb..cecf283 100644 --- a/src/models/story_class.ts +++ b/src/models/story_class.ts @@ -35,6 +35,5 @@ export function initializeClassStoryModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/story_state.ts b/src/models/story_state.ts index 1163f15..10d185f 100644 --- a/src/models/story_state.ts +++ b/src/models/story_state.ts @@ -40,6 +40,5 @@ export function initializeStoryStateModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/models/student.ts b/src/models/student.ts index c3a5ac4..880de77 100644 --- a/src/models/student.ts +++ b/src/models/student.ts @@ -110,7 +110,6 @@ export function initializeStudentModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", indexes: [ { unique: true, diff --git a/src/models/student_options.ts b/src/models/student_options.ts index b7e4c50..25f2a1c 100644 --- a/src/models/student_options.ts +++ b/src/models/student_options.ts @@ -49,6 +49,5 @@ export function initializeStudentOptionsModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/hubbles_law/models/async_merged_student_classes.ts b/src/stories/hubbles_law/models/async_merged_student_classes.ts index 2868e8a..79d9cb2 100644 --- a/src/stories/hubbles_law/models/async_merged_student_classes.ts +++ b/src/stories/hubbles_law/models/async_merged_student_classes.ts @@ -44,6 +44,5 @@ export function initializeAsyncMergedHubbleStudentClassesModel(sequelize: Sequel } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/hubbles_law/models/galaxy.ts b/src/stories/hubbles_law/models/galaxy.ts index 10d4938..431afd6 100644 --- a/src/stories/hubbles_law/models/galaxy.ts +++ b/src/stories/hubbles_law/models/galaxy.ts @@ -86,6 +86,5 @@ export function initializeGalaxyModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/hubbles_law/models/hubble_class_data.ts b/src/stories/hubbles_law/models/hubble_class_data.ts index d36a3fb..1529e36 100644 --- a/src/stories/hubbles_law/models/hubble_class_data.ts +++ b/src/stories/hubbles_law/models/hubble_class_data.ts @@ -43,7 +43,6 @@ export function initializeHubbleClassDataModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", freezeTableName: true }); } diff --git a/src/stories/hubbles_law/models/hubble_measurement.ts b/src/stories/hubbles_law/models/hubble_measurement.ts index 5f6ade5..55d5c2f 100644 --- a/src/stories/hubbles_law/models/hubble_measurement.ts +++ b/src/stories/hubbles_law/models/hubble_measurement.ts @@ -82,6 +82,5 @@ export function initializeHubbleMeasurementModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/hubbles_law/models/hubble_student_data.ts b/src/stories/hubbles_law/models/hubble_student_data.ts index 458c489..3b73e60 100644 --- a/src/stories/hubbles_law/models/hubble_student_data.ts +++ b/src/stories/hubbles_law/models/hubble_student_data.ts @@ -43,7 +43,6 @@ export function initializeHubbleStudentDataModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", freezeTableName: true }); } diff --git a/src/stories/hubbles_law/models/sample_measurement.ts b/src/stories/hubbles_law/models/sample_measurement.ts index d106e73..f8088e3 100644 --- a/src/stories/hubbles_law/models/sample_measurement.ts +++ b/src/stories/hubbles_law/models/sample_measurement.ts @@ -89,6 +89,5 @@ export function initializeSampleHubbleMeasurementModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/hubbles_law/models/sync_merged_classes.ts b/src/stories/hubbles_law/models/sync_merged_classes.ts index c35fbe7..ff1c04c 100644 --- a/src/stories/hubbles_law/models/sync_merged_classes.ts +++ b/src/stories/hubbles_law/models/sync_merged_classes.ts @@ -34,6 +34,5 @@ export function initializeSyncMergedHubbleClassesModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/minids/models/eclipse_response.ts b/src/stories/minids/models/eclipse_response.ts index 64c4e02..712bb3f 100644 --- a/src/stories/minids/models/eclipse_response.ts +++ b/src/stories/minids/models/eclipse_response.ts @@ -51,6 +51,5 @@ export function initializeEclipseMiniResponseModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB" }); } diff --git a/src/stories/solar-eclipse-2024/models/eclipse_data.ts b/src/stories/solar-eclipse-2024/models/eclipse_data.ts index 067137c..bd5e00d 100644 --- a/src/stories/solar-eclipse-2024/models/eclipse_data.ts +++ b/src/stories/solar-eclipse-2024/models/eclipse_data.ts @@ -103,6 +103,5 @@ export function initializeSolarEclipse2024DataModel(sequelize: Sequelize) { } }, { sequelize, - engine: "InnoDB", }); } diff --git a/src/tests/root.test.ts b/src/tests/root.test.ts deleted file mode 100644 index 3dc6148..0000000 --- a/src/tests/root.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, it } from "@jest/globals"; - -import testApp, { authorizedRequest } from "./utils"; - -describe("Test root route", async() => { - it("Should show a welcome message", async () => { - void authorizedRequest(testApp) - .get("/") - .expect(200) - .expect("Content-Type", /json/) - .expect({ message: "Welcome to the CosmicDS server!" }); - }); -}); diff --git a/src/tests/utils.ts b/src/tests/utils.ts deleted file mode 100644 index 0444f1a..0000000 --- a/src/tests/utils.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Express } from "express"; -import request from "supertest"; -import { Sequelize } from "sequelize"; - -import { setUpAssociations } from "../associations"; -import { initializeModels } from "../models"; -import { createApp } from "../server"; - -export function authorizedRequest(app: Express) { - return request(app) - .set("Authorization", process.env.CDS_API_KEY); -} - -// Just a pass-through for now -// Maybe we'll add more in the future -export function unauthorizedRequest(app: Express) { - return request(app); -} - -function createTestDatabase(): Sequelize { - const db = new Sequelize({ dialect: "mysql" }); - db.query("CREATE DATABASE IF NOT EXISTS test") - .catch(error => { - console.log(error); - throw new Error(`Error creating test database: ${error}`); - }); - return db; -} - -const testDB = createTestDatabase(); -setUpAssociations(); -initializeModels(testDB); - -const app = createApp(testDB); - -export default app; diff --git a/tests/root.test.ts b/tests/root.test.ts new file mode 100644 index 0000000..826f411 --- /dev/null +++ b/tests/root.test.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/no-floating-promises */ + +import { afterAll, beforeAll, describe, it } from "@jest/globals"; +import type { Express } from "express"; +import type { Sequelize } from "sequelize"; +import request from "supertest"; + +import { authorize, createTestApp, setupTestDatabase, teardownTestDatabase } from "./utils"; +import { setupApp } from "../src/app"; + +let testDB: Sequelize; +let testApp: Express; +beforeAll(async () => { + testDB = await setupTestDatabase(); + testApp = createTestApp(testDB); + setupApp(testApp, testDB); +}, 100_000); + +afterAll(async () => { + await teardownTestDatabase(); +}); + +describe("Test root route", () => { + + it("Should show a welcome message + warning", async () => { + authorize(request(testApp).get("/")) + .expect(200) + .expect("Content-Type", /json/) + .expect({ message: "Welcome to the CosmicDS server! You'll need to include a valid API key with your requests in order to access other endpoints." }); + }); + + it("Should show a welcome message", async () => { + authorize(request(testApp).get("/")) + .expect(200) + .expect("Content-Type", /json/) + .expect({ message: "Welcome to the CosmicDS server!" }); + }, 10_000); +}); diff --git a/tests/utils.ts b/tests/utils.ts new file mode 100644 index 0000000..53b4712 --- /dev/null +++ b/tests/utils.ts @@ -0,0 +1,76 @@ +import type { Express } from "express"; +import type { Server } from "http"; +import type { Test } from "supertest"; +import { Sequelize } from "sequelize"; + +import { setUpAssociations } from "../src/associations"; +import { initializeModels } from "../src/models"; +import { createApp } from "../src/server"; +import { APIKey } from "../src/models/api_key"; +import { config } from "dotenv"; +import { getDatabaseConnection } from "../src/database"; +import { createConnection, Connection } from "mysql2/promise"; + +export function authorize(request: Test): Test { + return request.set({ Authorization: process.env.CDS_API_KEY }); +} + +export async function createTestMySQLConnection(): Promise { + return createConnection({ + host: process.env.DB_TEST_HOSTNAME as string, + user: process.env.DB_TEST_USERNAME as string, + password: process.env.DB_TEST_PASSWORD as string, + }); +} + +export async function setupTestDatabase(): Promise { + config(); + const username = process.env.DB_TEST_USERNAME as string; + const password = process.env.DB_TEST_PASSWORD as string; + const host = process.env.DB_TEST_HOSTNAME as string; + const connection = await createTestMySQLConnection(); + await connection.query("CREATE DATABASE IF NOT EXISTS test;"); + const db = getDatabaseConnection({ + dbName: "test", + username, + password, + host, + }); + await db.query("USE test;"); + initializeModels(db); + setUpAssociations(); + + // We need to close when the connection terminates! + // See https://github.com/sequelize/sequelize/issues/7953 + // and https://stackoverflow.com/a/45114507 + // db.sync({ force: true, match: /test/ }).finally(() => db.close()); + await addTestData(); + + return db; +} + +export async function teardownTestDatabase(): Promise { + const connection = await createTestMySQLConnection(); + await connection.query("DROP DATABASE test;"); +} + +export async function addAPIKey(): Promise { + // Set up some basic data that we're going to want + await APIKey.sync({ force: true }); + return APIKey.create({ + hashed_key: process.env.HASHED_API_KEY as string, + client: "Tests", + }); +} + +export async function addTestData() { + await addAPIKey(); +} + +export function createTestApp(db: Sequelize): Express { + return createApp(db); +} + +export function runApp(app: Express, port = 8080, callback?: () => void): Server { + return app.listen(port, callback); +}