@accounter/scraper-app
Version:
Scraper app with Fastify server and React UI
161 lines (143 loc) • 5.25 kB
text/typescript
import { describe, expect, it, vi } from 'vitest';
import { PayloadValidationError } from '../../validate-payload.js';
import { scrapeDiscount } from '../discount.js';
const CREDS = { id: 'src-1', ID: '123456789', password: 'pass' };
const DATE_FROM = new Date('2024-01-01');
const DATE_TO = new Date('2024-01-31');
const noop = () => {};
const VALID_MONTH_RESULT = {
success: true,
accountNumber: 'ACC-001',
balance: 5000,
transactions: [
{
OperationDate: '20240101',
ValueDate: '20240101',
OperationCode: '1',
OperationDescription: 'Credit',
OperationAmount: 1000,
BalanceAfterOperation: 5000,
OperationNumber: 1,
OperationDescription2: '',
OperationDescription3: '',
OperationBranch: 1,
OperationBank: 1,
Channel: 'web',
ChannelName: 'Web',
InstituteCode: '1',
BranchTreasuryNumber: '1',
Urn: 'urn-1',
OperationDetailsServiceName: '',
CommissionChannelCode: '',
CommissionChannelName: '',
CommissionTypeName: '',
BusinessDayDate: '20240101',
EventName: '',
CategoryCode: 1,
CategoryDescCode: 1,
CategoryDescription: '',
OperationDescriptionToDisplay: 'Credit',
OperationOrder: 1,
IsLastSeen: false,
},
],
};
vi.mock('@accounter/modern-poalim-scraper', () => ({
init: vi.fn(),
}));
async function getInitMock() {
const mod = await import('@accounter/modern-poalim-scraper');
return mod.init as ReturnType<typeof vi.fn>;
}
describe('scrapeDiscount — happy path', () => {
it('resolves with a validated DiscountPayload containing one entry per month', async () => {
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({
getMonthTransactions: vi.fn().mockResolvedValue(VALID_MONTH_RESULT),
}),
close: vi.fn().mockResolvedValue(undefined),
});
const result = await scrapeDiscount(CREDS, DATE_FROM, DATE_TO, noop);
expect(Array.isArray(result)).toBe(true);
expect(result).toHaveLength(1);
expect(result[0]).toMatchObject({
accountNumber: 'ACC-001',
month: '2024-01',
balance: 5000,
});
expect(result[0]!.transactions).toHaveLength(1);
});
it('fetches one month per month in the date range', async () => {
const getMonthTransactions = vi.fn().mockResolvedValue(VALID_MONTH_RESULT);
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({ getMonthTransactions }),
close: vi.fn().mockResolvedValue(undefined),
});
const threeMonthsFrom = new Date('2024-01-01');
const threeMonthsTo = new Date('2024-03-31');
const result = await scrapeDiscount(CREDS, threeMonthsFrom, threeMonthsTo, noop);
expect(getMonthTransactions).toHaveBeenCalledTimes(3);
expect(result).toHaveLength(3);
expect(result.map(r => r.month)).toEqual(['2024-01', '2024-02', '2024-03']);
});
it('passes the correct month Date to getMonthTransactions', async () => {
const getMonthTransactions = vi.fn().mockResolvedValue(VALID_MONTH_RESULT);
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({ getMonthTransactions }),
close: vi.fn().mockResolvedValue(undefined),
});
await scrapeDiscount(CREDS, DATE_FROM, DATE_TO, noop);
expect(getMonthTransactions).toHaveBeenCalledWith(expect.any(Date));
});
it('calls close() even on success', async () => {
const close = vi.fn().mockResolvedValue(undefined);
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({
getMonthTransactions: vi.fn().mockResolvedValue(VALID_MONTH_RESULT),
}),
close,
});
await scrapeDiscount(CREDS, DATE_FROM, DATE_TO, noop);
expect(close).toHaveBeenCalledOnce();
});
});
describe('scrapeDiscount — invalid payload', () => {
it('throws PayloadValidationError when data fails schema validation', async () => {
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({
getMonthTransactions: vi.fn().mockResolvedValue({
success: true,
accountNumber: 'ACC-001',
balance: 0,
transactions: [{ OperationDate: 'bad' }], // missing required fields
}),
}),
close: vi.fn().mockResolvedValue(undefined),
});
await expect(scrapeDiscount(CREDS, DATE_FROM, DATE_TO, noop)).rejects.toBeInstanceOf(
PayloadValidationError,
);
});
it('calls close() even on validation error', async () => {
const close = vi.fn().mockResolvedValue(undefined);
const initMock = await getInitMock();
initMock.mockResolvedValue({
discount: vi.fn().mockResolvedValue({
getMonthTransactions: vi.fn().mockResolvedValue({
success: true,
accountNumber: 'ACC-001',
balance: 0,
transactions: [{ OperationDate: 'bad' }],
}),
}),
close,
});
await expect(scrapeDiscount(CREDS, DATE_FROM, DATE_TO, noop)).rejects.toThrow();
expect(close).toHaveBeenCalledOnce();
});
});