Skip to content

Conversation

@woldaker
Copy link

@woldaker woldaker commented Mar 1, 2025

Fixes #3290


finance.routingNumber is now comprised as follows:

Digits 0-3 = Pulled from locales/base/finance/federal_reserve_routing_symbol.ts
Digits 4-7 = Random
Digit 8 = Check digit. Calculated from the previous 8 digits as before.

Added more test conditions to the randomly-seeded finance.routingNumber test.

woldaker added 2 commits March 1, 2025 13:16
…). Added some conditions to random-seeded finance.routingNumber test. Updated finance test snapshot.
@woldaker woldaker requested a review from a team as a code owner March 1, 2025 21:51
@netlify
Copy link

netlify bot commented Mar 1, 2025

Deploy Preview for fakerjs ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit c0b3a2e
🔍 Latest deploy log https://app.netlify.com/projects/fakerjs/deploys/687d29e741f69700088a6a9b
😎 Deploy Preview https://deploy-preview-3429.fakerjs.dev
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov
Copy link

codecov bot commented Mar 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.96%. Comparing base (048c325) to head (c0b3a2e).
Report is 88 commits behind head on next.

Additional details and impacted files
@@            Coverage Diff             @@
##             next    #3429      +/-   ##
==========================================
- Coverage   99.97%   99.96%   -0.01%     
==========================================
  Files        2819     2890      +71     
  Lines      217500   222135    +4635     
  Branches      953      930      -23     
==========================================
+ Hits       217447   222068    +4621     
- Misses         53       67      +14     
Files with missing lines Coverage Δ
src/definitions/finance.ts 100.00% <ø> (ø)
...les/base/finance/federal_reserve_routing_symbol.ts 100.00% <100.00%> (ø)
src/locales/base/finance/index.ts 100.00% <100.00%> (ø)
src/locales/base/index.ts 100.00% <100.00%> (ø)
src/modules/finance/index.ts 100.00% <100.00%> (ø)

... and 106 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@matthewmayer matthewmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a little more detail to the method description

e.g.

"Generates a random routing number."

=>

"Generates a random [ABA routing number](https://en.wikipedia.org/wiki/ABA_routing_transit_number)"

…age for ABA Routing Number. Updated the example string given to reflect the new changes.
@woldaker
Copy link
Author

woldaker commented Mar 2, 2025

Done. I used one of the routing numbers from the test snapshot for the example string.

@woldaker
Copy link
Author

woldaker commented Mar 2, 2025

Also, I forgot to mention... I couldn't figure out how to link the original issue to this PR. Sorry I am a bit new to contributing to public github repos.

@woldaker
Copy link
Author

woldaker commented Mar 2, 2025

Also, as I'm sure you've noticed, I skipped any form of testing whether the 2nd group of 2 digits at indexes 2-3 actually matched up with one of the numbers listed in the base finance locale. Of course were I to do that, what I'd really be doing is simply checking if listOfFederalReserveRoutingSymbolsFromBaseLocale.includes(routingNumber.substring(0, 4)), but it appeared as though performing that sort of a check in the tests was not really what y'all wanted. I also considered splitting the first set of 2 digits up from the second set of 2 digits (the institution identifier), which if I had gone in that direction I would have encapsulated the FederalReserveRoutingSymbol into an object and then would have needed to instead make src/locales/base/finance/routing_number.ts and then in there do export const federal_reserve_district = [...]; and export const institution_identifier = (federalReserveDistrict: number) => {...}; or something similar, and then it's no longer a simple lookup table anymore, and I thought all of it was just a bit too overkill and was venturing into over-engineering territory, so I decided against that.

Edit: On a site note, it was interesting to find out that validate.js's isAbaRouting() function does not currently perform any validation on the aspects of an ABA routing number that this PR addresses. I looked at its source. All it's really doing is validating the check digit.

Edit 2: After looking at the validator.js source again, I had missed this regex at the top:

^(?!(1[3-9])|(20)|(3[3-9])|(4[0-9])|(5[0-9])|(60)|(7[3-9])|(8[1-9])|(9[0-2])|(9[3-9]))[0-9]{9}$

Which is checking (though not obviously, of course) that the federal reserve district is correct.
The last bit [0-9]{9} is verifying that it's a total of 9 digits long, which is great, but then you have the entire section before that which, after analyzing it further, is checking the first two digits to make sure that it falls under one of these categories:

