fix(frontend): clean up mock setup and route params
This commit is contained in:
parent
76cffc061d
commit
b26021016c
11
apps/frontend/mocks/data/auth.ts
Normal file
11
apps/frontend/mocks/data/auth.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const mockUser = {
|
||||||
|
id: 1,
|
||||||
|
email: 'user@test.com',
|
||||||
|
name: 'Test User',
|
||||||
|
role: 'user',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockAuthResponse = {
|
||||||
|
user: mockUser,
|
||||||
|
accessToken: 'mock-access-token',
|
||||||
|
}
|
||||||
40
apps/frontend/mocks/data/bonds.ts
Normal file
40
apps/frontend/mocks/data/bonds.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
export const mockBond = {
|
||||||
|
secid: 'SU26238RMFS5',
|
||||||
|
isin: 'RU000A101XU7',
|
||||||
|
name: 'ОФЗ 26238',
|
||||||
|
shortName: 'ОФЗ 26238',
|
||||||
|
latName: null,
|
||||||
|
listLevel: 1,
|
||||||
|
issueSize: 500000000,
|
||||||
|
faceValue: 1000,
|
||||||
|
faceUnit: 'RUB',
|
||||||
|
matDate: '2027-05-15',
|
||||||
|
couponValue: 36.9,
|
||||||
|
couponPercent: 7.5,
|
||||||
|
couponPeriod: 182,
|
||||||
|
nextCoupon: '2024-07-15',
|
||||||
|
accruedInt: 8.45,
|
||||||
|
bondType: 'ОФЗ',
|
||||||
|
bondSubType: 'ОФЗ-ПД',
|
||||||
|
offerDate: null,
|
||||||
|
buybackDate: null,
|
||||||
|
marketData: {
|
||||||
|
price: 98.5,
|
||||||
|
yieldToMaturity: 8.2,
|
||||||
|
duration: 3.5,
|
||||||
|
accruedInt: 8.45,
|
||||||
|
couponValue: 36.9,
|
||||||
|
couponPercent: 7.5,
|
||||||
|
nextCouponDate: '2024-07-15',
|
||||||
|
open: 98.0,
|
||||||
|
high: 99.0,
|
||||||
|
low: 97.5,
|
||||||
|
volume: 1000000,
|
||||||
|
updatedAt: '2024-01-15T10:00:00Z',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockBondHistory = [
|
||||||
|
{ date: '2024-01-15', closePrice: 98.5, yieldClose: 8.2, duration: 3.5 },
|
||||||
|
{ date: '2024-01-14', closePrice: 98.2, yieldClose: 8.3, duration: 3.5 },
|
||||||
|
]
|
||||||
189
apps/frontend/mocks/data/broker.ts
Normal file
189
apps/frontend/mocks/data/broker.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
export const mockBrokerAccounts = [
|
||||||
|
{
|
||||||
|
id: '2084014113',
|
||||||
|
type: 'brokerage',
|
||||||
|
name: 'Т-Инвестиции',
|
||||||
|
status: 'open',
|
||||||
|
openedAt: null,
|
||||||
|
accessLevel: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockBrokerPortfolio = {
|
||||||
|
account: mockBrokerAccounts[0],
|
||||||
|
positionCounts: { shares: 3, bonds: 2, etf: 0, other: 0 },
|
||||||
|
totals: {
|
||||||
|
shares: { currency: 'RUB', units: '240000', nano: 500000000, value: 240000.5 },
|
||||||
|
bonds: { currency: 'RUB', units: '45000', nano: 0, value: 45000 },
|
||||||
|
etf: null,
|
||||||
|
currencies: null,
|
||||||
|
futures: null,
|
||||||
|
options: null,
|
||||||
|
structuredProducts: null,
|
||||||
|
dfa: null,
|
||||||
|
portfolio: { currency: 'RUB', units: '285000', nano: 500000000, value: 285000.5 },
|
||||||
|
},
|
||||||
|
yields: {
|
||||||
|
expectedPercent: null,
|
||||||
|
daily: { currency: 'RUB', units: '1200', nano: 0, value: 1200 },
|
||||||
|
dailyPercent: null,
|
||||||
|
},
|
||||||
|
cash: [{ currency: 'RUB', units: '15000', nano: 0, value: 15000 }],
|
||||||
|
blockedCash: [],
|
||||||
|
asOf: '2024-06-01T10:00:00Z',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockBrokerPositions = [
|
||||||
|
{
|
||||||
|
figi: null,
|
||||||
|
instrumentUid: null,
|
||||||
|
positionUid: null,
|
||||||
|
ticker: 'SBER',
|
||||||
|
classCode: null,
|
||||||
|
instrumentType: 'share',
|
||||||
|
name: 'Сбер Банк',
|
||||||
|
quantity: { currency: '', units: '100', nano: 0, value: 100 },
|
||||||
|
blockedLots: null,
|
||||||
|
currentPrice: { currency: 'RUB', units: '289', nano: 500000000, value: 289.5 },
|
||||||
|
currentValue: { currency: 'RUB', units: '28950', nano: 0, value: 28950 },
|
||||||
|
averagePositionPrice: null,
|
||||||
|
expectedYieldPercent: null,
|
||||||
|
dailyYield: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
figi: null,
|
||||||
|
instrumentUid: null,
|
||||||
|
positionUid: null,
|
||||||
|
ticker: 'VTBR',
|
||||||
|
classCode: null,
|
||||||
|
instrumentType: 'share',
|
||||||
|
name: 'ВТБ',
|
||||||
|
quantity: { currency: '', units: '5000', nano: 0, value: 5000 },
|
||||||
|
blockedLots: null,
|
||||||
|
currentPrice: { currency: 'RUB', units: '0', nano: 23400000, value: 0.0234 },
|
||||||
|
currentValue: { currency: 'RUB', units: '117', nano: 0, value: 117 },
|
||||||
|
averagePositionPrice: null,
|
||||||
|
expectedYieldPercent: null,
|
||||||
|
dailyYield: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
figi: null,
|
||||||
|
instrumentUid: null,
|
||||||
|
positionUid: null,
|
||||||
|
ticker: 'SU26238RMFS5',
|
||||||
|
classCode: null,
|
||||||
|
instrumentType: 'bond',
|
||||||
|
name: 'ОФЗ 26238',
|
||||||
|
quantity: { currency: '', units: '10', nano: 0, value: 10 },
|
||||||
|
blockedLots: null,
|
||||||
|
currentPrice: { currency: 'RUB', units: '985', nano: 0, value: 985 },
|
||||||
|
currentValue: { currency: 'RUB', units: '9850', nano: 0, value: 9850 },
|
||||||
|
averagePositionPrice: null,
|
||||||
|
expectedYieldPercent: null,
|
||||||
|
dailyYield: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockBrokerOperations = [
|
||||||
|
{
|
||||||
|
cursor: null,
|
||||||
|
accountId: '2084014113',
|
||||||
|
id: 'op-1',
|
||||||
|
parentOperationId: null,
|
||||||
|
date: '2024-06-01T10:00:00Z',
|
||||||
|
type: 'buy',
|
||||||
|
category: 'trade',
|
||||||
|
description: null,
|
||||||
|
name: 'Покупка SBER',
|
||||||
|
state: 'executed',
|
||||||
|
instrumentUid: null,
|
||||||
|
figi: null,
|
||||||
|
ticker: 'SBER',
|
||||||
|
classCode: null,
|
||||||
|
instrumentType: 'share',
|
||||||
|
payment: { currency: 'RUB', units: '-27500', nano: 0, value: -27500 },
|
||||||
|
price: { currency: 'RUB', units: '275', nano: 0, value: 275 },
|
||||||
|
commission: { currency: 'RUB', units: '-55', nano: 0, value: -55 },
|
||||||
|
yield: null,
|
||||||
|
accruedInt: null,
|
||||||
|
quantity: { currency: '', units: '100', nano: 0, value: 100 },
|
||||||
|
quantityDone: { currency: '', units: '100', nano: 0, value: 100 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cursor: null,
|
||||||
|
accountId: '2084014113',
|
||||||
|
id: 'op-2',
|
||||||
|
parentOperationId: null,
|
||||||
|
date: '2024-05-20T14:30:00Z',
|
||||||
|
type: 'dividend',
|
||||||
|
category: 'income',
|
||||||
|
description: null,
|
||||||
|
name: 'Дивиденды Сбер',
|
||||||
|
state: 'executed',
|
||||||
|
instrumentUid: null,
|
||||||
|
figi: null,
|
||||||
|
ticker: 'SBER',
|
||||||
|
classCode: null,
|
||||||
|
instrumentType: 'share',
|
||||||
|
payment: { currency: 'RUB', units: '3500', nano: 0, value: 3500 },
|
||||||
|
price: null,
|
||||||
|
commission: null,
|
||||||
|
yield: null,
|
||||||
|
accruedInt: null,
|
||||||
|
quantity: null,
|
||||||
|
quantityDone: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockBrokerEvents = [
|
||||||
|
{
|
||||||
|
id: 'ev-1',
|
||||||
|
type: 'dividend',
|
||||||
|
source: 'forecast',
|
||||||
|
category: 'cashflow',
|
||||||
|
eventDate: '2024-07-10',
|
||||||
|
paymentDate: null,
|
||||||
|
ticker: 'SBER',
|
||||||
|
name: 'Сбер Банк',
|
||||||
|
instrumentUid: 'uid-sber',
|
||||||
|
instrumentType: 'share',
|
||||||
|
quantitySnapshot: 100,
|
||||||
|
payoutPerUnit: 35,
|
||||||
|
estimatedAmount: 3500,
|
||||||
|
actualAmount: null,
|
||||||
|
currency: 'RUB',
|
||||||
|
estimateMode: 'current_position',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ev-2',
|
||||||
|
type: 'coupon',
|
||||||
|
source: 'forecast',
|
||||||
|
category: 'cashflow',
|
||||||
|
eventDate: '2024-07-15',
|
||||||
|
paymentDate: null,
|
||||||
|
ticker: 'SU26238RMFS5',
|
||||||
|
name: 'ОФЗ 26238',
|
||||||
|
instrumentUid: 'uid-bond',
|
||||||
|
instrumentType: 'bond',
|
||||||
|
quantitySnapshot: 10,
|
||||||
|
payoutPerUnit: 36.9,
|
||||||
|
estimatedAmount: 369,
|
||||||
|
actualAmount: null,
|
||||||
|
currency: 'RUB',
|
||||||
|
estimateMode: 'current_position',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockEventsSummary = {
|
||||||
|
eventCount: 2,
|
||||||
|
nearestEventDate: '2024-07-10',
|
||||||
|
totalEstimatedCashflow: 3869,
|
||||||
|
actualCashflow: 0,
|
||||||
|
forecastEstimatedCashflow: 3869,
|
||||||
|
dividendsTotal: 3500,
|
||||||
|
couponsTotal: 369,
|
||||||
|
principalRepaymentTotal: 0,
|
||||||
|
actualDividendsTotal: 0,
|
||||||
|
actualCouponsTotal: 0,
|
||||||
|
actualPrincipalRepaymentTotal: 0,
|
||||||
|
}
|
||||||
22
apps/frontend/mocks/data/candles.ts
Normal file
22
apps/frontend/mocks/data/candles.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export const mockCandles = [
|
||||||
|
{
|
||||||
|
open: 280,
|
||||||
|
high: 290,
|
||||||
|
low: 278,
|
||||||
|
close: 289.5,
|
||||||
|
volume: 1000000,
|
||||||
|
value: 280000000,
|
||||||
|
begin: '2024-01-15T10:00:00Z',
|
||||||
|
end: '2024-01-15T18:00:00Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: 289,
|
||||||
|
high: 292,
|
||||||
|
low: 285,
|
||||||
|
close: 288,
|
||||||
|
volume: 800000,
|
||||||
|
value: 231200000,
|
||||||
|
begin: '2024-01-16T10:00:00Z',
|
||||||
|
end: '2024-01-16T18:00:00Z',
|
||||||
|
},
|
||||||
|
]
|
||||||
15
apps/frontend/mocks/data/index.ts
Normal file
15
apps/frontend/mocks/data/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export { mockAuthResponse, mockUser } from './auth'
|
||||||
|
export { mockBond, mockBondHistory } from './bonds'
|
||||||
|
export {
|
||||||
|
mockBrokerAccounts,
|
||||||
|
mockBrokerEvents,
|
||||||
|
mockBrokerOperations,
|
||||||
|
mockBrokerPortfolio,
|
||||||
|
mockBrokerPositions,
|
||||||
|
mockEventsSummary,
|
||||||
|
} from './broker'
|
||||||
|
export { mockCandles } from './candles'
|
||||||
|
export { mockAnalytics, mockPortfolioDetail, mockPortfolios, mockPositions } from './portfolios'
|
||||||
|
export { mockScreenerItems } from './screener'
|
||||||
|
export { mockSearchResults } from './search'
|
||||||
|
export { mockDividends, mockShare, mockShareHistory } from './shares'
|
||||||
138
apps/frontend/mocks/data/portfolios.ts
Normal file
138
apps/frontend/mocks/data/portfolios.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
export const mockPortfolios = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Основной портфель',
|
||||||
|
currency: 'RUB',
|
||||||
|
createdAt: '2024-01-01T00:00:00Z',
|
||||||
|
updatedAt: '2024-06-01T00:00:00Z',
|
||||||
|
totalValue: 285000,
|
||||||
|
positionCount: 5,
|
||||||
|
shareCount: 3,
|
||||||
|
bondCount: 2,
|
||||||
|
description: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'ИИС',
|
||||||
|
currency: 'RUB',
|
||||||
|
createdAt: '2024-03-15T00:00:00Z',
|
||||||
|
updatedAt: '2024-06-10T00:00:00Z',
|
||||||
|
totalValue: 150000,
|
||||||
|
positionCount: 3,
|
||||||
|
shareCount: 2,
|
||||||
|
bondCount: 1,
|
||||||
|
description: 'Индивидуальный инвестиционный счёт',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockPositions = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
secid: 'SBER',
|
||||||
|
shortName: 'Сбер',
|
||||||
|
type: 'share',
|
||||||
|
quantity: 100,
|
||||||
|
buyPrice: 275,
|
||||||
|
currentPrice: 289.5,
|
||||||
|
totalCost: 27500,
|
||||||
|
currentValue: 28950,
|
||||||
|
weightPercent: 10.2,
|
||||||
|
pnl: 1450,
|
||||||
|
pnlPercent: 5.27,
|
||||||
|
dividendIncome: 3500,
|
||||||
|
totalReturn: 4950,
|
||||||
|
totalReturnPercent: 18,
|
||||||
|
change: 14.5,
|
||||||
|
changePercent: 5.27,
|
||||||
|
notes: null,
|
||||||
|
tags: ['DIVIDEND', 'GROWTH'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
secid: 'VTBR',
|
||||||
|
shortName: 'ВТБ',
|
||||||
|
type: 'share',
|
||||||
|
quantity: 5000,
|
||||||
|
buyPrice: 0.021,
|
||||||
|
currentPrice: 0.0234,
|
||||||
|
totalCost: 105,
|
||||||
|
currentValue: 117,
|
||||||
|
weightPercent: 0.04,
|
||||||
|
pnl: 12,
|
||||||
|
pnlPercent: 11.43,
|
||||||
|
dividendIncome: 0,
|
||||||
|
totalReturn: 12,
|
||||||
|
totalReturnPercent: 11.43,
|
||||||
|
change: 0.0024,
|
||||||
|
changePercent: 11.43,
|
||||||
|
notes: null,
|
||||||
|
tags: ['SPECULATIVE'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
secid: 'SU26238RMFS5',
|
||||||
|
shortName: 'ОФЗ 26238',
|
||||||
|
type: 'bond',
|
||||||
|
quantity: 10,
|
||||||
|
buyPrice: 97,
|
||||||
|
currentPrice: 98.5,
|
||||||
|
totalCost: 9700,
|
||||||
|
currentValue: 9850,
|
||||||
|
weightPercent: 3.5,
|
||||||
|
pnl: 150,
|
||||||
|
pnlPercent: 1.55,
|
||||||
|
dividendIncome: 0,
|
||||||
|
totalReturn: 150,
|
||||||
|
totalReturnPercent: 1.55,
|
||||||
|
change: 1.5,
|
||||||
|
changePercent: 1.55,
|
||||||
|
yieldToMaturity: 8.2,
|
||||||
|
duration: 3.5,
|
||||||
|
couponValue: 36.9,
|
||||||
|
couponPercent: 7.5,
|
||||||
|
nextCouponDate: '2024-07-15',
|
||||||
|
matDate: '2027-05-15',
|
||||||
|
accruedInt: 8.45,
|
||||||
|
bid: 98.3,
|
||||||
|
offer: 98.6,
|
||||||
|
couponPeriod: 182,
|
||||||
|
bondType: 'ОФЗ',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockPortfolioDetail = {
|
||||||
|
id: 1,
|
||||||
|
name: 'Основной портфель',
|
||||||
|
currency: 'RUB',
|
||||||
|
description: null,
|
||||||
|
createdAt: '2024-01-01T00:00:00Z',
|
||||||
|
updatedAt: '2024-06-01T00:00:00Z',
|
||||||
|
positions: mockPositions,
|
||||||
|
totalValue: 285000,
|
||||||
|
analytics: {
|
||||||
|
totalInvested: 250000,
|
||||||
|
totalValue: 285000,
|
||||||
|
totalPnl: 35000,
|
||||||
|
totalPnlPercent: 14,
|
||||||
|
totalDividends: 5000,
|
||||||
|
totalReturn: 40000,
|
||||||
|
totalReturnPercent: 16,
|
||||||
|
positionCount: 5,
|
||||||
|
weightedYield: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockAnalytics = {
|
||||||
|
positions: mockPositions,
|
||||||
|
summary: {
|
||||||
|
totalInvested: 250000,
|
||||||
|
totalValue: 285000,
|
||||||
|
totalPnl: 35000,
|
||||||
|
totalPnlPercent: 14,
|
||||||
|
totalDividends: 5000,
|
||||||
|
totalReturn: 40000,
|
||||||
|
totalReturnPercent: 16,
|
||||||
|
positionCount: 5,
|
||||||
|
weightedYield: 7.5,
|
||||||
|
},
|
||||||
|
}
|
||||||
38
apps/frontend/mocks/data/screener.ts
Normal file
38
apps/frontend/mocks/data/screener.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export const mockScreenerItems = [
|
||||||
|
{
|
||||||
|
secid: 'SBER',
|
||||||
|
shortName: 'Сбер',
|
||||||
|
isin: 'RU0009029540',
|
||||||
|
type: 'share',
|
||||||
|
price: 289.5,
|
||||||
|
change: 2.5,
|
||||||
|
changePercent: 0.87,
|
||||||
|
volume: 15000000,
|
||||||
|
listLevel: 1,
|
||||||
|
capitalization: 6250000000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
secid: 'VTBR',
|
||||||
|
shortName: 'ВТБ',
|
||||||
|
isin: 'RU000A0JP5V6',
|
||||||
|
type: 'share',
|
||||||
|
price: 0.0234,
|
||||||
|
change: 0.0002,
|
||||||
|
changePercent: 0.86,
|
||||||
|
volume: 50000000,
|
||||||
|
listLevel: 1,
|
||||||
|
capitalization: 30000000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
secid: 'GAZP',
|
||||||
|
shortName: 'Газпром',
|
||||||
|
isin: 'RU0007661625',
|
||||||
|
type: 'share',
|
||||||
|
price: 198.5,
|
||||||
|
change: -1.5,
|
||||||
|
changePercent: -0.75,
|
||||||
|
volume: 8000000,
|
||||||
|
listLevel: 1,
|
||||||
|
capitalization: 4700000000000,
|
||||||
|
},
|
||||||
|
]
|
||||||
20
apps/frontend/mocks/data/search.ts
Normal file
20
apps/frontend/mocks/data/search.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export const mockSearchResults = [
|
||||||
|
{
|
||||||
|
secid: 'SBER',
|
||||||
|
isin: 'RU0009029540',
|
||||||
|
shortName: 'Сбер',
|
||||||
|
type: 'share',
|
||||||
|
listLevel: 1,
|
||||||
|
currency: 'RUB',
|
||||||
|
price: 289.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
secid: 'VTBR',
|
||||||
|
isin: 'RU000A0JP5V6',
|
||||||
|
shortName: 'ВТБ',
|
||||||
|
type: 'share',
|
||||||
|
listLevel: 1,
|
||||||
|
currency: 'RUB',
|
||||||
|
price: 0.0234,
|
||||||
|
},
|
||||||
|
]
|
||||||
50
apps/frontend/mocks/data/shares.ts
Normal file
50
apps/frontend/mocks/data/shares.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
export const mockShare = {
|
||||||
|
secid: 'SBER',
|
||||||
|
isin: 'RU0009029540',
|
||||||
|
name: 'Сбер Банк',
|
||||||
|
shortName: 'Сбер',
|
||||||
|
latName: 'Sberbank',
|
||||||
|
listLevel: 1,
|
||||||
|
issueSize: 21586900000,
|
||||||
|
faceValue: 3,
|
||||||
|
faceUnit: 'RUB',
|
||||||
|
type: 'common_share',
|
||||||
|
marketData: {
|
||||||
|
price: 289.5,
|
||||||
|
change: 2.5,
|
||||||
|
changePercent: 0.87,
|
||||||
|
open: 287,
|
||||||
|
high: 291,
|
||||||
|
low: 286.5,
|
||||||
|
volume: 15000000,
|
||||||
|
value: 4350000000,
|
||||||
|
issueCapitalization: 6250000000000,
|
||||||
|
updatedAt: '2024-01-15T10:00:00Z',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockDividends = [
|
||||||
|
{ registryCloseDate: '2024-07-10', value: 35.0, currency: 'RUB' },
|
||||||
|
{ registryCloseDate: '2023-10-05', value: 30.0, currency: 'RUB' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockShareHistory = [
|
||||||
|
{
|
||||||
|
date: '2024-01-15',
|
||||||
|
open: 287,
|
||||||
|
high: 291,
|
||||||
|
low: 286.5,
|
||||||
|
close: 289.5,
|
||||||
|
volume: 15000000,
|
||||||
|
value: 4350000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2024-01-14',
|
||||||
|
open: 285,
|
||||||
|
high: 288,
|
||||||
|
low: 284,
|
||||||
|
close: 287,
|
||||||
|
volume: 12000000,
|
||||||
|
value: 3440000000,
|
||||||
|
},
|
||||||
|
]
|
||||||
151
apps/frontend/mocks/handlers.ts
Normal file
151
apps/frontend/mocks/handlers.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { HttpResponse, http } from 'msw'
|
||||||
|
import {
|
||||||
|
mockAnalytics,
|
||||||
|
mockAuthResponse,
|
||||||
|
mockBond,
|
||||||
|
mockBondHistory,
|
||||||
|
mockBrokerAccounts,
|
||||||
|
mockBrokerEvents,
|
||||||
|
mockBrokerOperations,
|
||||||
|
mockBrokerPortfolio,
|
||||||
|
mockBrokerPositions,
|
||||||
|
mockCandles,
|
||||||
|
mockDividends,
|
||||||
|
mockEventsSummary,
|
||||||
|
mockPortfolioDetail,
|
||||||
|
mockPortfolios,
|
||||||
|
mockPositions,
|
||||||
|
mockScreenerItems,
|
||||||
|
mockSearchResults,
|
||||||
|
mockShare,
|
||||||
|
mockShareHistory,
|
||||||
|
mockUser,
|
||||||
|
} from './data'
|
||||||
|
import { envelope } from './utils'
|
||||||
|
|
||||||
|
const API = '/api/v1'
|
||||||
|
|
||||||
|
export const handlers = [
|
||||||
|
http.get(`${API}/health`, () =>
|
||||||
|
HttpResponse.json(
|
||||||
|
envelope({ status: 'ok', timestamp: new Date().toISOString(), uptime: 12345 }),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
http.get(`${API}/auth/me`, () => HttpResponse.json(envelope(mockUser))),
|
||||||
|
http.patch(`${API}/auth/me`, () => HttpResponse.json(envelope({ ...mockUser, name: 'Updated' }))),
|
||||||
|
http.post(`${API}/auth/login`, () => HttpResponse.json(envelope(mockAuthResponse))),
|
||||||
|
http.post(`${API}/auth/register`, () => HttpResponse.json(envelope(mockAuthResponse))),
|
||||||
|
http.post(`${API}/auth/refresh`, () => HttpResponse.json(envelope(mockAuthResponse))),
|
||||||
|
http.post(`${API}/auth/logout`, () => HttpResponse.json(envelope({ message: 'Logged out' }))),
|
||||||
|
|
||||||
|
http.get(`${API}/securities/search`, ({ request }) => {
|
||||||
|
const url = new URL(request.url)
|
||||||
|
const q = url.searchParams.get('q') || ''
|
||||||
|
if (q.length < 2) return HttpResponse.json(envelope([]))
|
||||||
|
const filtered = mockSearchResults.filter(
|
||||||
|
(r) =>
|
||||||
|
r.secid.toLowerCase().includes(q.toLowerCase()) ||
|
||||||
|
r.shortName.toLowerCase().includes(q.toLowerCase()),
|
||||||
|
)
|
||||||
|
return HttpResponse.json(envelope(filtered))
|
||||||
|
}),
|
||||||
|
|
||||||
|
http.get(`${API}/securities/shares/:secid`, ({ params }) => {
|
||||||
|
const { secid } = params
|
||||||
|
if (secid === 'NOTFOUND') return new HttpResponse(null, { status: 404 })
|
||||||
|
return HttpResponse.json(envelope({ ...mockShare, secid }))
|
||||||
|
}),
|
||||||
|
http.get(`${API}/securities/shares/:secid/marketdata`, () =>
|
||||||
|
HttpResponse.json(envelope(mockShare.marketData)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/securities/shares/:secid/dividends`, () =>
|
||||||
|
HttpResponse.json(envelope(mockDividends)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/securities/shares/:secid/history`, () =>
|
||||||
|
HttpResponse.json(envelope(mockShareHistory)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/securities/shares/:secid/candles`, () =>
|
||||||
|
HttpResponse.json(envelope(mockCandles)),
|
||||||
|
),
|
||||||
|
|
||||||
|
http.get(`${API}/securities/bonds/:secid`, ({ params }) => {
|
||||||
|
const { secid } = params
|
||||||
|
if (secid === 'NOTFOUND') return new HttpResponse(null, { status: 404 })
|
||||||
|
return HttpResponse.json(envelope({ ...mockBond, secid }))
|
||||||
|
}),
|
||||||
|
http.get(`${API}/securities/bonds/:secid/marketdata`, () =>
|
||||||
|
HttpResponse.json(envelope(mockBond.marketData)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/securities/bonds/:secid/history`, () =>
|
||||||
|
HttpResponse.json(envelope(mockBondHistory)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/securities/bonds/:secid/candles`, () =>
|
||||||
|
HttpResponse.json(envelope(mockCandles)),
|
||||||
|
),
|
||||||
|
|
||||||
|
http.get(`${API}/securities/screener`, () =>
|
||||||
|
HttpResponse.json(
|
||||||
|
envelope({
|
||||||
|
items: mockScreenerItems,
|
||||||
|
total: mockScreenerItems.length,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
totalPages: 1,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
http.get(`${API}/portfolios`, () => HttpResponse.json(envelope(mockPortfolios))),
|
||||||
|
http.post(`${API}/portfolios`, () => HttpResponse.json(envelope(mockPortfolios[0]))),
|
||||||
|
http.get(`${API}/portfolios/:id`, () => HttpResponse.json(envelope(mockPortfolioDetail))),
|
||||||
|
http.patch(`${API}/portfolios/:id`, () => HttpResponse.json(envelope(mockPortfolios[0]))),
|
||||||
|
http.delete(`${API}/portfolios/:id`, () => HttpResponse.json(envelope(null))),
|
||||||
|
http.post(`${API}/portfolios/:id/positions`, () => HttpResponse.json(envelope(mockPositions[0]))),
|
||||||
|
http.patch(`${API}/portfolios/:id/positions/:positionId`, () =>
|
||||||
|
HttpResponse.json(envelope(mockPositions[0])),
|
||||||
|
),
|
||||||
|
http.delete(`${API}/portfolios/:id/positions/:positionId`, () =>
|
||||||
|
HttpResponse.json(envelope(null)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/portfolios/:id/analytics`, () => HttpResponse.json(envelope(mockAnalytics))),
|
||||||
|
|
||||||
|
http.get(`${API}/broker/accounts`, () => HttpResponse.json(envelope(mockBrokerAccounts))),
|
||||||
|
http.get(`${API}/broker/accounts/:accountId/portfolio`, () =>
|
||||||
|
HttpResponse.json(envelope(mockBrokerPortfolio)),
|
||||||
|
),
|
||||||
|
http.get(`${API}/broker/accounts/:accountId/positions`, () =>
|
||||||
|
HttpResponse.json(
|
||||||
|
envelope({
|
||||||
|
accountId: '2084014113',
|
||||||
|
items: mockBrokerPositions,
|
||||||
|
nextCursor: null,
|
||||||
|
hasNext: false,
|
||||||
|
asOf: '2024-06-01T10:00:00Z',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
http.get(`${API}/broker/accounts/:accountId/operations`, () =>
|
||||||
|
HttpResponse.json(
|
||||||
|
envelope({
|
||||||
|
accountId: '2084014113',
|
||||||
|
items: mockBrokerOperations,
|
||||||
|
nextCursor: null,
|
||||||
|
hasNext: false,
|
||||||
|
asOf: '2024-06-01T10:00:00Z',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
http.get(`${API}/broker/accounts/:accountId/events`, () =>
|
||||||
|
HttpResponse.json(
|
||||||
|
envelope({
|
||||||
|
items: mockBrokerEvents,
|
||||||
|
summary: mockEventsSummary,
|
||||||
|
asOf: '2024-06-01T10:00:00Z',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
http.post(`${API}/broker/accounts/:accountId/operations/sync`, () =>
|
||||||
|
HttpResponse.json(envelope({ upserted: 5 })),
|
||||||
|
),
|
||||||
|
]
|
||||||
5
apps/frontend/mocks/utils.ts
Normal file
5
apps/frontend/mocks/utils.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export function envelope(data: unknown) {
|
||||||
|
return {
|
||||||
|
data: { data, meta: { fromCache: false, cachedAt: null } },
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { render, screen, waitFor } from '@testing-library/react'
|
import { render, screen, waitFor } from '@testing-library/react'
|
||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
@ -5,7 +6,6 @@ import { HttpResponse, http } from 'msw'
|
|||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { SessionContext } from '@/entities/session'
|
import { SessionContext } from '@/entities/session'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { SessionProvider } from './SessionProvider'
|
import { SessionProvider } from './SessionProvider'
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { renderHook, waitFor } from '@testing-library/react'
|
import { renderHook, waitFor } from '@testing-library/react'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { useBondCandles } from './useBondCandles'
|
import { useBondCandles } from './useBondCandles'
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { renderHook, waitFor } from '@testing-library/react'
|
import { renderHook, waitFor } from '@testing-library/react'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { useSearch } from '@/entities/search'
|
import { useSearch } from '@/entities/search'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import { beforeEach, describe, expect, it } from 'vitest'
|
import { beforeEach, describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { getMe, login, logout, refresh, register, updateProfile } from './sessionApi'
|
import { getMe, login, logout, refresh, register, updateProfile } from './sessionApi'
|
||||||
import { getAccessToken, setAccessToken } from './tokenManager'
|
import { getAccessToken, setAccessToken } from './tokenManager'
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { renderHook, waitFor } from '@testing-library/react'
|
import { renderHook, waitFor } from '@testing-library/react'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { useStockCandles } from './useStockCandles'
|
import { useStockCandles } from './useStockCandles'
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { renderHook, waitFor } from '@testing-library/react'
|
import { renderHook, waitFor } from '@testing-library/react'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { useStockDividends } from './useStockDividends'
|
import { useStockDividends } from './useStockDividends'
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { env } from './shared/config/env'
|
|||||||
|
|
||||||
async function startApp() {
|
async function startApp() {
|
||||||
if (env.VITE_API_MOCK) {
|
if (env.VITE_API_MOCK) {
|
||||||
const { worker } = await import('./shared/lib/test/browser')
|
const { worker } = await import('../mocks/browser')
|
||||||
await worker.start({ onUnhandledRequest: 'bypass' })
|
await worker.start({ onUnhandledRequest: 'bypass' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
createMemoryHistory,
|
createMemoryHistory,
|
||||||
@ -10,7 +11,6 @@ import { render, screen, waitFor } from '@testing-library/react'
|
|||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { TestSessionProvider } from '@/shared/lib/test/TestSessionProvider'
|
import { TestSessionProvider } from '@/shared/lib/test/TestSessionProvider'
|
||||||
import { LoginPage } from './ui/LoginPage'
|
import { LoginPage } from './ui/LoginPage'
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { PortfolioSummary } from '@/widgets/portfolio-summary'
|
|||||||
import { SharePositionTable } from '@/widgets/share-positions-table'
|
import { SharePositionTable } from '@/widgets/share-positions-table'
|
||||||
|
|
||||||
export function PortfolioDetailPage() {
|
export function PortfolioDetailPage() {
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams({ from: '/portfolios/$id' })
|
||||||
const portfolioId = parseInt(id!, 10)
|
const portfolioId = parseInt(id!, 10)
|
||||||
|
|
||||||
const { data: portfolio, isLoading, error } = usePortfolio(portfolioId)
|
const { data: portfolio, isLoading, error } = usePortfolio(portfolioId)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { screen, waitFor } from '@testing-library/react'
|
import { screen, waitFor } from '@testing-library/react'
|
||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { renderWithProviders } from '@/shared/lib/test/test-utils'
|
import { renderWithProviders } from '@/shared/lib/test/test-utils'
|
||||||
import { ProfilePage } from './ui/ProfilePage'
|
import { ProfilePage } from './ui/ProfilePage'
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
createMemoryHistory,
|
createMemoryHistory,
|
||||||
@ -10,7 +11,6 @@ import { render, screen } from '@testing-library/react'
|
|||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { TestSessionProvider } from '@/shared/lib/test/TestSessionProvider'
|
import { TestSessionProvider } from '@/shared/lib/test/TestSessionProvider'
|
||||||
import { RegisterPage } from './ui/RegisterPage'
|
import { RegisterPage } from './ui/RegisterPage'
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { PriceChart } from '@/widgets/price-chart'
|
|||||||
import { StockDetails } from '@/widgets/stock-details'
|
import { StockDetails } from '@/widgets/stock-details'
|
||||||
|
|
||||||
export function StockPage() {
|
export function StockPage() {
|
||||||
const { secid } = useParams<{ secid: string }>()
|
const { secid } = useParams({ from: '/stocks/$secid' })
|
||||||
const { data: stock, isLoading, error } = useStock(secid!)
|
const { data: stock, isLoading, error } = useStock(secid!)
|
||||||
const till = new Date().toISOString().split('T')[0]
|
const till = new Date().toISOString().split('T')[0]
|
||||||
const from = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
|
const from = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
|
||||||
|
|||||||
@ -1,190 +0,0 @@
|
|||||||
import { HttpResponse, http } from 'msw'
|
|
||||||
import type { BondResponse, CandleItem, SearchResultItem, ShareResponse } from '@/shared/api'
|
|
||||||
|
|
||||||
const API = '/api/v1'
|
|
||||||
|
|
||||||
const mockShare: ShareResponse = {
|
|
||||||
secid: 'SBER',
|
|
||||||
isin: 'RU0009029540',
|
|
||||||
name: 'Сбер Банк',
|
|
||||||
shortName: 'Сбер',
|
|
||||||
latName: 'Sberbank',
|
|
||||||
listLevel: 1,
|
|
||||||
issueSize: 21586900000,
|
|
||||||
faceValue: 3,
|
|
||||||
faceUnit: 'RUB',
|
|
||||||
type: 'common_share',
|
|
||||||
marketData: {
|
|
||||||
price: 289.5,
|
|
||||||
change: 2.5,
|
|
||||||
changePercent: 0.87,
|
|
||||||
open: 287,
|
|
||||||
high: 291,
|
|
||||||
low: 286.5,
|
|
||||||
volume: 15000000,
|
|
||||||
value: 4350000000,
|
|
||||||
issueCapitalization: 6250000000000,
|
|
||||||
updatedAt: '2024-01-15T10:00:00Z',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockBond: BondResponse = {
|
|
||||||
secid: 'SU26238RMFS5',
|
|
||||||
isin: 'RU000A101XU7',
|
|
||||||
name: 'ОФЗ 26238',
|
|
||||||
shortName: 'ОФЗ 26238',
|
|
||||||
latName: null,
|
|
||||||
listLevel: 1,
|
|
||||||
issueSize: 500000000,
|
|
||||||
faceValue: 1000,
|
|
||||||
faceUnit: 'RUB',
|
|
||||||
matDate: '2027-05-15',
|
|
||||||
couponValue: 36.9,
|
|
||||||
couponPercent: 7.5,
|
|
||||||
couponPeriod: 182,
|
|
||||||
nextCoupon: '2024-07-15',
|
|
||||||
accruedInt: 8.45,
|
|
||||||
bondType: 'ОФЗ',
|
|
||||||
bondSubType: 'ОФЗ-ПД',
|
|
||||||
offerDate: null,
|
|
||||||
buybackDate: null,
|
|
||||||
marketData: {
|
|
||||||
price: 98.5,
|
|
||||||
yieldToMaturity: 8.2,
|
|
||||||
duration: 3.5,
|
|
||||||
accruedInt: 8.45,
|
|
||||||
couponValue: 36.9,
|
|
||||||
couponPercent: 7.5,
|
|
||||||
nextCouponDate: '2024-07-15',
|
|
||||||
open: 98.0,
|
|
||||||
high: 99.0,
|
|
||||||
low: 97.5,
|
|
||||||
volume: 1000000,
|
|
||||||
updatedAt: '2024-01-15T10:00:00Z',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockCandles: CandleItem[] = [
|
|
||||||
{
|
|
||||||
open: 280,
|
|
||||||
high: 290,
|
|
||||||
low: 278,
|
|
||||||
close: 289.5,
|
|
||||||
volume: 1000000,
|
|
||||||
value: 280000000,
|
|
||||||
begin: '2024-01-15T10:00:00Z',
|
|
||||||
end: '2024-01-15T18:00:00Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
open: 289,
|
|
||||||
high: 292,
|
|
||||||
low: 285,
|
|
||||||
close: 288,
|
|
||||||
volume: 800000,
|
|
||||||
value: 231200000,
|
|
||||||
begin: '2024-01-16T10:00:00Z',
|
|
||||||
end: '2024-01-16T18:00:00Z',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const mockDividends = [
|
|
||||||
{ registryCloseDate: '2024-07-10', value: 35.0, currency: 'RUB' },
|
|
||||||
{ registryCloseDate: '2023-10-05', value: 30.0, currency: 'RUB' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const mockSearchResults: SearchResultItem[] = [
|
|
||||||
{
|
|
||||||
secid: 'SBER',
|
|
||||||
isin: 'RU0009029540',
|
|
||||||
shortName: 'Сбер',
|
|
||||||
type: 'share',
|
|
||||||
listLevel: 1,
|
|
||||||
currency: 'RUB',
|
|
||||||
price: 289.5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
secid: 'VTBR',
|
|
||||||
isin: 'RU000A0JP5V6',
|
|
||||||
shortName: 'ВТБ',
|
|
||||||
type: 'share',
|
|
||||||
listLevel: 1,
|
|
||||||
currency: 'RUB',
|
|
||||||
price: 0.0234,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const userResponse = {
|
|
||||||
id: 1,
|
|
||||||
email: 'user@test.com',
|
|
||||||
name: 'Test User',
|
|
||||||
role: 'user',
|
|
||||||
}
|
|
||||||
|
|
||||||
const authResponse = {
|
|
||||||
user: userResponse,
|
|
||||||
accessToken: 'mock-access-token',
|
|
||||||
}
|
|
||||||
|
|
||||||
const envelope = (data: unknown) => ({
|
|
||||||
data: { data, meta: { fromCache: false, cachedAt: null } },
|
|
||||||
})
|
|
||||||
|
|
||||||
export const handlers = [
|
|
||||||
http.get(`${API}/securities/search`, ({ request }) => {
|
|
||||||
const url = new URL(request.url)
|
|
||||||
const q = url.searchParams.get('q') || ''
|
|
||||||
if (q.length < 2) {
|
|
||||||
return HttpResponse.json(envelope([]))
|
|
||||||
}
|
|
||||||
const filtered = mockSearchResults.filter(
|
|
||||||
(r) =>
|
|
||||||
r.secid.toLowerCase().includes(q.toLowerCase()) ||
|
|
||||||
r.shortName.toLowerCase().includes(q.toLowerCase()),
|
|
||||||
)
|
|
||||||
return HttpResponse.json(envelope(filtered))
|
|
||||||
}),
|
|
||||||
|
|
||||||
http.get(`${API}/securities/shares/:secid`, ({ params }) => {
|
|
||||||
const { secid } = params
|
|
||||||
if (secid === 'NOTFOUND') return new HttpResponse(null, { status: 404 })
|
|
||||||
return HttpResponse.json(envelope({ ...mockShare, secid } as ShareResponse))
|
|
||||||
}),
|
|
||||||
|
|
||||||
http.get(`${API}/securities/shares/:secid/candles`, () =>
|
|
||||||
HttpResponse.json(envelope(mockCandles)),
|
|
||||||
),
|
|
||||||
|
|
||||||
http.get(`${API}/securities/shares/:secid/dividends`, () =>
|
|
||||||
HttpResponse.json(envelope(mockDividends)),
|
|
||||||
),
|
|
||||||
|
|
||||||
http.get(`${API}/securities/bonds/:secid`, ({ params }) => {
|
|
||||||
const { secid } = params
|
|
||||||
if (secid === 'NOTFOUND') return new HttpResponse(null, { status: 404 })
|
|
||||||
return HttpResponse.json(envelope({ ...mockBond, secid } as BondResponse))
|
|
||||||
}),
|
|
||||||
|
|
||||||
http.get(`${API}/securities/bonds/:secid/candles`, () =>
|
|
||||||
HttpResponse.json(envelope(mockCandles)),
|
|
||||||
),
|
|
||||||
|
|
||||||
http.get(`${API}/auth/me`, () => HttpResponse.json(envelope(userResponse))),
|
|
||||||
|
|
||||||
http.post(`${API}/auth/login`, () => HttpResponse.json(envelope(authResponse))),
|
|
||||||
|
|
||||||
http.post(`${API}/auth/register`, () => HttpResponse.json(envelope(authResponse))),
|
|
||||||
|
|
||||||
http.post(`${API}/auth/refresh`, () => HttpResponse.json(envelope(authResponse))),
|
|
||||||
|
|
||||||
http.post(`${API}/auth/logout`, () => HttpResponse.json(envelope({ message: 'Logged out' }))),
|
|
||||||
|
|
||||||
http.patch(`${API}/auth/me`, () =>
|
|
||||||
HttpResponse.json(envelope({ ...userResponse, name: 'Updated' })),
|
|
||||||
),
|
|
||||||
|
|
||||||
http.get(`${API}/health`, () =>
|
|
||||||
HttpResponse.json(
|
|
||||||
envelope({ status: 'ok', timestamp: new Date().toISOString(), uptime: 12345 }),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import '@testing-library/jest-dom'
|
import '@testing-library/jest-dom'
|
||||||
import { server } from './server'
|
import { server } from '@mocks/server'
|
||||||
|
|
||||||
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
|
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
|
||||||
afterEach(() => server.resetHandlers())
|
afterEach(() => server.resetHandlers())
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
import { server } from '@mocks/server'
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { render, screen, waitFor } from '@testing-library/react'
|
import { render, screen, waitFor } from '@testing-library/react'
|
||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
import { HttpResponse, http } from 'msw'
|
import { HttpResponse, http } from 'msw'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
import { server } from '@/shared/lib/test/server'
|
|
||||||
import { SearchBar } from '@/widgets/search-bar'
|
import { SearchBar } from '@/widgets/search-bar'
|
||||||
|
|
||||||
const API = '/api/v1'
|
const API = '/api/v1'
|
||||||
|
|||||||
@ -17,10 +17,11 @@
|
|||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"],
|
||||||
|
"@mocks/*": ["./mocks/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src", "mocks"],
|
||||||
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/shared/lib/test/**"],
|
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/shared/lib/test/**"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,10 @@ import path from 'path';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: [
|
||||||
'@': path.resolve(__dirname, './src'),
|
{ find: '@mocks', replacement: path.resolve(__dirname, './mocks') },
|
||||||
},
|
{ find: '@', replacement: path.resolve(__dirname, './src') },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
|
|||||||
@ -6,9 +6,10 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
logLevel: 'error',
|
logLevel: 'error',
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: [
|
||||||
'@': path.resolve(__dirname, './src'),
|
{ find: '@mocks', replacement: path.resolve(__dirname, './mocks') },
|
||||||
},
|
{ find: '@', replacement: path.resolve(__dirname, './src') },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
environment: 'jsdom',
|
environment: 'jsdom',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user