-
Notifications
You must be signed in to change notification settings - Fork 122
feat: adds tools for handling brazilian passports #469
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
base: main
Are you sure you want to change the base?
Changes from all commits
e47aee8
f422834
468da15
3f44845
9b4c8b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { beforeEach, describe, expect, test, vi } from "vitest"; | ||
| import { isValidPassport } from "../is-valid-passport/is-valid-passport"; | ||
| import { formatPassport } from "./format-passport"; | ||
|
|
||
| describe("formatPassport", () => { | ||
| beforeEach(() => { | ||
| vi.restoreAllMocks(); | ||
| }); | ||
|
|
||
| describe("should return the formatted passport", () => { | ||
| test("when passport is valid", () => { | ||
| vi.spyOn({ isValidPassport }, "isValidPassport").mockReturnValue(true); | ||
| expect(formatPassport("yz 987654")).toBe("YZ987654"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("should return null", () => { | ||
| test("when passport is not valid", () => { | ||
| vi.spyOn({ isValidPassport }, "isValidPassport").mockReturnValue(false); | ||
| expect(formatPassport("acd12736")).toBeNull(); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { isValidPassport } from "../is-valid-passport/is-valid-passport"; | ||
| import { parsePassport } from "../parse-passport/parse-passport"; | ||
|
|
||
| /** | ||
| * Formats a Brazilian passport number for display. | ||
| * Returns the passport uppercased and without symbols, or null if invalid. | ||
| * | ||
| * @param passport - A Brazilian passport number (any case, possibly with symbols). | ||
| * @returns The formatted passport number (uppercase, no symbols), or null if invalid. | ||
| * | ||
| * @example | ||
| * formatPassport("Ab123456") // "AB123456" | ||
| * formatPassport("Ab-123456") // "AB123456" | ||
| * formatPassport("111111") // null | ||
| */ | ||
| export const formatPassport = (passport: string): string | null => { | ||
| const cleaned = parsePassport(passport.toUpperCase()); | ||
| return isValidPassport(cleaned) ? cleaned : null; | ||
|
Comment on lines
+16
to
+18
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nao acho que o |
||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { describe, expect, test } from "vitest"; | ||
| import { isValidPassport } from "../is-valid-passport/is-valid-passport"; | ||
| import { generatePassport } from "./generate-passport"; | ||
|
|
||
| describe("generatePassport", () => { | ||
| test("should always generate a valid passport", () => { | ||
| for (let i = 0; i < 10_000; i++) { | ||
| expect(isValidPassport(generatePassport())).toBe(true); | ||
| } | ||
| }); | ||
| }); | ||
|
Comment on lines
+1
to
+11
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. talvez seja um numero mt grande, n sei quanto a gente utilizou nos outros generates, mas seria bom dar uma olhada e usar o mesmo |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * Generates a random valid Brazilian passport number. | ||
| * | ||
| * @returns A random valid passport number string (e.g. "RY393097"). | ||
| * | ||
| * @example | ||
| * generatePassport() // "RY393097" | ||
| * generatePassport() // "ZS840088" | ||
| */ | ||
| export const generatePassport = (): string => { | ||
| const letters = Array.from({ length: 2 }, () => | ||
| String.fromCharCode(65 + Math.floor(Math.random() * 26)), | ||
| ).join(""); | ||
|
|
||
| const digits = Array.from({ length: 6 }, () => | ||
| Math.floor(Math.random() * 10), | ||
| ).join(""); | ||
|
|
||
| return `${letters}${digits}`; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import { describe, expect, test } from "vitest"; | ||
| import { isValidPassport } from "./is-valid-passport"; | ||
|
|
||
| describe("isValidPassport", () => { | ||
| describe("should return false", () => { | ||
| test("when passport is not a string", () => { | ||
| expect(isValidPassport(1 as unknown as string)).toBe(false); | ||
| }); | ||
|
|
||
| test("when passport length is different from 8", () => { | ||
| expect(isValidPassport("1")).toBe(false); | ||
| }); | ||
|
|
||
| test("when passport does not match the expected format", () => { | ||
| expect(isValidPassport("1112223334-")).toBe(false); | ||
| }); | ||
| }); | ||
|
|
||
| describe("should return true", () => { | ||
| test("when passport is valid", () => { | ||
| expect(isValidPassport("AA111111")).toBe(true); | ||
| expect(isValidPassport("CL125167")).toBe(true); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * Checks if a Brazilian passport number is valid. | ||
| * To be considered valid, the input must be a string containing exactly two | ||
| * alphabetical characters followed by exactly six numerical digits. | ||
| * This function does not verify if the input is a real passport number, | ||
| * as there are no checksums for the Brazilian passport. | ||
| * | ||
| * @param passport - The string containing the passport number to be checked. | ||
| * @returns True if the passport number is valid (2 letters followed by 6 digits). | ||
| * | ||
| * @example | ||
| * isValidPassport("Ab123456") // false - must be uppercase | ||
| * isValidPassport("AB123456") // true | ||
| * isValidPassport("12345678") // false | ||
| * isValidPassport("DC-221345") // false | ||
| */ | ||
| export const isValidPassport = (passport: string): boolean => { | ||
| if (typeof passport !== "string") return false; | ||
| return /^[A-Z]{2}[0-9]{6}$/.test(passport); | ||
| }; | ||
|
Comment on lines
+17
to
+20
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aqui o passport pode ser string ou number, verifica como estao os outros
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aqui como fazemos no formatCnpj for exemplo: export const formatCnpj = (
value: string | number,
options?: FormatCnpjOptions,
): string =>
format({
pad: options?.pad,
value: sanitize(value, options?.version),
pattern: "00.000.000/0000-00",
}); |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { describe, expect, test } from "vitest"; | ||
| import { parsePassport } from "./parse-passport"; | ||
|
|
||
| describe("parsePassport", () => { | ||
| describe("should return the string without symbols", () => { | ||
| test("when there are no symbols, returns the same string", () => { | ||
| expect(parsePassport("Ab123456")).toBe("Ab123456"); | ||
| }); | ||
|
|
||
| test("when there are spaces", () => { | ||
| expect(parsePassport(" AB 123 456 ")).toBe("AB123456"); | ||
| }); | ||
|
|
||
| test("when there are dashes", () => { | ||
| expect(parsePassport("-AB1-23-4-56-")).toBe("AB123456"); | ||
| }); | ||
|
|
||
| test("when there are dots", () => { | ||
| expect(parsePassport(".AB.1.23.456.")).toBe("AB123456"); | ||
| }); | ||
|
|
||
| test("when there are multiple symbols", () => { | ||
| expect(parsePassport(".A B.1.2-3.45 -. 6.")).toBe("AB123456"); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /** | ||
| * Removes symbols ('-', '.', and whitespaces) from a passport number. | ||
| * | ||
| * @param passport - The string containing a passport number. | ||
| * @returns The passport number with dashes, dots, and whitespaces removed. | ||
| * | ||
| * @example | ||
| * parsePassport("Ab123456") // "Ab123456" | ||
| * parsePassport("Ab-123456") // "Ab123456" | ||
| * parsePassport("Ab -. 123456") // "Ab123456" | ||
| */ | ||
| export const parsePassport = (passport: string): string => | ||
| passport.replace(/[\s.-]/g, ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tem como tu tirar o mock aqui?