Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
{
"extends": "eslint-config-lob",
"parserOptions": {
"ecmaVersion": 2017
},
"globals": {
"API_KEY": false,
"expect": false,
"Lob": false
"HAS_LIVE_KEY": false,
"INTEGRATION_TIMEOUT": false,
"LiveLob": false,
"Lob": false,
"mocks": false
}
}
42 changes: 20 additions & 22 deletions .github/workflows/forked_run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,30 @@ name: Run Tests
on:
pull_request_target:
types: [labeled]

jobs:
node_tests:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.labels.*.name, 'Approved')
strategy:
matrix:
node: ['12', '14']
node: [20, 22]
steps:
- uses: actions/checkout@v2
- name: Setup
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- name: Create NYC folder
run: mkdir .nyc_output
- name: Install Dependencies
run: npm install
- name: Run tests
env:
LOB_API_KEY: ${{ secrets.API_KEY }}
run: npm run test
- name: Coverage
run: npm run test-lcov
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage/lcov.info
- uses: actions/checkout@v2
- name: Setup
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- name: Create NYC folder
run: mkdir .nyc_output
- name: Install Dependencies
run: npm install --legacy-peer-deps
- name: Run tests
run: npm run test
- name: Coverage
run: npm run test-lcov
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage/lcov.info
11 changes: 8 additions & 3 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Run Tests

on: [pull_request]
on: [push, pull_request]

jobs:
node_tests:
Expand All @@ -19,12 +19,17 @@ jobs:
- name: Install Dependencies
run: npm install --legacy-peer-deps
- name: Run tests
env:
LOB_API_KEY: ${{ secrets.API_KEY }}
run: npm run test
- name: Run integration tests
env:
TEST_API_KEY: ${{ secrets.TEST_API_KEY }}
LIVE_API_KEY: ${{ secrets.LIVE_API_KEY }}
run: npm run test:integration
- name: Coverage
if: matrix.node == 20
run: npm run test-lcov
- name: Coveralls
if: matrix.node == 20
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ coverage
*.sublime-*
.idea/
.vscode
.env
6 changes: 6 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recursive": true,
"timeout": 30000,
"require": ["./test/setup.js"],
"ignore": ["test/integration/**"]
}
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
## 7.1.0 (2026-01-15)

##### Security

* Replace deprecated `request` package with `axios` and `form-data` to address critical vulnerability (CVE-2023-28155)
* Add path traversal protection with URI encoding in resource methods

##### Bug Fixes

* Fix bulk verification endpoints (US and International) to send JSON body format instead of form-encoded data
* Fix object iteration to use `Object.keys()` instead of `for...in` to avoid prototype chain issues

##### Testing

* Add comprehensive unit test suite with HTTP mocking using `nock` (94 tests)
* Add integration test suite for live API validation (24 tests)
* Unit tests no longer require API keys - mocked responses enable offline development
* Integration tests run separately with `npm run test:integration`

##### Maintenance

* Update README with current testing instructions
* Clean up unreachable error handling code in HTTP client

#### 7.0.1 (2025-11-12)

