diff --git a/cypress/e2e/api.cy.ts b/cypress/e2e/api.cy.ts index be61f5dfc5b..e87ea856f50 100644 --- a/cypress/e2e/api.cy.ts +++ b/cypress/e2e/api.cy.ts @@ -34,7 +34,7 @@ describe('API Test', () => { cy.get('.api-group li').each(($el) => { const anchor = $el.find('a'); const text = anchor.text(); - const link = anchor.attr('href').split('#')[0]; + const link = anchor.attr('href')?.split('#')[0] ?? 'MISSING'; if (checked.has(link)) { return; } diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 12fea107d34..e8484526a74 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -121,11 +121,14 @@ const config = defineConfig({ { icon: 'github', link: 'https://github.com/faker-js/faker' }, ], - algolia: { - apiKey: process.env.API_KEY, - appId: process.env.APP_ID, - indexName: 'fakerjs', - }, + algolia: + process.env.API_KEY == null || process.env.APP_ID == null + ? undefined + : { + apiKey: process.env.API_KEY, + appId: process.env.APP_ID, + indexName: 'fakerjs', + }, footer: { message: 'Released under the MIT License.', diff --git a/docs/.vitepress/versions.ts b/docs/.vitepress/versions.ts index 2964557cee9..90b0fc8dd25 100644 --- a/docs/.vitepress/versions.ts +++ b/docs/.vitepress/versions.ts @@ -14,18 +14,23 @@ function readOtherLatestReleaseTagNames(): string[] { .toString('utf8') .split('\n') .filter((tag) => semver.valid(tag)) - .reduce>((acc, tag) => { - const majorVersion = semver.major(tag); + .filter((tag) => { // Only consider tags for our deployed website versions, // excluding the current major version. - if (majorVersion >= 6 && majorVersion !== currentMajorVersion) { - (acc[majorVersion] = acc[majorVersion] ?? []).push(tag); + const majorVersion = semver.major(tag); + return majorVersion >= 6 && majorVersion !== currentMajorVersion; + }) + .reduce>((latestTagByMajor, tag) => { + const majorVersion = semver.major(tag); + + const latestTag = latestTagByMajor[majorVersion]; + if (latestTag == null || semver.lt(latestTag, tag)) { + latestTagByMajor[majorVersion] = tag; } - return acc; + + return latestTagByMajor; }, {}); - return Object.entries(latestReleaseTagNames) - .map(([major, tags]) => semver.maxSatisfying(tags, `^${major}`)) - .sort(semver.rcompare); + return Object.values(latestReleaseTagNames).sort(semver.rcompare); } // Set by netlify diff --git a/scripts/apidoc/faker-class.ts b/scripts/apidoc/faker-class.ts index 6672896c50b..a9acad3cb41 100644 --- a/scripts/apidoc/faker-class.ts +++ b/scripts/apidoc/faker-class.ts @@ -28,6 +28,10 @@ export async function processFakerRandomizer( .getChildrenByKind(ReflectionKind.Interface) .find((clazz) => clazz.name === 'Randomizer'); + if (randomizerClass == null) { + throw new Error('Randomizer class not found'); + } + return processClass(randomizerClass); } @@ -63,7 +67,7 @@ async function processClass( function hasConstructor(clazz: DeclarationReflection): boolean { return clazz .getChildrenByKind(ReflectionKind.Constructor) - .some((constructor) => constructor.signatures.length > 0); + .some((constructor) => (constructor.signatures?.length ?? 0) > 0); } async function processConstructor( diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts index 08fe5896b18..82d4047ef7d 100644 --- a/scripts/apidoc/signature.ts +++ b/scripts/apidoc/signature.ts @@ -305,7 +305,7 @@ async function signatureTypeToText( await Promise.all( signature.parameters?.map( async (p) => `${p.name}: ${await typeToText(p.type)}` - ) + ) ?? [] ) ).join(', ')}) => ${await typeToText(signature.type)}`; } diff --git a/src/definitions/date.ts b/src/definitions/date.ts index 16cfb28aa26..2265a0256cf 100644 --- a/src/definitions/date.ts +++ b/src/definitions/date.ts @@ -26,8 +26,9 @@ export interface DateEntryDefinition { /** * The short name/abbreviation of the entry. + * If null, the locale does not support a short name/abbreviation for the entry. */ - abbr: string[]; + abbr: string[] | null; /** * The wide name of the entry when used in context. If absent wide will be used instead. diff --git a/src/definitions/definitions.ts b/src/definitions/definitions.ts index ca495e3477a..c2a3b560099 100644 --- a/src/definitions/definitions.ts +++ b/src/definitions/definitions.ts @@ -50,4 +50,4 @@ export type LocaleDefinition = { system?: SystemDefinition; vehicle?: VehicleDefinition; word?: WordDefinition; -} & Record | undefined>; +} & Record>; diff --git a/src/locale-proxy.ts b/src/locale-proxy.ts index 67b29d473cc..e99ba655156 100644 --- a/src/locale-proxy.ts +++ b/src/locale-proxy.ts @@ -54,6 +54,30 @@ export function createLocaleProxy(locale: LocaleDefinition): LocaleProxy { }) as LocaleProxy; } +/** + * Checks that the value is not null or undefined and throws an error if it is. + * + * @param value The value to check. + * @param path The path to the locale data. + */ +export function assertLocaleData( + value: T, + ...path: string[] +): asserts value is NonNullable { + if (value === null) { + throw new FakerError( + `The locale data for '${path.join('.')}' aren't applicable to this locale. + If you think this is a bug, please report it at: https://github.com/faker-js/faker` + ); + } else if (value === undefined) { + throw new FakerError( + `The locale data for '${path.join('.')}' are missing in this locale. + Please contribute the missing data to the project or use a locale/Faker instance that has these data. + For more information see https://fakerjs.dev/guide/localization.html` + ); + } +} + /** * Creates a proxy for a category that throws an error when accessing an undefined property. * @@ -79,20 +103,10 @@ function createCategoryProxy< const value = target[entryName]; if (typeof entryName === 'symbol' || entryName === 'nodeType') { return value; - } else if (value === null) { - throw new FakerError( - `The locale data for '${categoryName}.${entryName.toString()}' aren't applicable to this locale. - If you think this is a bug, please report it at: https://github.com/faker-js/faker` - ); - } else if (value === undefined) { - throw new FakerError( - `The locale data for '${categoryName}.${entryName.toString()}' are missing in this locale. - Please contribute the missing data to the project or use a locale/Faker instance that has these data. - For more information see https://fakerjs.dev/guide/localization.html` - ); - } else { - return value; } + + assertLocaleData(value, categoryName, entryName.toString()); + return value; }, set: throwReadOnlyError, diff --git a/src/modules/airline/index.ts b/src/modules/airline/index.ts index 4c1ec318eeb..e8ac47c58c2 100644 --- a/src/modules/airline/index.ts +++ b/src/modules/airline/index.ts @@ -155,7 +155,7 @@ export class AirlineModule extends ModuleBase { ): string { const { allowNumerics = false, allowVisuallySimilarCharacters = false } = options; - const excludedChars = []; + const excludedChars: string[] = []; if (!allowNumerics) { excludedChars.push(...numerics); } diff --git a/src/modules/color/index.ts b/src/modules/color/index.ts index 5962ef71b67..57b906a376d 100644 --- a/src/modules/color/index.ts +++ b/src/modules/color/index.ts @@ -47,17 +47,19 @@ export type Casing = 'lower' | 'upper' | 'mixed'; * * @param hexColor Hex color string to be formatted. * @param options Options object. - * @param options.prefix Prefix of the generated hex color. Defaults to `'0x'`. - * @param options.casing Letter type case of the generated hex color. Defaults to `'mixed'`. + * @param options.prefix Prefix of the generated hex color. + * @param options.casing Letter type case of the generated hex color. */ function formatHexColor( hexColor: string, - options?: { - prefix?: string; - casing?: Casing; + options: { + prefix: string; + casing: Casing; } ): string { - switch (options?.casing) { + const { prefix, casing } = options; + + switch (casing) { case 'upper': hexColor = hexColor.toUpperCase(); break; @@ -68,8 +70,8 @@ function formatHexColor( // Do nothing } - if (options?.prefix) { - hexColor = options.prefix + hexColor; + if (prefix) { + hexColor = prefix + hexColor; } return hexColor; @@ -360,19 +362,20 @@ export class ColorModule extends ModuleBase { */ includeAlpha?: boolean; }): string | number[]; - rgb(options?: { - prefix?: string; - casing?: Casing; - format?: 'hex' | ColorFormat; - includeAlpha?: boolean; - }): string | number[] { + rgb( + options: { + prefix?: string; + casing?: Casing; + format?: 'hex' | ColorFormat; + includeAlpha?: boolean; + } = {} + ): string | number[] { const { format = 'hex', includeAlpha = false, prefix = '#', casing = 'lower', - } = options || {}; - options = { format, includeAlpha, prefix, casing }; + } = options; let color: string | number[]; let cssFunction: CssFunctionType = 'rgb'; if (format === 'hex') { @@ -380,7 +383,7 @@ export class ColorModule extends ModuleBase { length: includeAlpha ? 8 : 6, prefix: '', }); - color = formatHexColor(color, options); + color = formatHexColor(color, { prefix, casing }); return color; } diff --git a/src/modules/commerce/index.ts b/src/modules/commerce/index.ts index 1be3fcb2765..425bc8483e9 100644 --- a/src/modules/commerce/index.ts +++ b/src/modules/commerce/index.ts @@ -1,3 +1,4 @@ +import { FakerError } from '../../errors/faker-error'; import { deprecated } from '../../internal/deprecated'; import { ModuleBase } from '../../internal/module-base'; @@ -401,7 +402,14 @@ export class CommerceModule extends ModuleBase { const registrantLength = groupRules.find( ([rangeMaximum]) => elementValue <= rangeMaximum - )[1]; + )?.[1]; + + if (!registrantLength) { + // This can only happen if the ISBN_LENGTH_RULES are corrupted + throw new FakerError( + `Unable to find a registrant length for the group ${group}` + ); + } const registrant = element.slice(0, registrantLength); const publication = element.slice(registrantLength); diff --git a/src/modules/date/index.ts b/src/modules/date/index.ts index a40b477247a..39c857354b7 100644 --- a/src/modules/date/index.ts +++ b/src/modules/date/index.ts @@ -3,6 +3,7 @@ import type { DateEntryDefinition } from '../../definitions'; import { FakerError } from '../../errors/faker-error'; import { deprecated } from '../../internal/deprecated'; import { SimpleModuleBase } from '../../internal/module-base'; +import { assertLocaleData } from '../../locale-proxy'; /** * Converts date passed as a string, number or Date to a Date object. @@ -15,6 +16,10 @@ function toDate( date: string | Date | number | undefined, fallback: () => Date ): Date { + if (date == null) { + return fallback(); + } + date = new Date(date); if (Number.isNaN(date.valueOf())) { date = fallback(); @@ -383,14 +388,15 @@ export class SimpleDateModule extends SimpleModuleBase { }, legacyTo?: string | Date | number ): Date { - if (typeof options !== 'object' || options instanceof Date) { + if (options instanceof Date || typeof options !== 'object') { deprecated({ deprecated: 'faker.date.between(from, to)', proposed: 'faker.date.between({ from, to })', since: '8.0', until: '9.0', }); - options = { from: options, to: legacyTo }; + // We use options as fallback for legacyTo avoid TS errors for unintended usage. + options = { from: options, to: legacyTo ?? options }; } const { from, to } = options; @@ -559,14 +565,15 @@ export class SimpleDateModule extends SimpleModuleBase { legacyTo?: string | Date | number, legacyCount: number = 3 ): Date[] { - if (typeof options !== 'object' || options instanceof Date) { + if (options instanceof Date || typeof options !== 'object') { deprecated({ deprecated: 'faker.date.betweens(from, to, count)', proposed: 'faker.date.betweens({ from, to, count })', since: '8.0', until: '9.0', }); - options = { from: options, to: legacyTo, count: legacyCount }; + // We use options as fallback for legacyTo avoid TS errors for unintended usage. + options = { from: options, to: legacyTo ?? options, count: legacyCount }; } const { from, to, count = 3 } = options; @@ -864,12 +871,6 @@ export class SimpleDateModule extends SimpleModuleBase { refDate?: string | Date | number; } = {} ): Date { - if (options.max < options.min) { - throw new FakerError( - `Max ${options.max} should be larger than or equal to min ${options.min}.` - ); - } - const mode = options.mode === 'age' ? 'age' : 'year'; const refDate = toDate(options.refDate, this.faker.defaultRefDate); const refYear = refDate.getUTCFullYear(); @@ -894,6 +895,12 @@ export class SimpleDateModule extends SimpleModuleBase { ); } + if (max < min) { + throw new FakerError( + `Max ${options.max} should be larger than or equal to min ${options.min}.` + ); + } + return new Date(this.faker.number.int({ min, max })); } } @@ -1074,12 +1081,8 @@ export class DateModule extends SimpleDateModule { context?: boolean; } = {} ): string { - const { - // eslint-disable-next-line deprecation/deprecation - abbr, - abbreviated = abbr ?? false, - context = false, - } = options; + // eslint-disable-next-line deprecation/deprecation + const { abbr, abbreviated = abbr ?? false, context = false } = options; if (abbr != null) { deprecated({ @@ -1100,7 +1103,9 @@ export class DateModule extends SimpleDateModule { type = useContext ? 'wide_context' : 'wide'; } - return this.faker.helpers.arrayElement(source[type]); + const values = source[type]; + assertLocaleData(values, 'date.month', type); + return this.faker.helpers.arrayElement(values); } /** @@ -1260,12 +1265,8 @@ export class DateModule extends SimpleDateModule { context?: boolean; } = {} ): string { - const { - // eslint-disable-next-line deprecation/deprecation - abbr, - abbreviated = abbr ?? false, - context = false, - } = options; + // eslint-disable-next-line deprecation/deprecation + const { abbr, abbreviated = abbr ?? false, context = false } = options; if (abbr != null) { deprecated({ @@ -1286,6 +1287,8 @@ export class DateModule extends SimpleDateModule { type = useContext ? 'wide_context' : 'wide'; } - return this.faker.helpers.arrayElement(source[type]); + const values = source[type]; + assertLocaleData(values, 'date.weekday', type); + return this.faker.helpers.arrayElement(values); } } diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts index c443b6055df..33db26f0003 100644 --- a/src/modules/finance/index.ts +++ b/src/modules/finance/index.ts @@ -23,6 +23,22 @@ export interface Currency { symbol: string; } +/** + * Puts a space after every 4 characters. + * + * @internal + * + * @param iban The iban to pretty print. + */ +export function prettyPrintIban(iban: string): string { + let pretty = ''; + for (let i = 0; i < iban.length; i += 4) { + pretty += `${iban.substring(i, i + 4)} `; + } + + return pretty.trimEnd(); +} + /** * Module to generate finance and money related entries. * @@ -663,9 +679,9 @@ export class FinanceModule extends ModuleBase { */ currencySymbol(): string { let symbol: string; - while (!symbol) { + do { symbol = this.currency().symbol; - } + } while (symbol.length === 0); return symbol; } @@ -1147,7 +1163,7 @@ export class FinanceModule extends ModuleBase { const result = `${ibanFormat.country}${checksum}${s}`; - return formatted ? result.match(/.{1,4}/g).join(' ') : result; + return formatted ? prettyPrintIban(result) : result; } /** diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 59eeadba59f..667f3a51d4d 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -1120,7 +1120,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { ) => RecordKey, >( method: TMethod, - args: Parameters = [] as Parameters, + args: Parameters = [] as unknown as Parameters, options: { /** * This parameter does nothing. diff --git a/src/modules/helpers/unique.ts b/src/modules/helpers/unique.ts index 44b3a71d339..20805530478 100644 --- a/src/modules/helpers/unique.ts +++ b/src/modules/helpers/unique.ts @@ -97,9 +97,9 @@ export function exec< maxRetries = 50, currentIterations = 0, compare = defaultCompare, - store, + store = {}, } = options; - let { exclude } = options; + let { exclude = [] } = options; options.currentIterations = currentIterations; // Support single exclude argument as string diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 5eb9b4bc279..8cc651a3fd7 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -620,6 +620,7 @@ export class InternetModule extends ModuleBase { firstName + this.faker.helpers.arrayElement(['.', '_']) + lastName; break; case 2: + default: result = `${firstName}${this.faker.helpers.arrayElement([ '.', '_', @@ -804,6 +805,7 @@ export class InternetModule extends ModuleBase { firstName + this.faker.helpers.arrayElement(['.', '_']) + lastName; break; case 2: + default: result = `${firstName}${this.faker.helpers.arrayElement([ '.', '_', diff --git a/src/modules/person/index.ts b/src/modules/person/index.ts index e0f4b6b0c67..0c5f79c37ce 100644 --- a/src/modules/person/index.ts +++ b/src/modules/person/index.ts @@ -1,5 +1,7 @@ import type { Faker } from '../..'; +import { FakerError } from '../../errors/faker-error'; import { ModuleBase } from '../../internal/module-base'; +import { assertLocaleData } from '../../locale-proxy'; export enum Sex { Female = 'female', @@ -18,6 +20,7 @@ export type SexType = `${Sex}`; * @param param2.generic Non-sex definitions. * @param param2.female Female definitions. * @param param2.male Male definitions. + * @param type Type of the definition. * * @returns Definition based on given sex. */ @@ -25,10 +28,14 @@ function selectDefinition( faker: Faker, elementSelectorFn: (values: T[]) => string, sex: SexType | undefined, - // TODO @Shinigami92 2022-03-21: Remove fallback empty object when `strict: true` - { generic, female, male }: { generic?: T[]; female?: T[]; male?: T[] } = {} + { + generic, + female, + male, + }: { generic?: T[] | null; female?: T[] | null; male?: T[] | null }, + type: string ): string { - let values: T[] | undefined; + let values: T[] | undefined | null; switch (sex) { case Sex.Female: @@ -50,6 +57,8 @@ function selectDefinition( } else { values = generic; } + + assertLocaleData(values, `person.{${type}, female_${type}, male_${type}}`); } return elementSelectorFn(values); @@ -92,11 +101,17 @@ export class PersonModule extends ModuleBase { const { first_name, female_first_name, male_first_name } = this.faker.rawDefinitions.person ?? {}; - return selectDefinition(this.faker, this.faker.helpers.arrayElement, sex, { - generic: first_name, - female: female_first_name, - male: male_first_name, - }); + return selectDefinition( + this.faker, + this.faker.helpers.arrayElement, + sex, + { + generic: first_name, + female: female_first_name, + male: male_first_name, + }, + 'first_name' + ); } /** @@ -135,16 +150,23 @@ export class PersonModule extends ModuleBase { generic: last_name_pattern, female: female_last_name_pattern, male: male_last_name_pattern, - } + }, + 'last_name_pattern' ); return this.faker.helpers.fake(pattern); } - return selectDefinition(this.faker, this.faker.helpers.arrayElement, sex, { - generic: last_name, - female: female_last_name, - male: male_last_name, - }); + return selectDefinition( + this.faker, + this.faker.helpers.arrayElement, + sex, + { + generic: last_name, + female: female_last_name, + male: male_last_name, + }, + 'last_name' + ); } /** @@ -164,11 +186,17 @@ export class PersonModule extends ModuleBase { const { middle_name, female_middle_name, male_middle_name } = this.faker.rawDefinitions.person ?? {}; - return selectDefinition(this.faker, this.faker.helpers.arrayElement, sex, { - generic: middle_name, - female: female_middle_name, - male: male_middle_name, - }); + return selectDefinition( + this.faker, + this.faker.helpers.arrayElement, + sex, + { + generic: middle_name, + female: female_middle_name, + male: male_middle_name, + }, + 'middle_name' + ); } /** @@ -305,11 +333,17 @@ export class PersonModule extends ModuleBase { const { prefix, female_prefix, male_prefix } = this.faker.rawDefinitions.person ?? {}; - return selectDefinition(this.faker, this.faker.helpers.arrayElement, sex, { - generic: prefix, - female: female_prefix, - male: male_prefix, - }); + return selectDefinition( + this.faker, + this.faker.helpers.arrayElement, + sex, + { + generic: prefix, + female: female_prefix, + male: male_prefix, + }, + 'prefix' + ); } /** @@ -350,9 +384,13 @@ export class PersonModule extends ModuleBase { * @since 8.0.0 */ jobDescriptor(): string { - return this.faker.helpers.arrayElement( - this.faker.definitions.person.title.descriptor - ); + const values = this.faker.definitions.person.title.descriptor; + + if (values == null) { + throw new FakerError('No person.title.descriptor definitions available.'); + } + + return this.faker.helpers.arrayElement(values); } /** @@ -364,9 +402,13 @@ export class PersonModule extends ModuleBase { * @since 8.0.0 */ jobArea(): string { - return this.faker.helpers.arrayElement( - this.faker.definitions.person.title.level - ); + const values = this.faker.definitions.person.title.level; + + if (values == null) { + throw new FakerError('No person.title.area definitions available.'); + } + + return this.faker.helpers.arrayElement(values); } /** @@ -378,9 +420,13 @@ export class PersonModule extends ModuleBase { * @since 8.0.0 */ jobType(): string { - return this.faker.helpers.arrayElement( - this.faker.definitions.person.title.job - ); + const values = this.faker.definitions.person.title.job; + + if (values == null) { + throw new FakerError('No person.title.job definitions available.'); + } + + return this.faker.helpers.arrayElement(values); } /** diff --git a/src/modules/random/index.ts b/src/modules/random/index.ts index 997583c1165..474e8ca61a4 100644 --- a/src/modules/random/index.ts +++ b/src/modules/random/index.ts @@ -123,7 +123,7 @@ export class RandomModule extends ModuleBase { '_', '-', ]; - let result: string; + let result = ''; let iteration = 0; diff --git a/test/faker.spec.ts b/test/faker.spec.ts index 2ff5aab9468..bd42246a5a5 100644 --- a/test/faker.spec.ts +++ b/test/faker.spec.ts @@ -41,7 +41,7 @@ describe('faker', () => { describe('rawDefinitions', () => { it('locale rawDefinition accessibility', () => { // Metadata - expect(faker.rawDefinitions.metadata.title).toBeDefined(); + expect(faker.rawDefinitions.metadata?.title).toBeDefined(); // Standard modules expect(faker.rawDefinitions.location?.city_name).toBeDefined(); // Non-existing module @@ -62,7 +62,7 @@ describe('faker', () => { // Non-existing module expect(faker.definitions.missing).toBeDefined(); // Non-existing definition in a non-existing module - expect(() => faker.definitions.missing.missing).toThrow(); + expect(() => faker.definitions.missing?.missing).toThrow(); // Non-existing definition in an existing module expect(() => faker.definitions.location.missing).toThrow(); }); diff --git a/test/modules/airline.spec.ts b/test/modules/airline.spec.ts index 5ac05a5b82f..bf674570c76 100644 --- a/test/modules/airline.spec.ts +++ b/test/modules/airline.spec.ts @@ -96,7 +96,7 @@ describe('airline', () => { it('should return a random narrowbody seat when not passing an argument', () => { const seat = faker.airline.seat(); const matchResult = seatRegex.exec(seat); - expect(matchResult).not.toBeNull(); + expectNotNull(matchResult); const row = matchResult[1]; const seatLetter = matchResult[2]; expect(row).toSatisfy((row: number) => row >= 1 && row <= 35); @@ -107,7 +107,7 @@ describe('airline', () => { aircraftType: Aircraft.Narrowbody, }); const matchResult = seatRegex.exec(seat); - expect(matchResult).not.toBeNull(); + expectNotNull(matchResult); const row = matchResult[1]; const seatLetter = matchResult[2]; expect(row).toSatisfy((row: number) => row >= 1 && row <= 35); @@ -116,7 +116,7 @@ describe('airline', () => { it('should return a random regional seat', () => { const seat = faker.airline.seat({ aircraftType: Aircraft.Regional }); const matchResult = seatRegex.exec(seat); - expect(matchResult).not.toBeNull(); + expectNotNull(matchResult); const row = matchResult[1]; const seatLetter = matchResult[2]; expect(row).toSatisfy((row: number) => row >= 1 && row <= 20); @@ -125,7 +125,7 @@ describe('airline', () => { it('should return a random widebody seat', () => { const seat = faker.airline.seat({ aircraftType: Aircraft.Widebody }); const matchResult = seatRegex.exec(seat); - expect(matchResult).not.toBeNull(); + expectNotNull(matchResult); const row = matchResult[1]; const seatLetter = matchResult[2]; expect(row).toSatisfy((row: number) => row >= 1 && row <= 60); @@ -179,3 +179,7 @@ describe('airline', () => { } ); }); + +function expectNotNull(value: T): asserts value is NonNullable { + expect(value).not.toBeNull(); +} diff --git a/test/modules/finance-iban.spec.ts b/test/modules/finance-iban.spec.ts index 145a4751b50..4d801aa570f 100644 --- a/test/modules/finance-iban.spec.ts +++ b/test/modules/finance-iban.spec.ts @@ -1,6 +1,7 @@ import validator from 'validator'; import { describe, expect, it } from 'vitest'; import { faker } from '../../src'; +import { prettyPrintIban } from '../../src/modules/finance'; import ibanLib from '../../src/modules/finance/iban'; import { times } from '../support/times'; @@ -36,7 +37,7 @@ describe('finance_iban', () => { expect(iban).toSatisfy(validator.isIBAN); - const ibanFormatted = iban.match(/.{1,4}/g).join(' '); + const ibanFormatted = prettyPrintIban(iban); const bban = iban.substring(4) + iban.substring(0, 4); expect( @@ -96,7 +97,7 @@ describe('finance_iban', () => { expect(iban).toSatisfy(validator.isIBAN); - const ibanFormated = iban.match(/.{1,4}/g).join(' '); + const ibanFormated = prettyPrintIban(iban); const bban = iban.substring(4) + iban.substring(0, 4); expect( @@ -162,7 +163,7 @@ describe('finance_iban', () => { expect(iban).toSatisfy(validator.isIBAN); - const ibanFormated = iban.match(/.{1,4}/g).join(' '); + const ibanFormated = prettyPrintIban(iban); const bban = iban.substring(4) + iban.substring(0, 4); expect( @@ -232,7 +233,7 @@ describe('finance_iban', () => { expect(iban).toSatisfy(validator.isIBAN); - const ibanFormated = iban.match(/.{1,4}/g).join(' '); + const ibanFormated = prettyPrintIban(iban); const bban = iban.substring(4) + iban.substring(0, 4); expect( @@ -291,7 +292,7 @@ describe('finance_iban', () => { expect(iban).toSatisfy(validator.isIBAN); - const ibanFormated = iban.match(/.{1,4}/g).join(' '); + const ibanFormated = prettyPrintIban(iban); const bban = iban.substring(4) + iban.substring(0, 4); expect( @@ -336,7 +337,7 @@ describe('finance_iban', () => { // Bank account number 16 digit const iban = faker.finance.iban(false, 'AL'); - const ibanFormated = iban.match(/.{1,4}/g).join(' '); + const ibanFormated = prettyPrintIban(iban); expect(iban).toSatisfy(validator.isIBAN); diff --git a/test/modules/helpers.spec.ts b/test/modules/helpers.spec.ts index 3f850086770..766d06502c4 100644 --- a/test/modules/helpers.spec.ts +++ b/test/modules/helpers.spec.ts @@ -223,7 +223,6 @@ describe('helpers', () => { }); it('should throw on an empty array', () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return expect(() => faker.helpers.arrayElement([])).toThrow( new FakerError('Cannot get value from empty dataset.') ); @@ -1062,7 +1061,7 @@ describe('helpers', () => { }); it('should be able to return locale definition strings', () => { - expect(faker.definitions.cell_phone.formats).toContain( + expect(faker.definitions.cell_phone?.formats).toContain( faker.helpers.fake('{{cell_phone.formats}}') ); }); diff --git a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts index 7e0203350cb..b4a9f5ff730 100644 --- a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts +++ b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts @@ -160,7 +160,7 @@ describe('verify JSDoc tags', () => { // Write temp files to disk // Extract examples and make them runnable - const examples = extractJoinedRawExamples(signature); + const examples = extractJoinedRawExamples(signature) ?? ''; // Save examples to a file to run them later in the specific tests const dir = resolveDirToModule(moduleName); diff --git a/test/vitest-extensions.ts b/test/vitest-extensions.ts index e23b9c09c81..0a441d87425 100644 --- a/test/vitest-extensions.ts +++ b/test/vitest-extensions.ts @@ -2,7 +2,7 @@ import { expect } from 'vitest'; expect.extend({ toContainDuplicates(received: T[]) { - const { isNot } = this; + const { isNot = false } = this; const uniques = new Set(received); const duplications = received.filter((entry) => !uniques.delete(entry)); diff --git a/tsconfig.json b/tsconfig.json index cda27929e8f..da5cd4e6926 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "stripInternal": true, // We need to disable these for now, and need to tackle them in another PR - "strictNullChecks": false, "noImplicitAny": false, // These are configs specifically for !build and have to be reverted in the tsconfig.build.json