Quoted from the wikipedia page on ABA routing numbers:

  • 00 is used by the United States Government
  • 01 through 12 are the "normal" routing numbers, and correspond to the 12 Federal Reserve Banks. For example, 0260-0959-3 is the routing number for Bank of America incoming wires in New York, with the initial "02" indicating the Federal Reserve Bank of New York.
  • 21 through 32 were assigned only to thrift institutions (e.g. credit unions and savings banks) through 1985, but are no longer assigned (thrifts are assigned normal 01–12 numbers). Currently they are still used by the thrift institutions, or their successors, and correspond to the normal routing number, plus 20. (For example, 2260-7352-3 is the routing number for Grand Adirondack Federal Credit Union in New York, with the initial "22" corresponding to "02" (New York Fed) plus "20" (thrift).)
  • 61 through 72 are special purpose routing numbers designated for use by non-bank payment processors and clearinghouses and are termed Electronic Transaction Identifiers (ETIs), and correspond to the normal routing number, plus 60.
  • 80 is used for traveler's checks

So that regex is effectively trying to be as exhaustive as possible, almost like an official spec would, except it's a little bizarre for two reasons:

One is that it is allowing 000000000, which passes even the check digit validation and is definitely not a valid routing number.
Two is the very strange use of (9[0-2])|(9[3-9]). I know, that's a little nit-picky, but what were the authors doing there exactly? Why not just (9[0-9])?

So tl;dr the call to isAbaRouting() in the test does handle the check digit (and the length=9) for us, but the additional check afterward to see if the first two digits fall within the range of 01-12 are still necessary so as to disallow results y'all aren't interested in, like the thrift/legacy numbers which are no longer issued, traveler's checks, and the 00 govt-only ones.

@ST-DDT ST-DDT added c: feature Request for new feature p: 1-normal Nothing urgent m: finance Something is referring to the finance module labels Mar 2, 2025
@ST-DDT ST-DDT added this to the vAnytime milestone Mar 2, 2025
@ST-DDT ST-DDT added c: bug Something isn't working and removed c: feature Request for new feature labels Mar 2, 2025
@woldaker
Copy link
Author

woldaker commented Mar 3, 2025

Strange. I keep getting this today:
image

which ultimately ends up failing the preflight:
image

When I first went to make the changes you had requested, pnpm complained about being updated, so I ended up doing pnpm setup followed by pnpm add -g @pnpm/exe which gave an error saying that I had to remove the existing pnpm.exe first, so I did Remove-Item C:\path\to\my\pnpm.exe and then reran pnpm add -g @pnpm/exe and then it worked. But now it just fails preflight every time.

Any ideas?

@ST-DDT
Copy link
Member

ST-DDT commented Mar 3, 2025

The timeouts happen randomly unfortunately. Even if we increase it to 30s.
We arent sure why this happens, but you can ignore the timeouts for now.

As for the pnpm update, you might have to update node to the latest (LTS) version. That solved it for me.
I use corepack enable to manage the pnpm version in use.

@woldaker
Copy link
Author

woldaker commented Mar 3, 2025

Okay that makes me feel better that I didn't do something and break it unwittingly. I'll try again after work today.

@woldaker
Copy link
Author

woldaker commented Mar 4, 2025

Okay I tried again and it didn't time out this time. Pushed up the changes you mentioned.

@woldaker
Copy link
Author

I was checking back in to see if there was any further action y'all needed me to take to get the PR completed. I see that there was a conflict in the finance definitions file, so I resolved that. Just let me know if there's anything else I should do. Thanks.

@xDivisionByZerox
Copy link
Member

@woldaker Thanks for taking action on your own already. Please note that actually merging your PR might take some time. This is not because we don't like your feature but have to carefully consider multiple side effects a feature might have and how well it integrates into the entire API of faker. Lastly, we are obviously working on later major features for the entire Faker project. We also need to consider how new features would integrate in these future plans.
So, to summarize, don't worry if your PR is not getting any action for some time. I appreciate your patience :)

@woldaker
Copy link
Author

woldaker commented Mar 12, 2025 via email

Copy link
Member

@xDivisionByZerox xDivisionByZerox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a while, but I've finally had the chance to review your changes. 🎉

Overall, the implementation looks good to me. I have just two minor suggestions - these aren't strictly necessary, but they could help reduce the overall complexity introduced by this PR.

One key point I'd like to discuss with the Faker team is whether the routing number data should be included in the base locale. Since routing numbers are specific to the U.S. by design, users who intentionally select the base locale typically do so to minimize the amount of imported data at startup.

Additionally, the routing number function is a legacy implementation that does not fully align with Faker's current standards. If this function were introduced today, it might be designed with a more general-purpose name - such as bankCode - to accommodate multiple locales. To be clear, I’m not suggesting deprecating the function in favor of a more generic alternative! However, given the tight coupling between its business logic and the American locale, I find it challenging to justify returning values for other locales.

Would it make sense to expose the locale data exclusively to the default en - and thus default - locale? After all, when calling this method from, for example, the de locale, would users really expect an ABA routing number? 🤔 FYI the German equivalent of "routing number" would be the "Bankleitzahl".

Looking forward to your thoughts @faker-js/members!


describe('routingNumber()', () => {
it('should return a string', () => {
it('should return a string and pass check digit validation', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should return a string and pass check digit validation', () => {
it('should return a valid ABA routing number', () => {

@@ -0,0 +1,168 @@
// Source: https://www.frbservices.org/resources/fees/check-key-to-routing-numbers.html
// Last Synced with Source: 2025-03-01
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can get the general information based on the commit date. I strongly believe that we would update these values (if required) before merging a PR that changes them.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should leave the source URL at the top though right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're saying just remove the // Last Synced comment right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Providing Source is very appreciated. Only the last synced line is obsolete IMO.

@xDivisionByZerox xDivisionByZerox added the s: needs decision Needs team/maintainer decision label Jun 16, 2025
@woldaker
Copy link
Author

This is true. US ABA routing numbers are for domestic transfers so that makes total sense to put them into the en_US locale. Internationally, you'd use an IBAN & SWIFT (or some other "routing number" equivalent for the country you're sending it to like GBDSC (UK) or CACPA (Canada)).

I can make those changes at some point this week after work.

@xDivisionByZerox
Copy link
Member

I can make those changes at some point this week after work.

Just making sure:
You only "need" to do the changes I specifically marked in the PR. You don't need to move the locale data just now. I'd like further feedback from other team members for now. 🙂

@woldaker
Copy link
Author

I am so sorry, work got busy and I completely forgot to finish this up! Taking another look at it now...

@woldaker
Copy link
Author

As an update, I took another look at this last night. I am not even on the same machine anymore that I was last time, so I didn't have pnpm, etc. After reinstalling what I think was everything I needed, pnpm run preflight kept failing with:

 FAIL  test/faker.spec.ts > faker > should not log anything on startup
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
...
 ELIFECYCLE  Command failed with exit code 1.
ERROR: "test:update-snapshots" exited with 1.
 ELIFECYCLE  Command failed with exit code 1.

so I'll have to take another look at it after work today.

@woldaker
Copy link
Author

woldaker commented Jul 20, 2025

Okay I was finally able to get it working. I think it was just that intermittent failure that nobody knows the cause of that was mentioned earlier. I made the changes as suggested here.

One thing I must say is that I absolutely agree that the routing number table I added does not belong in base. It belongs in any locale where US is the region. However, that brings up a different issue altogether: when someone from the UK uses faker and calls RoutingNumber(), I would think they should get a GBDSC number (the UK equivalent of the ABA), which doesn't look anything like a US ABA routing number (in the regex/string-format sense. They do both fulfill the same purpose: to identify a specific bank both in brand and in branch location physically). You can find a pretty decent list of various country's bank routing number formats here: https://developer.gs.com/docs/services/transaction-banking/routing-codes/.

Is the plan to do the same for all of them? I presume not. So that brings into question the wisdom of this PR in general. If we do this for US routing numbers, why doesn't every country get the same treatment? That would be a lot of work, of course; far too much work than anyone on the faker team (I presume) would consider to be worth the cost.

EDIT: I realized that that last paragraph would only be true if every country actually had their own RoutingNumber() function. This PR as simply an improvement to the current RoutingNumber() function, which only returns numbers formatted as a US ABA routing number anyway, falls outside the realm of what I had originally said. I think it is still an improvement that doesn't hurt or affect anything else.

Let me know your thoughts.

@xDivisionByZerox
Copy link
Member

EDIT: I realized that that last paragraph would only be true if every country actually had their own RoutingNumber() function. This PR as simply an improvement to the current RoutingNumber() function, which only returns numbers formatted as a US ABA routing number anyway, falls outside the realm of what I had originally said. I think it is still an improvement that doesn't hurt or affect anything else.

Big edit right there. I appreciate the effort you put into thinking about this feature in a wider sense. As pointed out in my previous comment the routingNumber() method is a legacy method that we got form the previous code base back in 2022. This means that it's API doesn't really align with the design choices made in modern (post v7) Faker. Ultimately the Faker team (or a community member) probably needs to design a more generic API that suites all locales for this use case.

But the change you present is targeted on the validity of the current resulting values of the routingNumber() method - which is a valid change/suggestion in it off itself. So let's focus on that.

I don't know when I or one for the team members will have time to review this PR again, but I didn't want to leave you hanging without at least an answer since I saw that you had a previous issue with your development setup, to which no one responded to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: bug Something isn't working m: finance Something is referring to the finance module p: 1-normal Nothing urgent s: needs decision Needs team/maintainer decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix finance.routingNumber() implementation

4 participants