-
-
Notifications
You must be signed in to change notification settings - Fork 915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using specific locales and calling prefix or jobTitle throws error: Calling faker.helpers.arrayElement()
without arguments is no longer supported.
#2503
Comments
Please note that the methods throwing an error when no data are provided is expected behavior although the exact error message is not. See also: Could you please checkout the PR and check whether it matches your expectations? |
Can confirm this bug due to the mentioned locale data being faker/src/modules/person/index.ts Line 310 in 74f6bbd
|
Checking out that PR it still throws an error if we do the following:
The error is better and more informative though:
I feel the library should not be throwing for the built-in locales and methods. I appreciate that for these locales we don't know what to return but instead of doing null would it be terrible if the locale definition returned an empty string or English with a console warning instead of an error? For example in my application I dynamically allow a user to select a locale and then generate some data using faker methods. With the current implementation I'm going to need to wrap each method call with try/catch as I still want some partial data instead of returning nothing if only one method fails. i.e. import { allFakers } from '@faker-js/faker';
function generateData(locale: keyof allFakers) {
const faker = allFakers[locale];
const data: Record<string, string> = {};
try {
data.name = faker.person.name();
} catch(e) { /* ignore */ }
try {
data.prefix = faker.person.prefix();
} catch(e) { /* ignore */ }
// ... etc
return data;
} Vs if faker handling locales import { allFakers } from '@faker-js/faker';
function generateData(locale: keyof allFakers) {
const faker = allFakers[locale];
return {
name: faker.person.name(),
prefix: faker.person.prefix(),
// ... etc
}
} |
The methods which currently throw when called with default parameters are as follows: When this is deliberate I think it would be good to mark these methods with @throws with a more detailed explanation as to why it throws, e.g. Presumably that would also allow tooling to indicate when a try-catch is needed?
Quick and dirty script for finding theseconst {
allFakers,
faker
} = require("@faker-js/faker")
const keys = Object.keys(allFakers)
const missing = {}
for (let key of keys) {
if (!["base"].includes(key)) {
const localFaker = allFakers[key]
let modules = Object.keys(faker)
for (let module of modules) {
if (!["rawDefinitions", "definitions", "helpers", "image", "string", "random"].includes(module)) {
let methods = Object.keys(faker[module])
for (let method of methods) {
if (!["faker"].includes(method)) {
try {
const result = localFaker[module][method]()
} catch (e) {
if (!missing[`${module}.${method}`]) {
missing[`${module}.${method}`] = []
}
missing[`${module}.${method}`].push(key)
}
}
}
}
}
}
}
for (let key2 of Object.keys(missing)) {
console.log(key2 + ": " + missing[key2].join(","))
} |
Well, then we would have to put the throws label on every method that uses locale data. Returning undefined can be just as bad for those that enable strictNotNull checks. |
Workaround: /*
* Defaults to undefined if the method throws an error.
*/
function du(fn: () => string) : string | undefined {
try {
return fn();
} catch {
return undefined;
}
} Usage: const jobTitle = du(() => faker.person.jobTitle()); |
We don't have to do that. We should document things that will likely trip up developers in built in methods and locales. |
@ST-DDT that workaround is okay and maybe acceptable for methods you know that will throw. However, as this could be indeterminate from consumers' point of view, you are asking us to wrap every method just in case it will throw. I can easily see others having failing tests where the test uses a random locale and some methods throw during the test suite. The PR to improve the error message will help isolate the cause. I do agree that returning Would it be terrible to fall back to the en locale definitions for these locales? |
Have to disagree with you here. Would be super confusing for me as a dev if some functions have a specific throw description because they are "more likely" to throw, but others don't yet they (could) throw will throw. |
Yes and no. What we really want is the community to get active to provide missing locale data. That is the reason why we explicitly decided on throwing for missing locale data. Nevertheless, I can understand that this might be frustrating, but you can always choose to use the default faker jnstance to ensure that all methods work.
Good that we agree on that.
It's not terrible, but we explicitly decided against that (I can provide a reference link later, currently on my phone). The reason is that if you use a specific locale, you do that on purpose to omit English locale data. If that wouldn't be the case, you would simply use the English locale. Another workaround would be to create your |
The prebuilt instances actually do fallback to en for missing data. Non applicable data on the other hand don't fall back. Unfortunately, that is the error you are running into. As @xDivisionByZerox mentioned, you can always create your own locale to circumvent the issue, or just omit locales, that don't work for your usecase. EDIT See also: https://fakerjs.dev/api/utils.html#mergelocales You can eliminate non applicable data by replacing faker/src/utils/merge-locales.ts Line 22 in 30557b9
with if (merged[key] == null) { in your copy of that method. @xDivisionByZerox Should we add an option (disabled by default) to our method for that? 🤔 |
@xDivisionByZerox @ST-DDT Ok, thanks for your rapid response thus far. I have a few work arounds:
For 3 I tried this, but it still throws an error am I missing something? function fakerFallback(faker: typeof Faker): typeof Faker {
for (const locale in faker.allFakers) {
Object.defineProperty(
faker.allFakers,
locale,
faker.mergeLocales([
faker.allLocales[locale as keyof typeof faker.allFakers],
faker.allLocales.en,
])
);
}
return faker;
}
// I would expect calling the following to fallback to english?
faker.allFakers.az.person.prefix(); |
I think adding @throws to every method that potentially throws with missing locale data would also raise awareness of the issue. Is there any downside to doing this? |
@labithiotis You have to use your own variant of |
Current mergeLocales is only merging on top-level definitions, i.e. if Also happens on the PR to improve the error messaging too. |
Yeah, I think I might have mad a mistake with the suggested mergeLocales changes. Here the fixed workaround: export function mergeLocales(locales: LocaleDefinition[]): LocaleDefinition {
const merged: LocaleDefinition = {};
for (const locale of locales) {
for (const key in locale) {
const value = locale[key];
if (merged[key] === undefined) {
merged[key] = { ...value };
} else {
merged[key] = { ...value, ...merged[key] };
}
// Remove explicitly absent values
const module = merged[key];
for (const entryKey in module) {
if (module[entryKey] == null) {
delete module[entryKey];
}
}
}
}
return merged;
} |
Team Decision
|
Pre-Checks
Describe the bug
When using a specific locale and method
person.prefix
orperson.jobTitle
it throws an error:I suspect the issue is the locale data has empty/missing array which is passed into the helper method by prefix or jobTitle.
Expected behaviour
I would expect this not to crash/throw an error.
Effected locales
az
id_ID
ru
zh_CN
zh_TW
Solutions
Minimal reproduction code
https://codesandbox.io/s/sad-maxwell-m44x5y?file=/src/index.mjs
Additional Context
There may be other locales and methods that are also effected by this too.
Environment Info
Which module system do you use?
Used Package Manager
pnpm
The text was updated successfully, but these errors were encountered: