test: isolate HTTP suites from scheduler and bank-card case order (WealthLedger/backend#65) #100
@@ -9,6 +9,7 @@ import { AppModule } from '../src/app.module';
|
|||||||
import { TbankTokenService } from '../src/integrations/tbank/tbank-token.service';
|
import { TbankTokenService } from '../src/integrations/tbank/tbank-token.service';
|
||||||
import { TbankClient } from '../src/integrations/tbank/tbank.client';
|
import { TbankClient } from '../src/integrations/tbank/tbank.client';
|
||||||
import { configureApp } from '../src/main';
|
import { configureApp } from '../src/main';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
describe('All accounts HTTP boundary', () => {
|
describe('All accounts HTTP boundary', () => {
|
||||||
@@ -31,6 +32,8 @@ describe('All accounts HTTP boundary', () => {
|
|||||||
const module = await Test.createTestingModule({ imports: [AppModule] })
|
const module = await Test.createTestingModule({ imports: [AppModule] })
|
||||||
.overrideProvider(TbankClient)
|
.overrideProvider(TbankClient)
|
||||||
.useValue(upstream)
|
.useValue(upstream)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { AppModule } from '../src/app.module';
|
|||||||
import { loggingOptions } from '../src/common/logging/logging.module';
|
import { loggingOptions } from '../src/common/logging/logging.module';
|
||||||
import { configureApp } from '../src/main';
|
import { configureApp } from '../src/main';
|
||||||
import { AuthService } from '../src/modules/auth/application/auth.service';
|
import { AuthService } from '../src/modules/auth/application/auth.service';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
type Authentication = { accessToken: string; user: { email: string } };
|
type Authentication = { accessToken: string; user: { email: string } };
|
||||||
@@ -33,7 +34,10 @@ describe('Authentication (e2e)', () => {
|
|||||||
},
|
},
|
||||||
assignResponse: true,
|
assignResponse: true,
|
||||||
}),
|
}),
|
||||||
}).compile();
|
})
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
|
.compile();
|
||||||
|
|
||||||
app = moduleFixture.createNestApplication();
|
app = moduleFixture.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
BankSummaryDto,
|
BankSummaryDto,
|
||||||
ExpenseCategoryDto,
|
ExpenseCategoryDto,
|
||||||
} from '../src/modules/banking/bank-cards/presentation/bank-card.dto';
|
} from '../src/modules/banking/bank-cards/presentation/bank-card.dto';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
jest.setTimeout(60000);
|
jest.setTimeout(60000);
|
||||||
@@ -77,7 +78,10 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
|||||||
const start = async () => {
|
const start = async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
imports: [AppModule],
|
imports: [AppModule],
|
||||||
}).compile();
|
})
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
await app.listen(0, '127.0.0.1');
|
await app.listen(0, '127.0.0.1');
|
||||||
@@ -369,6 +373,8 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
|||||||
expect((await getCard(own.id)).balance.value).toBe('1000');
|
expect((await getCard(own.id)).balance.value).toBe('1000');
|
||||||
});
|
});
|
||||||
it('renames default category without role loss; duplicates and stale rename conflict', async () => {
|
it('renames default category without role loss; duplicates and stale rename conflict', async () => {
|
||||||
|
// Defaults are seeded by the first write of the user; this case must not depend on earlier cases.
|
||||||
|
await createCard();
|
||||||
const category = (await categories()).find((c) => c.isDefault);
|
const category = (await categories()).find((c) => c.isDefault);
|
||||||
assert.ok(category);
|
assert.ok(category);
|
||||||
await auth('patch', '/categories/' + category.id)
|
await auth('patch', '/categories/' + category.id)
|
||||||
@@ -725,11 +731,19 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
|||||||
expect(await getCard(card.id)).toEqual(before);
|
expect(await getCard(card.id)).toEqual(before);
|
||||||
expect((await getOp(refund.id)).originalExpenseId).toBe(purchase.id);
|
expect((await getOp(refund.id)).originalExpenseId).toBe(purchase.id);
|
||||||
await auth('post', '/operations').send(deletedBody).expect(410);
|
await auth('post', '/operations').send(deletedBody).expect(410);
|
||||||
|
// The rename is this case's own prerequisite, not an effect of an earlier case.
|
||||||
|
const defaultCategory = (await categories()).find((c) => c.isDefault);
|
||||||
|
assert.ok(defaultCategory);
|
||||||
|
await auth('patch', '/categories/' + defaultCategory.id)
|
||||||
|
.send({ version: defaultCategory.version, name: 'Остальное' })
|
||||||
|
.expect(200);
|
||||||
expect((await categories()).find((c) => c.isDefault)?.name).toBe(
|
expect((await categories()).find((c) => c.isDefault)?.name).toBe(
|
||||||
'Остальное',
|
'Остальное',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('enforces actual FK and unique constraints', async () => {
|
it('enforces actual FK and unique constraints', async () => {
|
||||||
|
// Seeds the owner's default categories so the unique-name check has a real row to collide with.
|
||||||
|
await createCard();
|
||||||
await expect(
|
await expect(
|
||||||
db.expenseCategory.create({
|
db.expenseCategory.create({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { configureApp } from '../src/main';
|
|||||||
import { BondCatalogService } from '../src/modules/investments/instruments/bonds/application/bond-catalog.service';
|
import { BondCatalogService } from '../src/modules/investments/instruments/bonds/application/bond-catalog.service';
|
||||||
import { BondIncomeService } from '../src/modules/investments/instruments/bonds/application/bond-income.service';
|
import { BondIncomeService } from '../src/modules/investments/instruments/bonds/application/bond-income.service';
|
||||||
import { BondMarketService } from '../src/modules/investments/instruments/bonds/application/bond-market.service';
|
import { BondMarketService } from '../src/modules/investments/instruments/bonds/application/bond-market.service';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
|
|
||||||
const uid = 'e6123145-9665-43e0-8413-cd61b8aa9b13';
|
const uid = 'e6123145-9665-43e0-8413-cd61b8aa9b13';
|
||||||
describe('Bond HTTP contract', () => {
|
describe('Bond HTTP contract', () => {
|
||||||
@@ -38,6 +39,8 @@ describe('Bond HTTP contract', () => {
|
|||||||
.useValue(bonds)
|
.useValue(bonds)
|
||||||
.overrideProvider(BondIncomeService)
|
.overrideProvider(BondIncomeService)
|
||||||
.useValue(bonds)
|
.useValue(bonds)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { StockCatalogService } from '../src/modules/investments/instruments/stoc
|
|||||||
import { StockIncomeService } from '../src/modules/investments/instruments/stocks/application/stock-income.service';
|
import { StockIncomeService } from '../src/modules/investments/instruments/stocks/application/stock-income.service';
|
||||||
import { StockMarketService } from '../src/modules/investments/instruments/stocks/application/stock-market.service';
|
import { StockMarketService } from '../src/modules/investments/instruments/stocks/application/stock-market.service';
|
||||||
import { StockScreenerService } from '../src/modules/investments/instruments/stocks/application/stock-screener.service';
|
import { StockScreenerService } from '../src/modules/investments/instruments/stocks/application/stock-screener.service';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
|
|
||||||
const uid = 'e6123145-9665-43e0-8413-cd61b8aa9b13';
|
const uid = 'e6123145-9665-43e0-8413-cd61b8aa9b13';
|
||||||
describe('Stock HTTP contract', () => {
|
describe('Stock HTTP contract', () => {
|
||||||
@@ -41,6 +42,8 @@ describe('Stock HTTP contract', () => {
|
|||||||
.useValue(stocks)
|
.useValue(stocks)
|
||||||
.overrideProvider(StockScreenerService)
|
.overrideProvider(StockScreenerService)
|
||||||
.useValue(screener)
|
.useValue(screener)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { TbankAccessService } from '../src/integrations/tbank/tbank-access.servi
|
|||||||
import { TbankTokenService } from '../src/integrations/tbank/tbank-token.service';
|
import { TbankTokenService } from '../src/integrations/tbank/tbank-token.service';
|
||||||
import { TbankClient } from '../src/integrations/tbank/tbank.client';
|
import { TbankClient } from '../src/integrations/tbank/tbank.client';
|
||||||
import { configureApp } from '../src/main';
|
import { configureApp } from '../src/main';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
describe('Persistent T-Bank connection boundary (SQLite/HTTP)', () => {
|
describe('Persistent T-Bank connection boundary (SQLite/HTTP)', () => {
|
||||||
@@ -31,6 +32,8 @@ describe('Persistent T-Bank connection boundary (SQLite/HTTP)', () => {
|
|||||||
const module = await Test.createTestingModule({ imports: [AppModule] })
|
const module = await Test.createTestingModule({ imports: [AppModule] })
|
||||||
.overrideProvider(TbankClient)
|
.overrideProvider(TbankClient)
|
||||||
.useValue(upstream)
|
.useValue(upstream)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
} from '../src/modules/investments/income/income-analytics.dto';
|
} from '../src/modules/investments/income/income-analytics.dto';
|
||||||
import { moscowDate } from '../src/modules/investments/investment-calendar';
|
import { moscowDate } from '../src/modules/investments/investment-calendar';
|
||||||
import { BrokerageOperationsRepository } from '../src/modules/investments/operations/infrastructure/brokerage-operations.repository';
|
import { BrokerageOperationsRepository } from '../src/modules/investments/operations/infrastructure/brokerage-operations.repository';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
// Financial proof uses real persisted rows/coverage and the configured HTTP boundary.
|
// Financial proof uses real persisted rows/coverage and the configured HTTP boundary.
|
||||||
@@ -59,6 +60,8 @@ describe('local income completeness and exact money (SQLite)', () => {
|
|||||||
const module = await Test.createTestingModule({ imports: [AppModule] })
|
const module = await Test.createTestingModule({ imports: [AppModule] })
|
||||||
.overrideProvider(TbankClient)
|
.overrideProvider(TbankClient)
|
||||||
.useValue(upstream)
|
.useValue(upstream)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { TbankClient } from '../src/integrations/tbank/tbank.client';
|
|||||||
import { configureApp } from '../src/main';
|
import { configureApp } from '../src/main';
|
||||||
import { BrokerageOperationsRepository } from '../src/modules/investments/operations/infrastructure/brokerage-operations.repository';
|
import { BrokerageOperationsRepository } from '../src/modules/investments/operations/infrastructure/brokerage-operations.repository';
|
||||||
import { BrokerageOperationsResourceDto } from '../src/modules/investments/operations/presentation/brokerage-operation.dto';
|
import { BrokerageOperationsResourceDto } from '../src/modules/investments/operations/presentation/brokerage-operation.dto';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
const uid = '11111111-1111-4111-8111-111111111111';
|
const uid = '11111111-1111-4111-8111-111111111111';
|
||||||
@@ -45,6 +46,8 @@ describe('persistent ledger HTTP and cursor (SQLite)', () => {
|
|||||||
const module = await Test.createTestingModule({ imports: [AppModule] })
|
const module = await Test.createTestingModule({ imports: [AppModule] })
|
||||||
.overrideProvider(TbankClient)
|
.overrideProvider(TbankClient)
|
||||||
.useValue(upstream)
|
.useValue(upstream)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { BrokerageAccountsResourceDto } from '../src/modules/investments/brokera
|
|||||||
import { IncomeAnalyticsResourceDto } from '../src/modules/investments/income/income-analytics.dto';
|
import { IncomeAnalyticsResourceDto } from '../src/modules/investments/income/income-analytics.dto';
|
||||||
import { PortfolioService } from '../src/modules/investments/portfolio/application/portfolio.service';
|
import { PortfolioService } from '../src/modules/investments/portfolio/application/portfolio.service';
|
||||||
import { PortfolioResourceDto } from '../src/modules/investments/portfolio/presentation/portfolio.dto';
|
import { PortfolioResourceDto } from '../src/modules/investments/portfolio/presentation/portfolio.dto';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
function deferred<T>() {
|
function deferred<T>() {
|
||||||
@@ -102,6 +103,8 @@ describe('local accounts and portfolio HTTP (SQLite)', () => {
|
|||||||
const module = await Test.createTestingModule({ imports: [AppModule] })
|
const module = await Test.createTestingModule({ imports: [AppModule] })
|
||||||
.overrideProvider(TbankClient)
|
.overrideProvider(TbankClient)
|
||||||
.useValue(upstream)
|
.useValue(upstream)
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
configureApp(app);
|
configureApp(app);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
TbankOperationsByCursorRequest,
|
TbankOperationsByCursorRequest,
|
||||||
} from '../src/integrations/tbank/tbank.client';
|
} from '../src/integrations/tbank/tbank.client';
|
||||||
import { configureApp } from '../src/main';
|
import { configureApp } from '../src/main';
|
||||||
|
import { TbankHourlyScheduler } from '../src/modules/investments/tbank-sync/tbank-hourly.scheduler';
|
||||||
import { PrismaService } from '../src/prisma/prisma.service';
|
import { PrismaService } from '../src/prisma/prisma.service';
|
||||||
|
|
||||||
const evidenceDirectory = mkdtempSync(join(tmpdir(), 'wealthledger-read-evidence-'));
|
const evidenceDirectory = mkdtempSync(join(tmpdir(), 'wealthledger-read-evidence-'));
|
||||||
@@ -215,6 +216,8 @@ describe('T-Bank persisted read budget', () => {
|
|||||||
})
|
})
|
||||||
.overrideProvider(NcrRatingsClient)
|
.overrideProvider(NcrRatingsClient)
|
||||||
.useValue({ rating: () => counted('ncrRating', null) })
|
.useValue({ rating: () => counted('ncrRating', null) })
|
||||||
|
.overrideProvider(TbankHourlyScheduler)
|
||||||
|
.useValue({ tick: jest.fn() })
|
||||||
.compile();
|
.compile();
|
||||||
app = module.createNestApplication();
|
app = module.createNestApplication();
|
||||||
app.use((_req: Request, res: Response, next: NextFunction) => {
|
app.use((_req: Request, res: Response, next: NextFunction) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user