Skip to content

Commit

Permalink
Merge pull request #25 from derek-watson14/multiple-validator
Browse files Browse the repository at this point in the history
  • Loading branch information
Sparticuz authored Dec 7, 2023
2 parents da07a07 + 1ec9039 commit c4e9335
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 16 deletions.
60 changes: 45 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,35 @@ const usps = new USPS({
});
```

### verifyMultiple(object[])

Verify takes one parameter: object[]

object[]: [{Address1, Address2, City, State, Zip}]

**Example**

```js
usps
.verifyMultiple([{
Address1: "322 3rd st.",
Address2: "Apt 2",
City: "San Francisco",
State: "CA",
Zip5: "94103",
}, {
Address1: "322 3rd st.",
Address2: "Apt 2",
City: "San Francisco",
State: "CA",
Zip5: "94103",
}
])
.then((address) => {
console.log(address);
});
```

### verify(object)

Verify takes one parameter: object
Expand Down Expand Up @@ -88,19 +117,20 @@ console.log(result);
### Coverage

```
-------------------------|---------|----------|---------|---------|----------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------------|---------|----------|---------|---------|----------------------------------
All files | 91.78 | 59.61 | 87.5 | 91.78 |
src | 99.32 | 47.36 | 100 | 99.32 |
address-validate.ts | 98.97 | 33.33 | 100 | 98.97 | 94
usps.ts | 100 | 100 | 100 | 100 |
src/lookups | 85.55 | 60 | 66.66 | 85.55 |
city-state-lookup.ts | 97.95 | 80 | 100 | 97.95 | 45
pricing-rate-lookup.ts | 75.16 | 100 | 0 | 75.16 | 113-149
zip-code-lookup.ts | 98.61 | 50 | 100 | 98.61 | 68
src/utils | 94.58 | 72.22 | 100 | 94.58 |
proper-case.ts | 97.95 | 100 | 100 | 97.95 | 36
request.ts | 93.5 | 61.53 | 100 | 93.5 | 48-49,55,115-116,120-122,153-154
-------------------------|---------|----------|---------|---------|----------------------------------
-------------------------------|---------|----------|---------|---------|------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------------------|---------|----------|---------|---------|------------------------------
All files | 91.64 | 62.65 | 93.75 | 91.64 |
src | 95.85 | 55.55 | 100 | 95.85 |
address-validate.ts | 96 | 37.5 | 100 | 96 | 81,84,87,93
multiple-address-validate.ts | 92.77 | 54.54 | 100 | 92.77 | 62,65,68,80-82
usps.ts | 100 | 100 | 100 | 100 |
src/lookups | 84.81 | 66.66 | 83.33 | 84.81 |
city-state-lookup.ts | 100 | 83.33 | 100 | 100 | 45
pricing-rate-lookup.ts | 74.49 | 100 | 50 | 74.49 | 112-149
zip-code-lookup.ts | 95.83 | 54.54 | 100 | 95.83 | 57,60,63
src/utils | 95.65 | 75 | 100 | 95.65 |
proper-case.ts | 100 | 100 | 100 | 100 |
request.ts | 94.23 | 64.28 | 100 | 94.23 | 54-55,61,112,122-123,127-129
-------------------------------|---------|----------|---------|---------|------------------------------
```
86 changes: 86 additions & 0 deletions src/multiple-address-validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { Address, MultipleAddress } from "./usps.js";
import type USPSClass from "./usps.js";
import type { AddressValidateResponse } from "./address-validate.js";
import properCase from "./utils/proper-case.js";
import callUSPS from "./utils/request.js";

// See page 4, "AddressValidateRequest / Address /" section of: https://www.usps.com/business/web-tools-apis/address-information-api.pdf

export interface MultipleAddressValidateRequest {
Address: MultipleAddress[];
Revision: number;
}

// eslint-disable-next-line sonarjs/cognitive-complexity, func-names
export default async function (
this: USPSClass,
addresses: Address[],
): Promise<MultipleAddress[]> {
if (addresses.length > 5) {
throw new Error("Maximum of 5 addresses allowed per request.")
}

if (Array.isArray(addresses) === false) {
throw new TypeError("Must pass an array of addresses. For single address use 'verify' method.");
}

const Addresses: MultipleAddress[] = addresses.map((address: Address, index: number) => ({
'@ID': index.toString(),
Address1: address.Address2 ?? "",
Address2: address.Address1 ?? "",
City: address.City ?? "",
State: address.State ?? "",
Urbanization: address.Urbanization ?? "",
Zip5: address.Zip5 ?? "",
// USPS expects Zip4 after Zip5
// eslint-disable-next-line sort-keys
Zip4: address.Zip4 ?? "",
}));

const parameters: MultipleAddressValidateRequest = {
Revision: 1,
// USPS expects Address to come after Revision
// eslint-disable-next-line sort-keys
Address: Addresses,
};

let response: AddressValidateResponse[];
try {
response = (await callUSPS(
"Verify",
"AddressValidate",
"Address",
this.config,
parameters,
)) as AddressValidateResponse[];
if (response) {
return response.map((addr) => {
const fAddr = { ...addr };

const switchAddresses = fAddr.Address1;
fAddr.Address1 = fAddr.Address2;
fAddr.Address2 = switchAddresses;
if (this.config.properCase) {
fAddr.Address1 = fAddr.Address1
? properCase(fAddr.Address1)
: undefined;
fAddr.Address2 = fAddr.Address2
? properCase(fAddr.Address2)
: undefined;
fAddr.City = fAddr.City ? properCase(fAddr.City) : undefined;
fAddr.FirmName = fAddr.FirmName
? properCase(fAddr.FirmName)
: undefined;
}
fAddr.Zip4 =
typeof fAddr.Zip4 === "object"
? undefined
: fAddr.Zip4?.toString();
return fAddr as MultipleAddress;
});
}
throw new Error("Can't find results");
} catch (error) {
throw new Error(error as string);
}
}
10 changes: 10 additions & 0 deletions src/usps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import verify from "./address-validate.js";
import verifyMultiple from "./multiple-address-validate.js"
import cityStateLookup from "./lookups/city-state-lookup.js";
import pricingRateLookup from "./lookups/pricing-rate-lookup.js";
import zipCodeLookup from "./lookups/zip-code-lookup.js";
Expand Down Expand Up @@ -28,6 +29,13 @@ export interface Address {
Zip5?: string;
}

// Each address needs an ID when sending multiple in a single request
// Error can be returned for each address
export interface MultipleAddress extends Address {
"@ID": string;
Error?: ErrorResponse;
}

export default class {
public cityStateLookup = cityStateLookup;

Expand All @@ -46,5 +54,7 @@ export default class {

public verify = verify;

public verifyMultiple = verifyMultiple;

public zipCodeLookup = zipCodeLookup;
}
4 changes: 4 additions & 0 deletions src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import type {
AddressValidateRequest,
AddressValidateResponse,
} from "../address-validate.js";
import type {
MultipleAddressValidateRequest,
} from "../multiple-address-validate.js";
import type {
CityStateLookupRequest,
CityStateLookupResponse,
Expand Down Expand Up @@ -72,6 +75,7 @@ export default async (
config: Config,
parameters:
| AddressValidateRequest
| MultipleAddressValidateRequest
| ZipCodeLookupRequest
| CityStateLookupRequest
| RateV4Request,
Expand Down
115 changes: 115 additions & 0 deletions test/multiple-validator-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable sonarjs/no-duplicate-string */
import test from "ava";

import USPS from "../src/usps.js";

const usps = new USPS({
userId: process.env["USPS_ID"]!,
});

const fourAddresses = [
{
Address1: "11205 SE 233RD PL.",
Address2: "Apartment 2",
City: "Kent",
State: "WA",
Zip5: "98031",
},
{
Address1: "11205 SE 233RD PL.",
Address2: "UNIT 2",
City: "Kent",
State: "WA",
Zip5: "98031",
},
{
Address1: "11205 southeast 233Road PLace.",
Address2: "Building 2",
City: "Kent",
State: "WA",
Zip5: "98031",
},
{
Address1: "11205 SE 233RD PL.",
Address2: "Floor 2",
City: "Kent",
State: "WA",
Zip5: "98031",
},
];

const moreAddresses = [
{
Address1: "11205 SE 233RD PL.",
Address2: "Apartment 4",
City: "Kent",
State: "WA",
Zip5: "98031",
},
{
Address1: "11205 southeast 233Road PLace.",
Address2: "Building 3",
City: "Kent",
State: "WA",
Zip5: "98031",
},
]

const invalidAddress = {
Address1: "1212 s kingsway rd",
City: "seffner",
State: "fl",
Zip5: "33584",
}

test("Multiple address verify should return the same number of addresses.", async (t) => {
const addresses = await usps.verifyMultiple(fourAddresses);
t.is(addresses.length, 4);
});

test("Multiple address verify should only accept addesses in an array.", async (t) => {
const error = await t.throwsAsync(async () => {
// @ts-expect-error Testing invalid input
await usps.verifyMultiple(fourAddresses[0]);
});
t.is(
error?.message,
"Must pass an array of addresses. For single address use 'verify' method.",
);
});

test("Multiple address verify should throw an error if more than 5 addresses are passed.", async (t) => {
const error = await t.throwsAsync(async () => {
await usps.verifyMultiple([...fourAddresses, ...moreAddresses]);
});
t.is(
error?.message,
"Maximum of 5 addresses allowed per request.",
);
});

test("Multiple address verify should validate each address in the same way as a single verify would.", async (t) => {
const addresses = await usps.verifyMultiple(fourAddresses);
t.is(addresses[0]?.Address2, "APT 2");
t.is(addresses[1]?.Address2, "UNIT 2");
t.is(addresses[2]?.Address2, "BLDG 2");
t.is(addresses[3]?.Address2, "FL 2");
});

test("Multiple address verify should handle proper case the same as single verify.", async (t) => {
const uspsCase = new USPS({
properCase: true,
userId: process.env["USPS_ID"]!,
});
const addresses = await uspsCase.verifyMultiple(moreAddresses);
t.is(addresses[0]?.Address1, "11205 SE 233rd Pl");
t.is(addresses[0]?.Address2, "Apt 4");
t.is(addresses[0]?.City, "Kent");
});

test("Multiple address verify should contain error message for any unverifiable addresses in a list.", async (t) => {
const addresses = await usps.verifyMultiple([...moreAddresses, invalidAddress]);
t.false("Error" in addresses[0]!);
t.false("Error" in addresses[1]!);
t.is(addresses[2]?.Error?.Description, "Multiple addresses were found for the information you entered, and no default exists.");
});
1 change: 0 additions & 1 deletion test/validator-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable sonarjs/no-duplicate-string */

import test from "ava";

import USPS from "../src/usps.js";
Expand Down

0 comments on commit c4e9335

Please sign in to comment.