chore: strengthen backend eslint profile
This commit is contained in:
+33
-19
@@ -1,10 +1,12 @@
|
||||
import type { Server } from 'node:http';
|
||||
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import assert from 'node:assert/strict';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type { Server } from 'node:http';
|
||||
import request from 'supertest';
|
||||
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { configureApp } from '../src/main';
|
||||
import {
|
||||
@@ -28,12 +30,12 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
);
|
||||
const money = (value: string) => ({ currency: 'RUB', value });
|
||||
const auth = (
|
||||
method: 'get' | 'post' | 'patch' | 'delete',
|
||||
method: 'delete' | 'get' | 'patch' | 'post',
|
||||
path: string,
|
||||
user = owner,
|
||||
) =>
|
||||
request(app.getHttpServer())
|
||||
[method]('/api/v1/bank-cards' + path)
|
||||
// eslint-disable-next-line security/detect-object-injection -- Keys come from local test fixtures or numeric iteration, not external input.
|
||||
request(app.getHttpServer())[method]('/api/v1/bank-cards' + path)
|
||||
.set('Authorization', `Bearer ${token(user)}`);
|
||||
const createCard = async (value = '1000', user = owner, extra = {}) =>
|
||||
(
|
||||
@@ -102,10 +104,11 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
if (app) await app.close();
|
||||
});
|
||||
it('requires auth and reads never seed data or need T-Bank', async () => {
|
||||
for (const path of ['', '/categories', '/summary?month=2026-08'])
|
||||
for (const path of ['', '/categories', '/summary?month=2026-08']) {
|
||||
await request(app.getHttpServer())
|
||||
.get('/api/v1/bank-cards' + path)
|
||||
.expect(401);
|
||||
}
|
||||
expect((await auth('get', '').expect(200)).body).toEqual([]);
|
||||
expect(await categories()).toEqual([]);
|
||||
expect(await db.expenseCategory.count({ where: { userId: owner } })).toBe(
|
||||
@@ -241,10 +244,11 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
money('92233720368547758.08'),
|
||||
{ currency: 'USD', value: '1' },
|
||||
money('NaN'),
|
||||
])
|
||||
]) {
|
||||
await auth('post', '/operations')
|
||||
.send({ ...op(card.id), amount })
|
||||
.expect(400);
|
||||
}
|
||||
for (const extra of [
|
||||
{ date: '2026-02-30' },
|
||||
{ date: '2099-01-01' },
|
||||
@@ -252,10 +256,11 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
{ description: 'x'.repeat(501) },
|
||||
{ kind: 'topup', categoryId: (await categories())[0].id },
|
||||
{ kind: 'transfer', targetCardId: card.id },
|
||||
])
|
||||
]) {
|
||||
await auth('post', '/operations')
|
||||
.send(op(card.id, 'expense', '1', extra))
|
||||
.expect(400);
|
||||
}
|
||||
expect(await db.bankCardOperation.count()).toBe(before);
|
||||
for (const extra of [
|
||||
{ name: ' ' },
|
||||
@@ -264,7 +269,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
{ lastFour: '123' },
|
||||
{ openingDate: '2026-02-30' },
|
||||
{ openingBalance: money('-92233720368547758.09') },
|
||||
])
|
||||
]) {
|
||||
await auth('post', '')
|
||||
.send({
|
||||
id: randomUUID(),
|
||||
@@ -274,6 +279,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
...extra,
|
||||
})
|
||||
.expect(400);
|
||||
}
|
||||
});
|
||||
it('returns nested money field errors without exposing input or writing a card', async () => {
|
||||
const before = await db.bankCard.count();
|
||||
@@ -310,8 +316,8 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
});
|
||||
|
||||
it('scopes every card/category/expense link and edit to owner', async () => {
|
||||
const own = await createCard(),
|
||||
foreign = await createCard('0', stranger);
|
||||
const foreign = await createCard('0', stranger),
|
||||
own = await createCard();
|
||||
const foreignCategories = (
|
||||
await auth('get', '/categories', stranger).expect(200)
|
||||
).body as ExpenseCategoryDto[];
|
||||
@@ -326,15 +332,17 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
'/' + foreign.id + '/expenses',
|
||||
'/operations/' + foreignOp.id,
|
||||
'/summary?month=2026-08&cardId=' + foreign.id,
|
||||
])
|
||||
]) {
|
||||
await auth('get', path).expect(404);
|
||||
}
|
||||
for (const body of [
|
||||
op(foreign.id),
|
||||
op(own.id, 'expense', '1', { categoryId: foreignCategories[0].id }),
|
||||
op(own.id, 'transfer', '1', { targetCardId: foreign.id }),
|
||||
op(own.id, 'refund', '1', { originalExpenseId: foreignOp.id }),
|
||||
])
|
||||
]) {
|
||||
await auth('post', '/operations').send(body).expect(404);
|
||||
}
|
||||
await auth('patch', '/' + foreign.id)
|
||||
.send({ version: 1, archived: true })
|
||||
.expect(404);
|
||||
@@ -457,7 +465,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
}),
|
||||
),
|
||||
]);
|
||||
expect(responses.map((r) => r.status).sort()).toEqual([201, 409]);
|
||||
expect(responses.map((r) => r.status).sort((a, b) => a - b)).toEqual([201, 409]);
|
||||
const body = op(card.id, 'refund', '400', {
|
||||
date: '2026-09-01',
|
||||
originalExpenseId: expense.id,
|
||||
@@ -484,10 +492,11 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
{ amount: money('999') },
|
||||
{ date: '2026-09-02' },
|
||||
{ cardId: (await createCard()).id },
|
||||
])
|
||||
]) {
|
||||
await auth('patch', '/operations/' + expense.id)
|
||||
.send({ version: current.version, ...patch })
|
||||
.expect(409);
|
||||
}
|
||||
await auth(
|
||||
'delete',
|
||||
`/operations/${expense.id}?version=${current.version}`,
|
||||
@@ -501,6 +510,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
category.id,
|
||||
);
|
||||
});
|
||||
// eslint-disable-next-line sonarjs/assertions-in-tests -- Every rejection is asserted through awaited Supertest .expect(400).
|
||||
it('rejects invalid refund references, dates, immutable kind and purchase link', async () => {
|
||||
const card = await createCard(),
|
||||
other = await createCard();
|
||||
@@ -513,8 +523,9 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
originalExpenseId: purchase.id,
|
||||
date: '2026-07-01',
|
||||
}),
|
||||
])
|
||||
]) {
|
||||
await auth('post', '/operations').send(body).expect(400);
|
||||
}
|
||||
const refund = await createOp(
|
||||
op(card.id, 'refund', '10', { originalExpenseId: purchase.id }),
|
||||
);
|
||||
@@ -532,7 +543,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
await createOp(op(a.id, 'expense', '20'));
|
||||
await createOp(op(a.id, 'expense', '30'));
|
||||
const pages: BankOperationsPageDto[] = [];
|
||||
for (let page = 1; page <= 3; page++)
|
||||
for (let page = 1; page <= 3; page++) {
|
||||
pages.push(
|
||||
(
|
||||
await auth(
|
||||
@@ -541,6 +552,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
).expect(200)
|
||||
).body as BankOperationsPageDto,
|
||||
);
|
||||
}
|
||||
expect(new Set(pages.flatMap((p) => p.items.map((i) => i.id))).size).toBe(
|
||||
3,
|
||||
);
|
||||
@@ -564,8 +576,9 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
for (const body of [
|
||||
op(card.id),
|
||||
op(card.id, 'transfer', '1', { targetCardId: (await createCard()).id }),
|
||||
])
|
||||
]) {
|
||||
await auth('post', '/operations').send(body).expect(409);
|
||||
}
|
||||
await auth('patch', '/operations/' + expense.id)
|
||||
.send({ version: 1, description: 'no' })
|
||||
.expect(409);
|
||||
@@ -625,7 +638,7 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
});
|
||||
expect(
|
||||
refunds.reduce((sum, row) => sum + row.amountKopecks, 0n) <=
|
||||
source.amountKopecks,
|
||||
source.amountKopecks,
|
||||
).toBe(true);
|
||||
});
|
||||
it('serializes opening-date changes and validates archived previous transfer sides', async () => {
|
||||
@@ -755,8 +768,9 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
||||
it('filters journal and summary inclusively across months and rejects invalid periods', async () => {
|
||||
const card = await createCard();
|
||||
const dates = ['2026-07-30', '2026-07-31', '2026-08-01', '2026-08-02'];
|
||||
for (const date of dates)
|
||||
for (const date of dates) {
|
||||
await createOp(op(card.id, 'expense', '10', { date }));
|
||||
}
|
||||
const range = 'from=2026-07-31&to=2026-08-01';
|
||||
const history = (
|
||||
await auth('get', `/${card.id}/operations?${range}&limit=1`).expect(200)
|
||||
|
||||
Reference in New Issue
Block a user