diff --git a/.insomnia.json b/.insomnia.json index cf8df85..4627724 100644 --- a/.insomnia.json +++ b/.insomnia.json @@ -31,7 +31,7 @@ "settingRebuildPath": true, "settingSendCookies": true, "settingStoreCookies": true, - "url": "https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json", + "url": "https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondinfo.json", "_type": "request" }, { @@ -90,7 +90,7 @@ "metaSortKey": -1598209090094, "method": "PUT", "modified": 1598212311229, - "name": "Update all treasury bonds", + "name": "Update all treasury bond", "parameters": [], "parentId": "fld_2a24df81d4fc40299c24389a4fedc93b", "settingDisableRenderRequestBody": false, @@ -99,7 +99,7 @@ "settingRebuildPath": true, "settingSendCookies": true, "settingStoreCookies": true, - "url": "{{baseURL}}/treasurybonds/updateAll", + "url": "{{baseURL}}/treasurybond/updateAll", "_type": "request" }, { @@ -110,7 +110,7 @@ "environmentPropertyOrder": null, "metaSortKey": -1598048831768, "modified": 1598048831768, - "name": "TreasuryBonds", + "name": "TreasuryBond", "parentId": "wrk_37eef8ddc0034da5a3331d14411851a0", "_type": "request_group" }, @@ -134,7 +134,7 @@ "settingRebuildPath": true, "settingSendCookies": true, "settingStoreCookies": true, - "url": "{{baseURL}}/treasurybonds", + "url": "{{baseURL}}/treasurybond", "_type": "request" }, { @@ -166,7 +166,7 @@ "settingRebuildPath": true, "settingSendCookies": true, "settingStoreCookies": true, - "url": "{{baseURL}}/treasurybonds", + "url": "{{baseURL}}/treasurybond", "_type": "request" }, { @@ -180,7 +180,7 @@ "metaSortKey": -1598048869452, "method": "GET", "modified": 1598199043855, - "name": "List Treasury bonds", + "name": "List Treasury bond", "parameters": [], "parentId": "fld_2a24df81d4fc40299c24389a4fedc93b", "settingDisableRenderRequestBody": false, @@ -189,12 +189,15 @@ "settingRebuildPath": true, "settingSendCookies": true, "settingStoreCookies": true, - "url": "{{baseURL}}/treasurybonds", + "url": "{{baseURL}}/treasurybond", "_type": "request" }, { "_id": "req_fe9dd271bc4d433d92927f3e0297df15", - "authentication": { "token": "", "type": "bearer" }, + "authentication": { + "token": "", + "type": "bearer" + }, "body": { "mimeType": "application/json", "text": "{\n\t\"email\": \"redacteduser@privacydomain.com\",\n\t\"password\": \"12345678\"\n}" @@ -609,8 +612,14 @@ "_id": "env_30b2fa03c7c14c6193209f0a7ed69b3f", "color": "#00aa60", "created": 1597617822940, - "data": { "baseURL": "http://localhost:3333" }, - "dataPropertyOrder": { "&": ["baseURL"] }, + "data": { + "baseURL": "http://localhost:3333" + }, + "dataPropertyOrder": { + "&": [ + "baseURL" + ] + }, "isPrivate": false, "metaSortKey": 1597617822940, "modified": 1597617915367, diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 6ede751..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# See https://pre-commit.com for more information -# See https://pre-commit.com/hooks.html for more hooks -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files - - id: check-merge-conflict - - id: check-symlinks - - id: check-vcs-permalinks - - id: detect-private-key - - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.15.0 - hooks: - - id: eslint - args: - [ - --fix, - --report-unused-disable-directives, - --config, - server/.eslintrc.yaml, - ] - types: [file] - types_or: [javascript, jsx, ts, tsx] - verbose: true - additional_dependencies: - - eslint@8.15.0 - - eslint-plugin-import@2.26.0 - - eslint-plugin-jest@26.1.5 - - eslint-plugin-react@6.10.3 - - eslint-import-resolver-typescript@2.2.1 - - '@typescript-eslint/eslint-plugin@5.23.0' - - '@typescript-eslint/parser@5.23.0' - - eslint-config-airbnb-base@15.0.0 - - prettier@2.0.5 - - eslint-plugin-prettier@4.0.0 - - eslint-config-prettier@8.5.0 diff --git a/README.md b/README.md index 5c697fa..a9686cb 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ A web application that notifies you about Brazilian treasury bond rates. # 💻 Project -AlertaDoTesouro is a project elaborated with the intent of automatically monitoring Brazilian government bonds and alerting users about them according to their preferences of rates. Tools such as Node.js, Express, PostgreSQL, Docker, Redis, linting and debugging tools, mail delivery systems, among others, were employed to build this system. +AlertaDoTesouro is a project elaborated with the intent of automatically monitoring Brazilian government bond and alerting users about them according to their preferences of rates. Tools such as Node.js, Express, PostgreSQL, Docker, Redis, linting and debugging tools, mail delivery systems, among others, were employed to build this system. Furthermore, this project was also presented as required academic work for the Integrated Project classes during the 2022/1 semester. The application allows users to set one value per treasury bond, so they can get notified whenever its rate goes above or below that value. Users should be able to be* notified by email or browser notifications. @@ -76,9 +76,9 @@ All files related exlusively to the back-end server are located in `/server`. The back-end REST API is fully functional and was made with Express. Multiple endpoints have been defined and they can be explored extensively by referring to the `.insomnia.json` file, which can be imported into [Insomnia](https://insomnia.rest/) itself or possibly other REST clients. -#### Example: listing treasury bonds +#### Example: listing treasury bond -A typical request would be a simple `GET` request to the `/treasurybonds` endpoint. Response example: +A typical request would be a simple `GET` request to the `/treasurybond` endpoint. Response example: ```bash [ diff --git a/compose.yaml b/compose.yaml index 131700f..1c959b9 100644 --- a/compose.yaml +++ b/compose.yaml @@ -7,9 +7,9 @@ services: - dev env_file: web/.env environment: - - NODE_ENV=development - - BACKEND_BASE_URL=http://server-dev:3333 - - REACT_APP_BASE_URL=http://server-dev:3000 + NODE_ENV: development + BACKEND_BASE_URL: http://server-dev:3333 + REACT_APP_BASE_URL: http://server-dev:3000 restart: on-failure networks: - backend @@ -38,11 +38,12 @@ services: - dev depends_on: - postgres + - postgres_test - redis env_file: server/.env environment: - - NODE_ENV=development - - PORT=3333 + NODE_ENV: development + PORT: 3333 restart: on-failure ports: - '${PORT:-3333}:3333' @@ -52,7 +53,7 @@ services: - ./server:/app - ./.prettierrc.yaml:/.prettierrc.yaml working_dir: /app - command: sh -c 'yarn install && yarn typeorm migration:run && (yarn dev:queue & yarn dev:server)' + command: sh -c 'yarn install && yarn typeorm migration:run && yarn typeorm migration:run --connection test && echo "##MIGATIONS RAN ON TEST DB##" || echo "##MIGATIONS FAILED TO RUN ON TEST DB. If you want to deploy the test database, pass the `--profile test` flag##" ; (yarn dev:queue & yarn dev:server)' # server: # image: node:lts-alpine @@ -61,7 +62,7 @@ services: # env_file: server/.env # environment: # - NODE_ENV=production - # # Treasury bonds database + # # Treasury bond database # - DB_TYPE=postgres # - DB_HOST=postgres # - DB_PORT=5432 @@ -75,7 +76,7 @@ services: # - JWT_SECRET=${JWT_SECRET} # Change to required without breaking dev build # # - JWT_SECRET=${JWT_SECRET?} # - JWT_EXPIRES_IN="1d" - # # Cron schedule for update-all-treasury-bonds task + # # Cron schedule for update-all-treasury-bond task # - UPDATE_CRON=${UPDATE_CRON:-"*/2 * * * *"} # # Cron schedule for check-all-notifications task # - NOTIFICATIONS_CRON=${SEVER_NOTIFICATIONS_CRON:-"*/2 * * * *"} @@ -102,15 +103,24 @@ services: postgres: image: postgres:alpine - environment: - POSTGRES_USER: alertadotesouro - POSTGRES_PASSWORD: your_postgres_password + env_file: server/.env networks: - backend volumes: - db-data:/var/lib/postgresql/data restart: unless-stopped + postgres_test: + image: postgres:alpine + profiles: + - test + env_file: server/.env.test + networks: + - backend + volumes: + - db-data-test:/var/lib/postgresql/data + restart: unless-stopped + redis: image: redis:alpine networks: @@ -122,3 +132,4 @@ networks: volumes: db-data: + db-data-test: diff --git a/server/.env.example b/server/.env.example index 7aa6ad1..809fe2e 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,10 +1,9 @@ -# Treasury bonds database -DB_TYPE=postgres +# Treasury bond database DB_HOST=postgres DB_PORT=5432 -DB_USERNAME=alertadotesouro -DB_PASSWORD=your_postgres_password -DB_DATABASE=alertadotesouro +POSTGRES_USER=alertadotesouro +POSTGRES_PASSWORD=your_postgres_password +POSTGRES_DB=alertadotesouro # JWT secret for password hashing JWT_SECRET=secret_passphrase @@ -14,7 +13,7 @@ JWT_EXPIRES_IN="1d" # Port to run the server on PORT=3333 -# Cron schedule for update-all-treasury-bonds task +# Cron schedule for update-all-treasury-bond task UPDATE_CRON="*/15 * * * *" # Cron schedule for check-all-notifications task NOTIFICATIONS_CRON="*/15 * * * *" diff --git a/server/.env.test.example b/server/.env.test.example new file mode 100644 index 0000000..8a7a166 --- /dev/null +++ b/server/.env.test.example @@ -0,0 +1,6 @@ +# Tests database. Other variables are set to the same values as the production database. +DB_HOST=postgres_test +DB_PORTT=5432 +POSTGRES_USER=alertadotesouro_test +POSTGRES_PASSWORD=your_postgres_password +POSTGRES_DB=alertadotesouro diff --git a/server/.eslintrc.js b/server/.eslintrc.js new file mode 100644 index 0000000..e1bff3d --- /dev/null +++ b/server/.eslintrc.js @@ -0,0 +1,77 @@ +module.exports = { + root: true, + env: { + es2020: true, + node: true, + "jest/globals": true, + }, + extends: [ + "airbnb-base", + "plugin:import/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:jest/recommended", + "plugin:jest/style", + "plugin:prettier/recommended" // This comes last + ], + parserOptions: { + project: require("path").join(__dirname, 'tsconfig.json') + }, + plugins: [ + "prettier", + "@typescript-eslint", + "jest", + ], + settings: { + "import/resolver": { + typescript: {} + } + }, + rules: { + "no-underscore-dangle": "off", + "class-methods-use-this": "off", + "camelcase": "off", + "prettier/prettier": "error", + "no-unused-vars": "off", + "no-console": "off", + "jest/no-disabled-tests": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + + varsIgnorePattern: "^_", + argsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + ignoreRestSiblings: true + } + ], + "@typescript-eslint/naming-convention": [ + "error", + { + format: [ + "camelCase", + "PascalCase", + "UPPER_CASE"], + selector: "default", + leadingUnderscore: "allow" + } + ], + "import/no-extraneous-dependencies": + ["error", { + devDependencies: [ + "**/*.test.js", + "**/*.test.ts", + "**/*.spec.js", + "**/*.spec.ts", + ] + }], + "import/extensions": + [ + "error", + "ignorePackages", + { + ts: "never", + } + ], + } +} diff --git a/server/.eslintrc.yaml b/server/.eslintrc.yaml deleted file mode 100644 index d3060c8..0000000 --- a/server/.eslintrc.yaml +++ /dev/null @@ -1,36 +0,0 @@ ---- -root: true -env: - es2020: true - node: true - jest/globals: true -extends: - - airbnb-base - - plugin:import/recommended - - plugin:@typescript-eslint/recommended - - plugin:jest/recommended - - plugin:jest/style - - plugin:prettier/recommended # This comes last -parser: '@typescript-eslint/parser' -parserOptions: - ecmaVersion: 11 - sourceType: module -plugins: - - prettier - - '@typescript-eslint' - - jest -rules: - class-methods-use-this: - - 'off' - camelcase: 'off' - prettier/prettier: error - import/extensions: - - error - - ignorePackages - - ts: never - tsx: never - no-console: - - 'off' -settings: - import/resolver: - typescript: diff --git a/server/jest.config.ts b/server/jest.config.ts new file mode 100644 index 0000000..cd28547 --- /dev/null +++ b/server/jest.config.ts @@ -0,0 +1,10 @@ +import type { Config } from '@jest/types'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const config: Config.InitialOptions = { + preset: 'ts-jest', + testEnvironment: 'node', +}; +export default config; diff --git a/server/ormconfig.ts b/server/ormconfig.ts index 7b5dd16..a13ec5f 100644 --- a/server/ormconfig.ts +++ b/server/ormconfig.ts @@ -1,19 +1,43 @@ import dotenv from 'dotenv'; +import { ConnectionOptions } from 'typeorm'; import loadRequiredEnv from './src/utils/loadRequiredEnv'; dotenv.config(); - -export = { - type: loadRequiredEnv('DB_TYPE'), - host: loadRequiredEnv('DB_HOST'), - port: loadRequiredEnv('DB_PORT'), - username: loadRequiredEnv('DB_USERNAME'), - password: loadRequiredEnv('DB_PASSWORD'), - database: loadRequiredEnv('DB_DATABASE'), - entities: ['./src/models/*.ts'], - migrations: ['./src/database/migrations/*.ts'], - cli: { - migrationsDir: './src/database/migrations', +const testEnv = dotenv.config({ path: '.env.test' }); +if (testEnv.error) { + throw testEnv.error; +} +const connectionOptions: ConnectionOptions[] = [ + { + name: 'default', + type: 'postgres', + host: loadRequiredEnv('DB_HOST'), + port: Number(loadRequiredEnv('DB_PORT')), + username: loadRequiredEnv('POSTGRES_USER'), + password: loadRequiredEnv('POSTGRES_PASSWORD'), + database: loadRequiredEnv('POSTGRES_DB'), + entities: ['./src/models/*.ts'], + migrations: ['./src/database/migrations/*.ts'], + cli: { + migrationsDir: './src/database/migrations', + }, + }, + { + name: 'test', + type: 'postgres', + host: testEnv.parsed?.DB_HOST, + port: Number(testEnv.parsed?.DB_PORT), + username: testEnv.parsed?.POSTGRES_USER, + password: testEnv.parsed?.POSTGRES_PASSWORD, + database: testEnv.parsed?.POSTGRES_DB, + entities: ['./src/models/*.ts'], + migrations: ['./src/database/migrations/*.ts'], + cli: { + migrationsDir: './src/database/migrations', + }, + dropSchema: true, + logging: true, }, - migrationsTransactionMode: 'each', -}; +]; + +export = connectionOptions; diff --git a/server/package.json b/server/package.json index ba2aed9..5c64317 100644 --- a/server/package.json +++ b/server/package.json @@ -15,11 +15,9 @@ "docs": "typedoc --out docs", "docker:docs": "docker exec -t alertadotesouro-server-dev-1 yarn docs", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", - "lint:fix": "eslint --fix . --ext .js,.jsx,.ts,.tsx", "docker:lint": "docker exec -t alertadotesouro-server-dev-1 yarn lint", - "docker:lint:fix": "docker exec -t alertadotesouro-server-dev-1 yarn lint:fix", - "pretty": "prettier \"**/*\" --write --ignore-unknown", - "docker:pretty": "docker exec -t alertadotesouro-server-dev-1 yarn pretty" + "test": "NODE_ENV=test jest", + "docker:test": "docker exec -t alertadotesouro-server-dev-1 yarn test" }, "dependencies": { "axios": "^0.21.0", @@ -44,10 +42,12 @@ "@types/cors": "^2.8.12", "@types/express": "^4.17.7", "@types/express-handlebars": "^3.1.0", + "@types/jest": "^28.1.0", "@types/jsonwebtoken": "^8.5.0", "@types/node": "^17.0.38", "@types/node-cron": "^3.0.1", "@types/nodemailer": "^6.4.4", + "@types/supertest": "^2.0.12", "@types/uuid": "^8.3.0", "@types/yup": "^0.29.6", "@typescript-eslint/eslint-plugin": "^5.23.0", @@ -61,6 +61,8 @@ "eslint-plugin-prettier": "^4.0.0", "jest": "^28.1.0", "prettier": "^2.0.5", + "supertest": "^6.2.3", + "ts-jest": "^28.0.4", "ts-node": "^10.8.0", "ts-node-dev": "^2.0.0", "typedoc": "^0.22.15", diff --git a/server/src/app.test.ts b/server/src/app.test.ts new file mode 100644 index 0000000..7ad6741 --- /dev/null +++ b/server/src/app.test.ts @@ -0,0 +1,6 @@ +import app from './app'; + +it('Installs all the middleware', () => { + expect(app.listen).toBeDefined(); + // I don't even know what else to test +}); diff --git a/server/src/app.ts b/server/src/app.ts index b55f9d6..10a5db9 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -10,5 +10,4 @@ app.use(cors()); app.use(logRequest); app.use(express.json()); app.use(routes); - export default app; diff --git a/server/src/database/index.test.ts b/server/src/database/index.test.ts new file mode 100644 index 0000000..b1d9ff1 --- /dev/null +++ b/server/src/database/index.test.ts @@ -0,0 +1,21 @@ +import { getConnection } from 'typeorm'; + +import DB from '.'; + +beforeAll(() => { + return DB.connect('test'); +}); + +afterAll(() => { + return DB.close('test'); +}); + +beforeEach(() => { + return DB.clear('test'); +}); + +test('connects to the `TEST` database', () => { + const connection = getConnection('test'); + expect(connection).toBeDefined(); + expect(connection.isConnected).toBeTruthy(); +}); diff --git a/server/src/database/index.ts b/server/src/database/index.ts index c6e6a48..7625ebd 100644 --- a/server/src/database/index.ts +++ b/server/src/database/index.ts @@ -1,3 +1,34 @@ -import { createConnection } from 'typeorm'; +import { createConnection, getConnection } from 'typeorm'; +import 'dotenv/config'; -createConnection(); +const DB = { + async connect(name = 'default') { + await createConnection(name); + }, + + async close(connectionName?: string) { + await getConnection(connectionName).close(); + }, + + clear(connectionName?: string) { + const connection = getConnection(connectionName); + const entities = connection.entityMetadatas; + + entities.forEach(async entity => { + const repository = connection.getRepository(entity.name); + await repository.clear(); + }); + }, + + async drop(connectionName?: string) { + await getConnection(connectionName).dropDatabase(); + }, +}; + +DB.connect().catch(err => { + console.error('❌ Error connecting to DB!'); + console.error(err); + throw err; +}); + +export default DB; diff --git a/server/src/database/migrations/1632517914173-MigrationsRefactoring.ts b/server/src/database/migrations/1632517914173-MigrationsRefactoring.ts index d7b8b62..c24c542 100644 --- a/server/src/database/migrations/1632517914173-MigrationsRefactoring.ts +++ b/server/src/database/migrations/1632517914173-MigrationsRefactoring.ts @@ -7,7 +7,7 @@ export class MigrationsRefactoring1632517914173 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( - `CREATE TABLE "treasurybonds" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "code" integer NOT NULL, "name" text NOT NULL, "expirationDate" TIMESTAMP WITH TIME ZONE NOT NULL, "minimumInvestmentAmount" double precision NOT NULL, "investmentUnitaryValue" double precision NOT NULL, "semianualInterestIndex" boolean NOT NULL, "annualInvestmentRate" double precision NOT NULL, "annualRedRate" double precision NOT NULL, "minimumRedValue" double precision NOT NULL, "ISIN" text NOT NULL, "indexedTo" json NOT NULL, "lastDateOfNegotiation" TIMESTAMP WITH TIME ZONE, "texts" json NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_08c337a5d83f7f0b0c0d884021d" PRIMARY KEY ("id"))`, + `CREATE TABLE "treasurybond" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "code" integer NOT NULL, "name" text NOT NULL, "expirationDate" TIMESTAMP WITH TIME ZONE NOT NULL, "minimumInvestmentAmount" double precision NOT NULL, "investmentUnitaryValue" double precision NOT NULL, "semianualInterestIndex" boolean NOT NULL, "annualInvestmentRate" double precision NOT NULL, "annualRedRate" double precision NOT NULL, "minimumRedValue" double precision NOT NULL, "ISIN" text NOT NULL, "indexedTo" json NOT NULL, "lastDateOfNegotiation" TIMESTAMP WITH TIME ZONE, "texts" json NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_08c337a5d83f7f0b0c0d884021d" PRIMARY KEY ("id"))`, ); await queryRunner.query( `CREATE TABLE "users" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" text NOT NULL, "password" text NOT NULL, "confirmed" boolean DEFAULT false, "notify" boolean, "notifyByEmail" boolean DEFAULT false, "notifyByBrowser" boolean DEFAULT false, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`, @@ -22,7 +22,7 @@ export class MigrationsRefactoring1632517914173 implements MigrationInterface { `ALTER TABLE "notifications" ADD CONSTRAINT "FK_9a8a82462cab47c73d25f49261f" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, ); await queryRunner.query( - `ALTER TABLE "notifications" ADD CONSTRAINT "FK_a69633c09b0ec2abcdde4ca1d59" FOREIGN KEY ("treasurybond_id") REFERENCES "treasurybonds"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + `ALTER TABLE "notifications" ADD CONSTRAINT "FK_a69633c09b0ec2abcdde4ca1d59" FOREIGN KEY ("treasurybond_id") REFERENCES "treasurybond"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, ); } @@ -36,6 +36,6 @@ export class MigrationsRefactoring1632517914173 implements MigrationInterface { await queryRunner.query(`DROP TABLE "notifications"`); await queryRunner.query(`DROP TYPE "notifications_type_enum"`); await queryRunner.query(`DROP TABLE "users"`); - await queryRunner.query(`DROP TABLE "treasurybonds"`); + await queryRunner.query(`DROP TABLE "treasurybond"`); } } diff --git a/server/src/jest.test.ts b/server/src/jest.test.ts new file mode 100644 index 0000000..08f0116 --- /dev/null +++ b/server/src/jest.test.ts @@ -0,0 +1,7 @@ +test('Jest works', () => { + expect(true).toBe(true); + expect(false).toBe(false); + expect(1).toBe(1); + expect(0).toBe(0); + expect(-1).toBe(-1); +}); diff --git a/server/src/jobs/SendDataExportMail.ts b/server/src/jobs/SendDataExportMail.ts index abea3ae..16ba0e7 100644 --- a/server/src/jobs/SendDataExportMail.ts +++ b/server/src/jobs/SendDataExportMail.ts @@ -29,18 +29,19 @@ class DataExportMail { subject: `Alerta do Tesouro - Exportação de seus dados`, text: `

Alerta do Tesouro

`, template: 'data-export', - attachments: [{ - filename: `data_export_${userData.email}.json`, - path: tempFile, - }] + attachments: [ + { + filename: `data_export_${userData.email}.json`, + path: tempFile, + }, + ], }); console.log(`data-export email was just sent to '${userData.email}'.`); // Delete temporary directory await fs.promises.rm(tempDir, { recursive: true }); - } - catch (err) { + } catch (err) { console.log(err); } } diff --git a/server/src/middlewares/ensureAuthenticated.test.ts b/server/src/middlewares/ensureAuthenticated.test.ts new file mode 100644 index 0000000..42c7674 --- /dev/null +++ b/server/src/middlewares/ensureAuthenticated.test.ts @@ -0,0 +1,81 @@ +import { Request, Response } from 'express'; +import ensureAuthenticated from './ensureAuthenticated'; + +describe('ensures', () => { + // FIXME not actually throwing WTF but when env is actually no set on server it throws. I don't think it have anything to do with asynchronous tests and such, since they are on different threads. + it.skip('fails when `JWT_SECRET` env is not set', () => { + const request = { + // Is there a way to modularize this better? Doesn't feel DRY enough. + headers: { + authorization: 'Bearer 12345', + }, + } as Request; // Asserting to type is fine to mock a request, that's the whole point; + const next = jest.fn(); + delete process.env.JWT_SECRET; + expect(() => + ensureAuthenticated(request, null as unknown as Response, next), + ).toThrow(); + }); + + it('rejects when JWT is missing', () => { + const request = { + headers: { + // authorization: 'Bearer 12345', + }, + } as Request; // Asserting to type is fine to mock a request, that's the whole point; + const next = jest.fn(); + ensureAuthenticated( + request, + null as unknown as Response, // Passing stuff "force-asserting" like this is fine since for this function specifically it won't use it ever -- it's even names as `_` in the function definition + next, + ); + expect(next.mock.calls).toHaveLength(1); + // REVIEW - I don't know how to hard type `jest.fn.mock.calls` since they are `any[]` + expect(next.mock.calls[0][0] instanceof Error).toBeTruthy(); + expect(next.mock.calls[0][0].message).toBe( + 'Invalid JSON Web Token: JSON Web Token is missing', + ); + }); + + // TODO + it.todo('validates a valid and authentic JWT'); + + describe('rejects JWT present but invalid', () => { + it('not in Bearer token format', () => { + const request = { + headers: { + authorization: '12345', + }, + } as Request; + const next = jest.fn(); + + ensureAuthenticated(request, null as unknown as Response, next); + + expect(next.mock.calls).toHaveLength(1); + expect(next.mock.calls[0][0] instanceof Error).toBeTruthy(); + expect(next.mock.calls[0][0].message).toBe( + 'Invalid JSON Web Token: jwt must be provided', + ); + }); + + it('rejects malformed JWT token', () => { + const request = { + headers: { + authorization: 'Bearer 12345', + }, + } as Request; + const next = jest.fn(); + + ensureAuthenticated(request, null as unknown as Response, next); + + expect(next.mock.calls).toHaveLength(1); + expect(next.mock.calls[0][0] instanceof Error).toBeTruthy(); + expect(next.mock.calls[0][0].message).toBe( + 'Invalid JSON Web Token: jwt malformed', + ); + }); + + // TODO + it.todo('invalid JWT token'); + }); +}); diff --git a/server/src/middlewares/ensureAuthenticated.ts b/server/src/middlewares/ensureAuthenticated.ts index 83018e1..dde941b 100644 --- a/server/src/middlewares/ensureAuthenticated.ts +++ b/server/src/middlewares/ensureAuthenticated.ts @@ -33,14 +33,13 @@ export default function ensureAuthenticated( ): void { const authHeader = request.headers.authorization; - if (!authHeader) { - throw new Error('JSON Web Token is missing'); - } - try { + if (!authHeader) { + throw new Error('JSON Web Token is missing'); + } const [, token] = authHeader.split(' '); // Do not use "type" of token (Bearer) - const decoded = verify(token, authConfig.jwt.secret as string); + const decoded = verify(token, authConfig.jwt.secret); const { sub } = decoded as TokenPayload; @@ -51,8 +50,9 @@ export default function ensureAuthenticated( next(); } catch (err) { if (err instanceof Error) { - next(Error(`Invalid JSON Web Token: ${err.message}`)); + next(new Error(`Invalid JSON Web Token: ${err.message}`)); + } else { + next(err); } - next(err); } } diff --git a/server/src/middlewares/requestsLogger.ts b/server/src/middlewares/requestsLogger.ts index fe9b682..de81e93 100644 --- a/server/src/middlewares/requestsLogger.ts +++ b/server/src/middlewares/requestsLogger.ts @@ -14,10 +14,14 @@ export default function logRequest( _: Response, next: NextFunction, ): void { - const { method, url } = request; - const logLabel = `[${method.toUpperCase()}] request to ${url}`; + if (process.env.NODE_ENV !== 'test') { + const { method, url } = request; + const logLabel = `[${method.toUpperCase()}] request to ${url}`; - console.time(logLabel); - next(); - console.timeEnd(logLabel); + console.time(logLabel); + next(); + console.timeEnd(logLabel); + } else { + next(); + } } diff --git a/server/src/models/TreasuryBond.ts b/server/src/models/TreasuryBond.ts index 1dfd072..885f3d0 100644 --- a/server/src/models/TreasuryBond.ts +++ b/server/src/models/TreasuryBond.ts @@ -58,7 +58,7 @@ export interface Index { * @property {Date} created_at - The date when the bond was created in the database * @property {Date} updated_at - The date when the bond was updated in the database */ -@Entity('treasurybonds') +@Entity('treasurybond') class TreasuryBond { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/server/src/routes/index.test.ts b/server/src/routes/index.test.ts new file mode 100644 index 0000000..3280074 --- /dev/null +++ b/server/src/routes/index.test.ts @@ -0,0 +1,17 @@ +import request from 'supertest'; +import app from '../app'; + +describe('/', () => { + test('GET /', async () => { + const res = await request(app).get('/'); + + expect(res.status).toBe(200); + expect(res.headers).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8', + ); + expect(res.body).toMatchObject({ + message: '🌐 AlertaDoTesouro is online.', + }); + }); +}); diff --git a/server/src/routes/index.ts b/server/src/routes/index.ts index cf2d2b4..dd6723c 100644 --- a/server/src/routes/index.ts +++ b/server/src/routes/index.ts @@ -2,23 +2,23 @@ import { Router } from 'express'; import usersRouter from './users.routes'; import notificationsRouter from './notifications.routes'; import sessionsRouter from './sessions.routes'; -import treasuryBondsRouter from './treasurybonds.routes'; +import treasuryBondRouter from './treasurybond.routes'; import emailRouter from './email.routes'; // Define main Router const routes = Router(); /** - * Root route of the API (/); returns a plain text message. + * Root route of the API (/); returns a json message. */ routes.get('/', async (_, response) => { - return response.send('🌐 AlertaDoTesouro is online.'); + return response.json({ message: '🌐 AlertaDoTesouro is online.' }); }); // Define all main routes of the API with their respective sub-routes routes.use('/users', usersRouter); routes.use('/sessions', sessionsRouter); -routes.use('/treasurybonds', treasuryBondsRouter); +routes.use('/treasurybond', treasuryBondRouter); routes.use('/notifications', notificationsRouter); routes.use('/email', emailRouter); diff --git a/server/src/routes/notifications.routes.ts b/server/src/routes/notifications.routes.ts index b8b5d4f..28c63b1 100644 --- a/server/src/routes/notifications.routes.ts +++ b/server/src/routes/notifications.routes.ts @@ -55,7 +55,7 @@ notificationsRouter.post('/', async (request, response, next) => { }); const userRepository = getRepository(User); - const findUser: User | undefined = await userRepository.findOne(user_id); + const findUser: User | undefined = await userRepository.findOne(user_id); if (!findUser) { throw new Error('User not found when creating notification'); diff --git a/server/src/routes/treasurybond.routes.ts b/server/src/routes/treasurybond.routes.ts new file mode 100644 index 0000000..cbffa73 --- /dev/null +++ b/server/src/routes/treasurybond.routes.ts @@ -0,0 +1,36 @@ +import { Router } from 'express'; +import { getRepository, RepositoryNotTreeError } from 'typeorm'; +import CreateTreasuryBondService from '../services/CreateTreasuryBondService'; +import TreasuryBond from '../models/TreasuryBond'; +import UpdateTreasuryBondService from '../services/UpdateTreasuryBondService'; + +const treasuryBondRouter = Router(); + +/** + * Endpoint for listing all treasury bond. + */ +treasuryBondRouter.get('/', async (_request, response) => { + const treasuryBondRepository = getRepository(TreasuryBond); + const treasuryBond = await treasuryBondRepository.find(); + + return response.json(treasuryBond); +}); + +/** + * Endpoint for updating all treasury bond. // REVIEW: this shouldn't exist... + */ +treasuryBondRouter.put('/', async (_request, response, next) => { + const updateTreasuryBond = new UpdateTreasuryBondService(); + try { + const checkResult = await updateTreasuryBond.execute(); + console.log('Successfully updated all treasury bond in the database!'); + return response.json({ + ok: checkResult, + message: 'Successfully updated all treasury bond', + }); + } catch (err) { + next(err); + } +}); + +export default treasuryBondRouter; diff --git a/server/src/routes/treasurybonds.routes.ts b/server/src/routes/treasurybonds.routes.ts deleted file mode 100644 index da3f998..0000000 --- a/server/src/routes/treasurybonds.routes.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Router } from 'express'; -import { getRepository, RepositoryNotTreeError } from 'typeorm'; -import CreateTreasuryBondService from '../services/CreateTreasuryBondService'; -import TreasuryBond from '../models/TreasuryBond'; -import UpdateTreasuryBondService from '../services/UpdateTreasuryBondService'; - -const treasuryBondsRouter = Router(); - -/** - * Endpoint for listing all treasury bonds. - */ -treasuryBondsRouter.get('/', async (_request, response) => { - const treasuryBondsRepository = getRepository(TreasuryBond); - const treasuryBond = await treasuryBondsRepository.find(); - - return response.json(treasuryBond); -}); - -/** - * Endpoint for updating all treasury bonds. // REVIEW: this shouldn't exist... - */ -treasuryBondsRouter.put('/', async (_request, response, next) => { - const updateTreasuryBonds = new UpdateTreasuryBondService(); - try { - const checkResult = await updateTreasuryBonds.execute(); - console.log('Successfully updated all treasury bonds in the database!'); - return response.json({ - ok: checkResult, - message: 'Successfully updated all treasury bonds', - }); - } catch (err) { - next(err); - } -}); - -export default treasuryBondsRouter; diff --git a/server/src/server.ts b/server/src/server.ts index ce8e060..89fbb18 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,5 +1,5 @@ import 'reflect-metadata'; -import App from './app'; +import app from './app'; import loadRequiredEnv from './utils/loadRequiredEnv'; import './database'; @@ -10,6 +10,6 @@ const PORT = loadRequiredEnv('PORT'); /** * Start the server */ -App.listen(PORT, () => { +app.listen(PORT, () => { console.log(`Server started on port ${PORT}!`); }); diff --git a/server/src/services/CheckNotificationsValueService.ts b/server/src/services/CheckNotificationsValueService.ts index 2c4c9e2..07e6fab 100644 --- a/server/src/services/CheckNotificationsValueService.ts +++ b/server/src/services/CheckNotificationsValueService.ts @@ -12,26 +12,26 @@ class CheckNotificationsValueService { const notificationRepository = getRepository(Notification); const treasuryBondRepository = getRepository(TreasuryBond); - const treasuryBonds = await treasuryBondRepository.find({ + const treasuryBond = await treasuryBondRepository.find({ where: { lastDateOfNegotiation: IsNull() }, relations: ['notifications', 'notifications.user'], }); - // Check if there are any treasury bonds that exceed the conditions of any notification - for (const treasuryBond of treasuryBonds) { - for (const notification of treasuryBond.notifications) { - if (!treasuryBond.lastDateOfNegotiation) { + // Check if there are any treasury bond that exceed the conditions of any notification + for (const bond of treasuryBond) { + for (const notification of bond.notifications) { + if (!bond.lastDateOfNegotiation) { switch (notification.type) { case 'maior': if ( - treasuryBond.annualInvestmentRate > notification.value && + bond.annualInvestmentRate > notification.value && notification.active && notification.user.notify ) { if (notification.user.notifyByEmail) { await Queue.add(NotifyBondReturns.key, { notification, - treasuryBond, + treasuryBond: bond, findUser: notification.user, }); @@ -47,14 +47,14 @@ class CheckNotificationsValueService { break; default: if ( - treasuryBond.annualInvestmentRate < notification.value && + bond.annualInvestmentRate < notification.value && notification.active && notification.user.notify ) { if (notification.user.notifyByEmail) { await Queue.add(NotifyBondReturns.key, { notification, - treasuryBond, + treasuryBond: bond, findUser: notification.user, }); diff --git a/server/src/services/CreateNotificationService.ts b/server/src/services/CreateNotificationService.ts index 9c39ff4..f2169a5 100644 --- a/server/src/services/CreateNotificationService.ts +++ b/server/src/services/CreateNotificationService.ts @@ -53,7 +53,9 @@ class CreateNotificationService { // Fetch the TreasuryBond to be included related to the Notification const treasuryBondRepository = getRepository(TreasuryBond); - const bond: TreasuryBond | undefined = await treasuryBondRepository.findOne({ id: treasurybond_id }); + const bond: TreasuryBond | undefined = await treasuryBondRepository.findOne( + { id: treasurybond_id }, + ); const notification = notificationsRepository.create({ user_id, diff --git a/server/src/services/CreateTreasuryBondService.ts b/server/src/services/CreateTreasuryBondService.ts index 18f5af6..459d37d 100644 --- a/server/src/services/CreateTreasuryBondService.ts +++ b/server/src/services/CreateTreasuryBondService.ts @@ -39,18 +39,19 @@ class CreateTreasuryBondService { indexedTo, texts, }: Request): Promise { - const treasuryBondsRepository = getRepository(TreasuryBond); + const treasuryBondRepository = getRepository(TreasuryBond); - const checkIfTreasuryBondExists: TreasuryBond | undefined = await treasuryBondsRepository.findOne({ - where: { code }, - }); + const checkIfTreasuryBondExists: TreasuryBond | undefined = + await treasuryBondRepository.findOne({ + where: { code }, + }); if (checkIfTreasuryBondExists) { throw new Error('Treasury bond is already in the database.'); } console.log(texts); - const treasuryBond = treasuryBondsRepository.create({ + const treasuryBond = treasuryBondRepository.create({ code, name, expirationDate, @@ -65,7 +66,7 @@ class CreateTreasuryBondService { texts, }); - await treasuryBondsRepository.save(treasuryBond); + await treasuryBondRepository.save(treasuryBond); return treasuryBond; } diff --git a/server/src/services/CreateUserSessionService.ts b/server/src/services/CreateUserSessionService.ts index 74b5c0a..d4cd620 100644 --- a/server/src/services/CreateUserSessionService.ts +++ b/server/src/services/CreateUserSessionService.ts @@ -29,7 +29,9 @@ export default class CreateUserSessionService { public async execute({ email, password }: Request): Promise { const usersRepository = getRepository(User); - const user: User | undefined = await usersRepository.findOne({ where: { email } }); + const user: User | undefined = await usersRepository.findOne({ + where: { email }, + }); if (!user) { throw new Error('Incorrect email/password combination.'); diff --git a/server/src/services/DeleteNotificationService.ts b/server/src/services/DeleteNotificationService.ts index 31ba430..2d42b73 100644 --- a/server/src/services/DeleteNotificationService.ts +++ b/server/src/services/DeleteNotificationService.ts @@ -10,9 +10,10 @@ class DeleteNotificationService { notification_id: string, ): Promise { const notificationRepository = getRepository(Notification); - const findNotification: Notification | undefined = await notificationRepository.findOne({ - where: { user_id }, - }); + const findNotification: Notification | undefined = + await notificationRepository.findOne({ + where: { user_id }, + }); if (!findNotification) { throw new Error('This notification does not exist.'); diff --git a/server/src/services/DeleteUserService.ts b/server/src/services/DeleteUserService.ts index 3c419ef..6c6fc44 100644 --- a/server/src/services/DeleteUserService.ts +++ b/server/src/services/DeleteUserService.ts @@ -8,7 +8,7 @@ class DeleteUserService { public async execute(user_id: string): Promise { // Search and delete user from the database const userRepository = getRepository(User); - const findUser: User | undefined = await userRepository.findOne({ + const findUser: User | undefined = await userRepository.findOne({ where: { id: user_id }, }); diff --git a/server/src/services/Queue.ts b/server/src/services/Queue.ts index 0680a42..c4315ba 100644 --- a/server/src/services/Queue.ts +++ b/server/src/services/Queue.ts @@ -5,7 +5,12 @@ import SendConfirmAccountMail from '../jobs/SendConfirmAccountMail'; import SendResetPasswordMail from '../jobs/SendResetPasswordMail'; import SendDataExportMail from '../jobs/SendDataExportMail'; -const jobs = [NotifyBondReturns, SendConfirmAccountMail, SendResetPasswordMail, SendDataExportMail]; +const jobs = [ + NotifyBondReturns, + SendConfirmAccountMail, + SendResetPasswordMail, + SendDataExportMail, +]; /** * @class Queue diff --git a/server/src/services/ResetUserPasswordService.ts b/server/src/services/ResetUserPasswordService.ts index f134ba2..3f55545 100644 --- a/server/src/services/ResetUserPasswordService.ts +++ b/server/src/services/ResetUserPasswordService.ts @@ -37,7 +37,7 @@ class ResetPasswordService { const userRepository = getRepository(User); - const findUser: User | undefined = await userRepository.findOne({ + const findUser: User | undefined = await userRepository.findOne({ where: { id: user_id }, }); diff --git a/server/src/services/UpdateTreasuryBondService.ts b/server/src/services/UpdateTreasuryBondService.ts index bbf8759..aa9a1f0 100644 --- a/server/src/services/UpdateTreasuryBondService.ts +++ b/server/src/services/UpdateTreasuryBondService.ts @@ -1,7 +1,7 @@ import * as uuid from 'uuid'; import { getRepository } from 'typeorm'; import TreasuryBond from '../models/TreasuryBond'; -import { fetchListOfTreasuryBonds } from '../utils/fetchTBAPI'; +import { fetchListOfTreasuryBond } from '../utils/fetchTBAPI'; /** * @class UpdateTreasuryBondService @@ -9,11 +9,11 @@ import { fetchListOfTreasuryBonds } from '../utils/fetchTBAPI'; */ class UpdateTreasuryBondService { public async execute(): Promise { - const treasuryBondsRepository = getRepository(TreasuryBond); + const treasuryBondRepository = getRepository(TreasuryBond); - const treasuryBondsList = await fetchListOfTreasuryBonds(); + const treasuryBondList = await fetchListOfTreasuryBond(); try { - for (const tb of treasuryBondsList) { + for (const tb of treasuryBondList) { const currentTb = tb.TrsrBd; const code = currentTb.cd; const name = currentTb.nm; @@ -37,7 +37,7 @@ class UpdateTreasuryBondService { }; // Insert treasurybond into database or update if already exists - const treasuryBond = treasuryBondsRepository.create({ + const treasuryBond = treasuryBondRepository.create({ code, name, expirationDate, @@ -55,22 +55,23 @@ class UpdateTreasuryBondService { // Generate uuid to be used if TreasuryBond is new treasuryBond.id = uuid.v4(); - const treasuryBondExists: TreasuryBond | undefined = await treasuryBondsRepository.findOne({ - where: { code }, - }); + const treasuryBondExists: TreasuryBond | undefined = + await treasuryBondRepository.findOne({ + where: { code }, + }); // If it doesn't exist, insert it if (treasuryBondExists) { treasuryBond.id = treasuryBondExists.id; - treasuryBondsRepository.update(treasuryBond.id, treasuryBond); + treasuryBondRepository.update(treasuryBond.id, treasuryBond); } else { - await treasuryBondsRepository.insert(treasuryBond); + await treasuryBondRepository.insert(treasuryBond); } - treasuryBondsRepository.save(treasuryBond); + treasuryBondRepository.save(treasuryBond); } return true; } catch (err) { - console.log(`Failed while trying to update treasury bonds:${err}`); + console.log(`Failed while trying to update treasury bond:${err}`); return false; } } diff --git a/server/src/services/UpdateUserService.ts b/server/src/services/UpdateUserService.ts index 0076fa5..9450959 100644 --- a/server/src/services/UpdateUserService.ts +++ b/server/src/services/UpdateUserService.ts @@ -48,7 +48,7 @@ class UpdateUserService { const userRepository = getRepository(User); - const findUser: User | undefined = await userRepository.findOne({ + const findUser: User | undefined = await userRepository.findOne({ where: { id: user_id }, }); diff --git a/server/src/tasks.ts b/server/src/tasks.ts index f150658..3cc494e 100644 --- a/server/src/tasks.ts +++ b/server/src/tasks.ts @@ -4,15 +4,15 @@ import UpdateTreasuryBondService from './services/UpdateTreasuryBondService'; import loadRequiredEnv from './utils/loadRequiredEnv'; /** - * Cron job to check the value of all treasury bonds and update the database. + * Cron job to check the value of all treasury bond and update the database. */ cron.schedule(loadRequiredEnv('UPDATE_CRON'), async () => { - console.log('Running update-all-treasury-bonds task...'); - const updateTreasuryBonds = new UpdateTreasuryBondService(); + console.log('Running update-all-treasury-bond task...'); + const updateTreasuryBond = new UpdateTreasuryBondService(); try { - const checkResult = await updateTreasuryBonds.execute(); + const checkResult = await updateTreasuryBond.execute(); console.log( - `Successfully updated all treasury bonds in the database: ${checkResult}`, + `Successfully updated all treasury bond in the database: ${checkResult}`, ); } catch (err) { console.log(err); diff --git a/server/src/utils/fetchTBAPI.ts b/server/src/utils/fetchTBAPI.ts index 4bf6227..07d28db 100644 --- a/server/src/utils/fetchTBAPI.ts +++ b/server/src/utils/fetchTBAPI.ts @@ -34,7 +34,7 @@ export async function fetchTreasuryBondByCode( ): Promise { // Fetch API const APIUrl = - 'https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json'; + 'https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondinfo.json'; const agent = new https.Agent({ rejectUnauthorized: false, }); @@ -42,10 +42,10 @@ export async function fetchTreasuryBondByCode( httpsAgent: agent, }); - const treasuryBondsList = response.data.response.TrsrBdTradgList; + const treasuryBondList = response.data.response.TrsrBdTradgList; // Look for treasury bond by ID - const treasuryBondJson = treasuryBondsList.find( + const treasuryBondJson = treasuryBondList.find( (tb: any) => tb.TrsrBd.cd === TBCode, ); @@ -54,14 +54,14 @@ export async function fetchTreasuryBondByCode( } /** - * Request treasury bonds from Tesouro Direto's API + * Request treasury bond from Tesouro Direto's API * - * @returns {Promise> | Promise} - Array with treasury bonds data or void if request fails + * @returns {Promise> | Promise} - Array with treasury bond data or void if request fails */ -export async function fetchListOfTreasuryBonds(): Promise> { +export async function fetchListOfTreasuryBond(): Promise> { // Fetch API const APIUrl = - 'https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json'; + 'https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondinfo.json'; const agent = new https.Agent({ rejectUnauthorized: false, @@ -72,14 +72,14 @@ export async function fetchListOfTreasuryBonds(): Promise> { }); try { - const treasuryBondsList: Array = + const treasuryBondList: Array = response.data.response.TrsrBdTradgList; - // console.log(treasuryBondsList); - console.log('Successfully fetched treasury bonds from API.'); - return treasuryBondsList; + // console.log(treasuryBondList); + console.log('Successfully fetched treasury bond from API.'); + return treasuryBondList; } catch (error) { - console.log(`No treasury bonds found: ${error}`); - console.log('Unable to fetch treasury bonds from API.'); + console.log(`No treasury bond found: ${error}`); + console.log('Unable to fetch treasury bond from API.'); return []; } } diff --git a/server/src/utils/loadRequiredEnv.test.ts b/server/src/utils/loadRequiredEnv.test.ts new file mode 100644 index 0000000..fa11e8b --- /dev/null +++ b/server/src/utils/loadRequiredEnv.test.ts @@ -0,0 +1,17 @@ +import loadRequiredEnv from './loadRequiredEnv'; + +describe('loadRequiredEnv', () => { + test('loads variable', () => { + const envName = 'TEST_ENV_VARIABLE'; + process.env[envName] = 'test'; + expect(loadRequiredEnv(envName)).toBe('test'); + }); + + test('throws error when unset', () => { + const envName = 'TEST_ENV_VARIABLE_UNSET'; + // toThrow assertion needs to be called from a wrapping function + expect(() => loadRequiredEnv(envName)).toThrow( + `Undefined required env '${envName}'. Please define it in your environment.`, + ); + }); +}); diff --git a/server/src/utils/loadRequiredEnv.ts b/server/src/utils/loadRequiredEnv.ts index 3f03ce7..bcba176 100644 --- a/server/src/utils/loadRequiredEnv.ts +++ b/server/src/utils/loadRequiredEnv.ts @@ -6,7 +6,7 @@ * @throws Error If the environment variable is not available * */ -export default function loadEnvOrThrow(envName: string): string { +export default function loadRequiredEnv(envName: string): string { const env = process.env[`${envName}`]; if (env === undefined) { throw new Error( diff --git a/server/yarn.lock b/server/yarn.lock index 493a45e..b2e92e8 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -701,6 +701,11 @@ dependencies: "@types/node" "*" +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + "@types/cors@^2.8.12": version "2.8.12" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" @@ -756,6 +761,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@^28.1.0": + version "28.1.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.0.tgz#6107d7f8cf46d994e4de23e11f873d61bafe5573" + integrity sha512-ITfF6JJIl9zbEi2k6NmhNE/BiDqfsI/ceqfvdaWaPbcrCpYyyRq4KtDQIWh6vQUru6SqwppODiom/Zhid+np6A== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -788,11 +801,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947" integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g== -"@types/node@^17.0.38": - version "17.0.38" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947" - integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g== - "@types/nodemailer@^6.4.4": version "6.4.4" resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b" @@ -838,6 +846,21 @@ resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== +"@types/superagent@*": + version "4.1.15" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.15.tgz#63297de457eba5e2bc502a7609426c4cceab434a" + integrity sha512-mu/N4uvfDN2zVQQ5AYJI/g4qxn2bHB6521t1UuH09ShNWjebTqN0ZFuYK9uYjcgmI0dTQEs+Owi1EO6U0OkOZQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" + integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== + dependencies: + "@types/superagent" "*" + "@types/uuid@^8.3.0": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" @@ -1075,6 +1098,16 @@ array.prototype.flat@^1.2.5: es-abstract "^1.19.2" es-shim-unscopables "^1.0.0" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + axios@^0.21.0: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -1222,6 +1255,13 @@ browserslist@^4.20.2: node-releases "^2.0.3" picocolors "^1.0.0" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -1387,6 +1427,18 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +component-emitter@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1426,6 +1478,11 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookiejar@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== + cors@^2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -1492,6 +1549,11 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -1507,6 +1569,19 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +dezalgo@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ== + dependencies: + asap "^2.0.0" + wrappy "1" + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + diff-sequences@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.0.2.tgz#40f8d4ffa081acbd8902ba35c798458d0ff1af41" @@ -1968,7 +2043,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1978,6 +2053,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" @@ -2057,6 +2137,25 @@ follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formidable@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" + integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ== + dependencies: + dezalgo "1.0.3" + hexoid "1.0.0" + once "1.4.0" + qs "6.9.3" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -2258,6 +2357,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hexoid@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -2330,7 +2434,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2601,6 +2705,16 @@ jest-config@^28.1.0: slash "^3.0.0" strip-json-comments "^3.1.1" +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + jest-diff@^28.1.0: version "28.1.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.0.tgz#77686fef899ec1873dbfbf9330e37dd429703269" @@ -2641,6 +2755,11 @@ jest-environment-node@^28.1.0: jest-mock "^28.1.0" jest-util "^28.1.0" +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + jest-get-type@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" @@ -2673,6 +2792,16 @@ jest-leak-detector@^28.1.0: jest-get-type "^28.0.2" pretty-format "^28.1.0" +jest-matcher-utils@^27.0.0: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + jest-matcher-utils@^28.1.0: version "28.1.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz#2ae398806668eeabd293c61712227cb94b250ccf" @@ -2823,7 +2952,7 @@ jest-snapshot@^28.1.0: pretty-format "^28.1.0" semver "^7.3.5" -jest-util@^28.1.0: +jest-util@^28.0.0, jest-util@^28.1.0: version "28.1.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.0.tgz#d54eb83ad77e1dd441408738c5a5043642823be5" integrity sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA== @@ -3042,6 +3171,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -3076,7 +3210,7 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@^1.1.1: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -3113,7 +3247,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@~1.1.2: +methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -3131,7 +3265,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -3143,6 +3277,11 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -3311,7 +3450,7 @@ on-finished@2.4.1: dependencies: ee-first "1.1.1" -once@^1.3.0: +once@1.4.0, once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -3576,6 +3715,15 @@ prettier@^2.0.5: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== +pretty-format@^27.0.0, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + pretty-format@^28.1.0: version "28.1.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.0.tgz#8f5836c6a0dfdb834730577ec18029052191af55" @@ -3620,13 +3768,18 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.10.3: +qs@6.10.3, qs@^6.10.3: version "6.10.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== dependencies: side-channel "^1.0.4" +qs@6.9.3: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -3647,11 +3800,25 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + react-is@^18.0.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -3764,7 +3931,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.2.1, safe-buffer@^5.0.1: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -3784,6 +3951,13 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +semver@7.x, semver@^7.3.5, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -3794,13 +3968,6 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.5, semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -3966,6 +4133,13 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -3998,6 +4172,31 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +superagent@^7.1.3: + version "7.1.6" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.6.tgz#64f303ed4e4aba1e9da319f134107a54cacdc9c6" + integrity sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.3" + debug "^4.3.4" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^2.0.1" + methods "^1.1.2" + mime "2.6.0" + qs "^6.10.3" + readable-stream "^3.6.0" + semver "^7.3.7" + +supertest@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.2.3.tgz#291b220126e5faa654d12abe1ada3658757c8c67" + integrity sha512-3GSdMYTMItzsSYjnIcljxMVZKPW1J9kYHZY+7yLfD0wpPwww97GeImZC1oOk0S5+wYl2niJwuFusBJqwLqYM3g== + dependencies: + methods "^1.1.2" + superagent "^7.1.3" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4110,6 +4309,20 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +ts-jest@^28.0.4: + version "28.0.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.4.tgz#0ab705a60fc4b9f3506f35e26edfa9e9c915c31b" + integrity sha512-S6uRDDdCJBvnZqyGjB4VCnwbQrbgdL8WPeP4jevVSpYsBaeGRQAIS08o3Svav2Ex+oXwLgJ/m7F24TNq62kA1A== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^20.x" + ts-node-dev@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" @@ -4283,6 +4496,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -4412,7 +4630,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.x: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== diff --git a/thunder-tests/thunderCollection.json b/thunder-tests/thunderCollection.json index b2d74fb..48e7952 100644 --- a/thunder-tests/thunderCollection.json +++ b/thunder-tests/thunderCollection.json @@ -14,7 +14,7 @@ }, { "_id": "9fbecb26-ed75-4c52-9f2a-8c41e4c66f50", - "name": "TreasuryBonds", + "name": "TreasuryBond", "containerId": "", "created": "2022-06-02T04:17:51.875Z", "sortNum": 2 @@ -61,4 +61,4 @@ "tests": [] } } -] \ No newline at end of file +] diff --git a/thunder-tests/thunderclient.json b/thunder-tests/thunderclient.json index 090088f..3c6f265 100644 --- a/thunder-tests/thunderclient.json +++ b/thunder-tests/thunderclient.json @@ -17,8 +17,8 @@ "_id": "e2ec7445-5964-46e2-99e4-9b8e3dd95f0f", "colId": "322f5698-0674-4053-af06-78aa8fe9a378", "containerId": "9fbecb26-ed75-4c52-9f2a-8c41e4c66f50", - "name": "Update all treasury bonds", - "url": "{{baseURL}}/treasurybonds/updateAll", + "name": "Update all treasury bond", + "url": "{{baseURL}}/treasurybond/updateAll", "method": "PUT", "sortNum": 20000, "created": "2022-06-02T04:17:51.898Z", @@ -32,7 +32,7 @@ "colId": "322f5698-0674-4053-af06-78aa8fe9a378", "containerId": "9fbecb26-ed75-4c52-9f2a-8c41e4c66f50", "name": "Update Treasury bond", - "url": "{{baseURL}}/treasurybonds", + "url": "{{baseURL}}/treasurybond", "method": "PUT", "sortNum": 30000, "created": "2022-06-02T04:17:51.899Z", @@ -46,7 +46,7 @@ "colId": "322f5698-0674-4053-af06-78aa8fe9a378", "containerId": "9fbecb26-ed75-4c52-9f2a-8c41e4c66f50", "name": "Create Treasury bond", - "url": "{{baseURL}}/treasurybonds", + "url": "{{baseURL}}/treasurybond", "method": "POST", "sortNum": 40000, "created": "2022-06-02T04:17:51.900Z", @@ -63,8 +63,8 @@ "_id": "42e36405-f56a-4a50-9be7-bfbcd9af64b4", "colId": "322f5698-0674-4053-af06-78aa8fe9a378", "containerId": "9fbecb26-ed75-4c52-9f2a-8c41e4c66f50", - "name": "List Treasury bonds", - "url": "{{baseURL}}/treasurybonds", + "name": "List Treasury bond", + "url": "{{baseURL}}/treasurybond", "method": "GET", "sortNum": 50000, "created": "2022-06-02T04:17:51.901Z", @@ -269,7 +269,7 @@ "colId": "322f5698-0674-4053-af06-78aa8fe9a378", "containerId": "", "name": "API TD", - "url": "https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json", + "url": "https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondinfo.json", "method": "GET", "sortNum": 160000, "created": "2022-06-02T04:17:51.912Z", @@ -297,4 +297,4 @@ "params": [], "tests": [] } -] \ No newline at end of file +] diff --git a/web/.eslintrc.yaml b/web/.eslintrc.yaml index cc72832..abb0669 100644 --- a/web/.eslintrc.yaml +++ b/web/.eslintrc.yaml @@ -23,13 +23,15 @@ settings: react: version: detect rules: - no-alert: off jsx-a11y/label-has-associated-control: off no-underscore-dangle: off + no-console: off no-unused-vars: off + jest/no-disabled-tests: off react/prop-types: off react/jsx-props-no-spreading: off react/require-default-props: off # https://stackoverflow.com/a/69746922/12921102 + react-hooks/exhaustive-deps: warn "@typescript-eslint/unbound-method": off # FIXME (?) "@typescript-eslint/no-misused-promises": - error @@ -49,5 +51,3 @@ rules: selector: "default" leadingUnderscore: allow prettier/prettier: warn - react-hooks/exhaustive-deps: warn - no-console: off diff --git a/web/jest.config.js b/web/jest.config.js new file mode 100644 index 0000000..8cbf894 --- /dev/null +++ b/web/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; \ No newline at end of file diff --git a/web/package.json b/web/package.json index 80402ee..ff334a7 100644 --- a/web/package.json +++ b/web/package.json @@ -50,7 +50,7 @@ "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^14.2.0", - "@types/jest": "^27.5.1", + "@types/jest": "^28.1.0", "@types/node": "^17.0.35", "@types/react": "^18.0.9", "@types/react-dom": "^18.0.5", @@ -72,6 +72,7 @@ "eslint-plugin-react": "^7.30.0", "eslint-plugin-react-hooks": "^4.5.0", "prettier": "^2.6.2", + "ts-jest": "^28.0.4", "typescript": "^4.6.4" } } diff --git a/web/src/pages/Account/index.tsx b/web/src/pages/Account/index.tsx index 0e17697..a9a9ad4 100644 --- a/web/src/pages/Account/index.tsx +++ b/web/src/pages/Account/index.tsx @@ -104,20 +104,26 @@ export default function Account() { try { formRef.current?.setErrors({}); - // Redundant validation, but surely is a validation. - const schema = Yup.object().shape({ - oldPassword: Yup.string().min(8, 'Mínimo de 8 caracteres'), - newPassword: Yup.string().min(8, 'Mínimo de 8 caracteres'), - newPasswordConfirmation: Yup.string().when( - 'password', - (password: string, field: Yup.StringSchema) => - password - ? field - .required('Senhas devem ser iguais') - .oneOf([Yup.ref('password')], 'Senhas devem ser iguais') - : field, - ), - }); + const schema = Yup.object().shape({ + email: Yup.string() + .required('Email é obrigatório') + .email('Digite um email válido'), + password: Yup.string().required('Informe sua senha'), + newPassword: Yup.string().oneOf( + [Yup.ref('confirmPassword')], + 'Senhas devem ser iguais', + ), + confirmPassword: Yup.string().when( + 'newPassword', + (newPassword: string, field: Yup.StringSchema) => + newPassword + ? field + .required('É necessário confirmar sua senha') + .min(8, 'Mínimo de 8 caracteres') + .oneOf([Yup.ref('newPassword')], 'Senhas devem ser iguais') + : field, + ), + }); await schema.validate(data, { abortEarly: false, diff --git a/web/src/pages/Account/styles.ts b/web/src/pages/Account/styles.ts index eac5da1..7aaca31 100644 --- a/web/src/pages/Account/styles.ts +++ b/web/src/pages/Account/styles.ts @@ -56,7 +56,7 @@ export const Container = styled.div` background: ${shade(0.1, '#3b9fff')}; } &#exportar-dados { - background: #00AA33; + background: #00aa33; &:hover { background: ${shade(0.1, '#00AA33')}; } diff --git a/web/src/pages/Dashboard/index.tsx b/web/src/pages/Dashboard/index.tsx index 3b7e509..ce2c728 100644 --- a/web/src/pages/Dashboard/index.tsx +++ b/web/src/pages/Dashboard/index.tsx @@ -1,5 +1,5 @@ import { FiCheckCircle, FiClock, FiRefreshCw } from 'react-icons/fi'; -import { Container, BondsList } from './styles'; +import { Container, BondList } from './styles'; import Card from '../../components/Card'; export default function Dashboard() { @@ -27,8 +27,8 @@ export default function Dashboard() { - -
+ +

Títulos indexados ao IPCA

@@ -56,7 +56,7 @@ export default function Dashboard() {
- +
); } diff --git a/web/src/pages/Dashboard/styles.ts b/web/src/pages/Dashboard/styles.ts index 17a99a3..a49b9f1 100644 --- a/web/src/pages/Dashboard/styles.ts +++ b/web/src/pages/Dashboard/styles.ts @@ -58,7 +58,7 @@ export const Container = styled.div` } `; -export const BondsList = styled.div` +export const BondList = styled.div` display: flex; justify-content: center; @@ -66,7 +66,7 @@ export const BondsList = styled.div` flex-direction: column; width: 100%; - div#bonds-list { + div#bond-list { h1 { margin-bottom: 20px; } diff --git a/web/src/pages/ResetPassword/index.tsx b/web/src/pages/ResetPassword/index.tsx index caf9f24..e7aedff 100644 --- a/web/src/pages/ResetPassword/index.tsx +++ b/web/src/pages/ResetPassword/index.tsx @@ -34,8 +34,8 @@ export default function ResetPassword() { (newPassword: string, field: Yup.StringSchema) => newPassword ? field - .required('Senhas devem ser iguais') - .oneOf([Yup.ref('newPassword')], 'Senhas devem ser iguais') + .required('Senhas devem ser iguais') + .oneOf([Yup.ref('newPassword')], 'Senhas devem ser iguais') : field, ), }); diff --git a/web/yarn.lock b/web/yarn.lock index 2387c8f..c665fd7 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -2019,7 +2019,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*": +"@types/jest@*", "@types/jest@^28.1.0": version "28.1.0" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.0.tgz#6107d7f8cf46d994e4de23e11f873d61bafe5573" integrity sha512-ITfF6JJIl9zbEi2k6NmhNE/BiDqfsI/ceqfvdaWaPbcrCpYyyRq4KtDQIWh6vQUru6SqwppODiom/Zhid+np6A== @@ -2027,14 +2027,6 @@ jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" -"@types/jest@^27.5.1": - version "27.5.2" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" - integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== - dependencies: - jest-matcher-utils "^27.0.0" - pretty-format "^27.0.0" - "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -3038,6 +3030,13 @@ browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4 node-releases "^2.0.3" picocolors "^1.0.0" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -4517,7 +4516,7 @@ fast-glob@^3.2.11, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5823,7 +5822,7 @@ jest-util@^27.5.1: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-util@^28.1.0: +jest-util@^28.0.0, jest-util@^28.1.0: version "28.1.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.0.tgz#d54eb83ad77e1dd441408738c5a5043642823be5" integrity sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA== @@ -6153,7 +6152,7 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.memoize@^4.1.2: +lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== @@ -6218,6 +6217,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + makeerror@1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" @@ -7998,18 +8002,18 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: +semver@7.x, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -8644,6 +8648,20 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-jest@^28.0.4: + version "28.0.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.4.tgz#0ab705a60fc4b9f3506f35e26edfa9e9c915c31b" + integrity sha512-S6uRDDdCJBvnZqyGjB4VCnwbQrbgdL8WPeP4jevVSpYsBaeGRQAIS08o3Svav2Ex+oXwLgJ/m7F24TNq62kA1A== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^20.x" + tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" @@ -9313,7 +9331,7 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.x: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==