## 7.0.0 (2025-11-11)
Expand Down
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,22 @@ To contribute, please see the [CONTRIBUTING.md](https://github.com/lob/lob-node/

## Testing

To run the tests with coverage:
To run unit tests with coverage:

```
LOB_API_KEY=YOUR_TEST_API_KEY npm test
npm test
```

To run the tests without coverage:
To run integration tests (requires API keys):

```
LOB_API_KEY=YOUR_TEST_API_KEY npm run test-no-cover
TEST_API_KEY=your_test_key npm run test:integration
```

Some integration tests require a live API key:

```
TEST_API_KEY=your_test_key LIVE_API_KEY=your_live_key npm run test:integration
```

=======================
Expand Down
12 changes: 6 additions & 6 deletions examples/create_card.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
const fs = require('fs');

const lobFactory = require('../lib/index.js');
const Lob = new lobFactory('YOUR_API_KEY'); // Replace YOUR_API_KEY with your own API key
const lob = new lobFactory('YOUR_API_KEY'); // Replace YOUR_API_KEY with your own API key

const frontFile = fs.readFileSync(`${__dirname}/cards/card.pdf`) // Replace with your own custom PDF front
const backFile = fs.readFileSync(`${__dirname}/cards/card.pdf`) // Replace with your own custom PDF back
const frontFile = fs.readFileSync(`${__dirname}/cards/card.pdf`); // Replace with your own custom PDF front
const backFile = fs.readFileSync(`${__dirname}/cards/card.pdf`); // Replace with your own custom PDF back

Lob.cards.create({
lob.cards.create({
description: 'My Card',
front: frontFile,
back: backFile,
Expand All @@ -21,5 +21,5 @@ Lob.cards.create({
} else {
console.log('The Lob API responded with this card object: ', card);
}
});

});
12 changes: 5 additions & 7 deletions examples/create_cardOrder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@

// Create a card order for an existing card

const fs = require('fs');

const lobFactory = require('../lib/index.js');
const Lob = new lobFactory('YOUR_API_KEY'); // Replace YOUR_API_KEY with your own API key
const lob = new lobFactory('YOUR_API_KEY'); // Replace YOUR_API_KEY with your own API key

const cardId = 'YOUR_CARD_ID'; // Replace YOUR_CARD_ID with the Card ID you'd like to place an order for

Lob.cardOrders.create(cardId, {
'quantity': 10000
lob.cardOrders.create(cardId, {
quantity: 10000
}, (err, cardOrder) => {
if (err) {
console.log(err);
} else {
console.log('The Lob API responded with this cardOrder object: ', cardOrder);
}
});

});
26 changes: 13 additions & 13 deletions examples/create_check.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
*/

const lobFactory = require('../lib/index.js');
const Lob = new lobFactory('YOUR_API_KEY');
const lob = new lobFactory('YOUR_API_KEY');

// Create the address
Lob.addresses.create({
lob.addresses.create({
name: 'Test Person',
email: 'test@gmail.com',
phone: '123456789',
Expand All @@ -24,20 +24,20 @@ Lob.addresses.create({
if (err) {
return console.log(err);
}
Lob.bankAccounts.create({
lob.bankAccounts.create({
routing_number: '122100024',
account_number: '123456789',
account_type: 'company',
signatory: 'John Doe'
}, (err, bankAccount) => {
if (err) {
return console.log(err);
}, (err2, bankAccount) => {
if (err2) {
return console.log(err2);
}
Lob.bankAccounts.verify(bankAccount.id, { amounts: [23, 34] }, (err) => {
if (err) {
return console.log(err);
lob.bankAccounts.verify(bankAccount.id, { amounts: [23, 34] }, (err3) => {
if (err3) {
return console.log(err3);
}
Lob.checks.create({
lob.checks.create({
description: 'Test Check',
check_number: '10000',
bank_account: bankAccount.id,
Expand All @@ -54,9 +54,9 @@ Lob.addresses.create({
memo: 'This is my first Check',
message: 'This check is for laundry',
logo: 'https://s3-us-west-2.amazonaws.com/public.lob.com/assets/check_logo.png'
}, (err, check) => {
if (err) {
return console.log(err);
}, (err4, check) => {
if (err4) {
return console.log(err4);
}
console.log('The Lob API responded with this check object: ', check);
});
Expand Down
54 changes: 27 additions & 27 deletions examples/create_letter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
const fs = require('fs');

const lobFactory = require('../lib/index.js');
const Lob = new lobFactory('YOUR_API_KEY');
const lob = new lobFactory('YOUR_API_KEY');

const file = fs.readFileSync(`${__dirname}/html/letter.html`).toString();

// Create the address
Lob.addresses.create({
lob.addresses.create({
name: 'Robin Joseph',
email: 'test@gmail.com',
phone: '123456789',
Expand All @@ -24,29 +24,29 @@ Lob.addresses.create({
address_zip: '60012',
address_country: 'US'
})
.then((address) => {
return Lob.letters.create({
description: 'My First Letter',
to: address.id,
from: {
name: 'Test Person',
address_line1: '123 Test Street',
address_line2: 'Unit 200',
address_city: 'Chicago',
address_state: 'IL',
address_zip: '60012',
address_country: 'US'
},
file,
merge_variables: {
name: 'Robin'
},
color: false
.then((address) => {
return lob.letters.create({
description: 'My First Letter',
to: address.id,
from: {
name: 'Test Person',
address_line1: '123 Test Street',
address_line2: 'Unit 200',
address_city: 'Chicago',
address_state: 'IL',
address_zip: '60012',
address_country: 'US'
},
file,
merge_variables: {
name: 'Robin'
},
color: false
});
})
.then((letter) => {
console.log('The Lob API responded with this letter object: ', letter);
})
.catch((err) => {
console.log(err);
});
})
.then((letter) => {
console.log('The Lob API responded with this letter object: ', letter);
})
.catch((err) => {
console.log(err);
});
12 changes: 6 additions & 6 deletions examples/create_postcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
const fs = require('fs');

const lobFactory = require('../lib/index.js');
const Lob = new lobFactory('YOUR_API_KEY');
const lob = new lobFactory('YOUR_API_KEY');

const file = fs.readFileSync(`${__dirname}/html/card.html`).toString();

// Create the address
Lob.addresses.create({
lob.addresses.create({
name: 'Robin Joseph',
email: 'test@gmail.com',
phone: '123456789',
Expand All @@ -27,17 +27,17 @@ Lob.addresses.create({
if (err) {
console.log(err);
} else {
Lob.postcards.create({
lob.postcards.create({
description: 'My Second Postcard',
to: address.id,
front: file,
back: file,
merge_variables: {
name: 'Robin'
}
}, (err, postcard) => {
if (err) {
console.log(err);
}, (err2, postcard) => {
if (err2) {
console.log(err2);
} else {
console.log('The Lob API responded with this postcard object: ', postcard);
}
Expand Down
Loading