Skip to content

Commit

Permalink
feat: adding mercantile bank scraper (eshaham#838)
Browse files Browse the repository at this point in the history
Co-authored-by: eqqupty <eqqupty@amazon.com>
Co-authored-by: Baruch Odem <baruchiro@gmail.com>
  • Loading branch information
3 people authored Mar 26, 2024
1 parent d8c4a57 commit 15bcd26
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/component_owners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ components:
- daniel-hauser
src/scrapers/leumi.ts:
- dimdimi4
src/scrapers/marcentile.ts:
- kfirarad
- EzzatQ
src/scrapers/max.ts:
- baruchiro
- galbarm
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Currently only the following banks are supported:
- Bank Hapoalim (thanks [@sebikaplun](https://github.com/sebikaplun))
- Leumi Bank (thanks [@esakal](https://github.com/esakal))
- Discount Bank
- Mercantile Bank (thanks [@ezzatq](https://github.com/ezzatq) and [@kfirarad](https://github.com/kfirarad)))
- Mizrahi Bank (thanks [@baruchiro](https://github.com/baruchiro))
- Otsar Hahayal Bank (thanks [@matanelgabsi](https://github.com/matanelgabsi))
- Visa Cal (thanks [@erikash](https://github.com/erikash), [@esakal](https://github.com/esakal) and [@nirgin](https://github.com/nirgin))
Expand Down Expand Up @@ -245,6 +246,18 @@ const credentials = {
```
This scraper supports fetching transaction from up to one year (minus 1 day).

## Mercantile scraper
This scraper expects the following credentials object:
```node
const credentials = {
id: <user identification number>,
password: <user password>,
num: <user identificaiton code>
};
```
This scraper supports fetching transaction from up to one year (minus 1 day).


### Known Limitations
- Missing memo field

Expand Down
5 changes: 5 additions & 0 deletions src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum CompanyTypes {
leumiCard = 'leumiCard',
otsarHahayal = 'otsarHahayal',
discount = 'discount',
mercantile = 'mercantile',
mizrahi = 'mizrahi',
leumi = 'leumi',
massad = 'massad',
Expand Down Expand Up @@ -44,6 +45,10 @@ export const SCRAPERS = {
name: 'Discount Bank',
loginFields: ['id', PASSWORD_FIELD, 'num'],
},
[CompanyTypes.mercantile]: {
name: 'Mercantile Bank',
loginFields: ['id', PASSWORD_FIELD, 'num'],
},
[CompanyTypes.otsarHahayal]: {
name: 'Bank Otsar Hahayal',
loginFields: ['username', PASSWORD_FIELD],
Expand Down
3 changes: 3 additions & 0 deletions src/scrapers/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import HapoalimScraper from './hapoalim';
import OtsarHahayalScraper from './otsar-hahayal';
import LeumiScraper from './leumi';
import DiscountScraper from './discount';
import MercantileScraper from './mercantile';
import MaxScraper from './max';
import VisaCalScraper from './visa-cal';
import IsracardScraper from './isracard';
Expand Down Expand Up @@ -34,6 +35,8 @@ export default function createScraper(options: ScraperOptions): Scraper<ScraperC
return new MizrahiScraper(options);
case CompanyTypes.discount:
return new DiscountScraper(options);
case CompanyTypes.mercantile:
return new MercantileScraper(options);
case CompanyTypes.otsarHahayal:
return new OtsarHahayalScraper(options);
case CompanyTypes.visaCal:
Expand Down
53 changes: 53 additions & 0 deletions src/scrapers/mercantile.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import MercantileScraper from './mercantile';
import {
maybeTestCompanyAPI, extendAsyncTimeout, getTestsConfig, exportTransactions,
} from '../tests/tests-utils';
import { SCRAPERS } from '../definitions';
import { LoginResults } from './base-scraper-with-browser';

const COMPANY_ID = 'mercantile'; // TODO this property should be hard-coded in the provider
const testsConfig = getTestsConfig();

describe('Mercantile legacy scraper', () => {
beforeAll(() => {
extendAsyncTimeout(); // The default timeout is 5 seconds per async test, this function extends the timeout value
});

test('should expose login fields in scrapers constant', () => {
expect(SCRAPERS.mercantile).toBeDefined();
expect(SCRAPERS.mercantile.loginFields).toContain('id');
expect(SCRAPERS.mercantile.loginFields).toContain('password');
expect(SCRAPERS.mercantile.loginFields).toContain('num');
});

maybeTestCompanyAPI(COMPANY_ID, (config) => config.companyAPI.invalidPassword)('should fail on invalid user/password"', async () => {
const options = {
...testsConfig.options,
companyId: COMPANY_ID,
};

const scraper = new MercantileScraper(options);

const result = await scraper.scrape(testsConfig.credentials.mercantile);

expect(result).toBeDefined();
expect(result.success).toBeFalsy();
expect(result.errorType).toBe(LoginResults.InvalidPassword);
});

maybeTestCompanyAPI(COMPANY_ID)('should scrape transactions"', async () => {
const options = {
...testsConfig.options,
companyId: COMPANY_ID,
};

const scraper = new MercantileScraper(options);
const result = await scraper.scrape(testsConfig.credentials.mercantile);
expect(result).toBeDefined();
const error = `${result.errorType || ''} ${result.errorMessage || ''}`.trim();
expect(error).toBe('');
expect(result.success).toBeTruthy();

exportTransactions(COMPANY_ID, result.accounts || []);
});
});
13 changes: 13 additions & 0 deletions src/scrapers/mercantile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import DiscountScraper from './discount';

type ScraperSpecificCredentials = { id: string, password: string, num: string };
class MercantileScraper extends DiscountScraper {
getLoginOptions(credentials: ScraperSpecificCredentials) {
return {
...super.getLoginOptions(credentials),
loginUrl: 'https://start.telebank.co.il/login/?bank=m',
};
}
}

export default MercantileScraper;

0 comments on commit 15bcd26

Please sign in to comment.