Skip to content

Commit

Permalink
add basic client tests jest & sinon
Browse files Browse the repository at this point in the history
  • Loading branch information
SerKnight committed Feb 26, 2020
1 parent dbf5e3c commit 75f510e
Show file tree
Hide file tree
Showing 16 changed files with 649 additions and 435 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
},
"overrides": [
{
"files": ["**/__tests__/**", "**/__integration_tests__/**", "**/*.test.ts"],
"files": ["**/__tests__/**", "**/__tests__/**", "**/*.test.ts"],
"env": {
"jest": true
},
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/custom-issue-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ This will help us to diagnose your issue.

Any bugs/issues with the API are best directed to: https://developer.xero.com/community

Often the best place for documentation is the integration tests in this repo. Please have a look:
Often the best place for documentation is the tests in this repo. Please have a look:

- [Integration tests](src/__integration_tests__)
- [tests](src/__tests__)
- [Sample app](https://github.com/XeroAPI/xero-node-sample-app)

Thanks
1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ docs_theme/
*.tgz
typedoc.json
scratch.ts
**/__integration_tests__/**
**/__tests__/**
*.map
docs_theme
Expand Down
89 changes: 61 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,40 @@ Follow these steps to create your Xero app

## Repo Context & Contributing
This SDK's functionality is majority generated [from our OpenAPISpec](https://github.com/XeroAPI/Xero-OpenAPI).
The exception is the `src/xeroClient.ts` which contains the javascript specific helper code that is unique to this repository only. Contributions are welcome but please keep in mind that majority of SDK is auto-generated from the OpenAPISpec. We try to get changes in that projects to be released on a bi-weekly cadence.
The exception is the `src/xeroClient.ts` which contains the typescript that is unique to this repository. Contributions are welcome but please keep in mind that majority of SDK is auto-generated from the OpenAPISpec. We try to get changes in that projects to be released on a reasonable cadence.

> Read more about our process in [maintaining our suite of SDK's](https://devblog.xero.com/building-sdks-for-the-future-b79ff726dfd6)
## Authentication

We use [OAuth2.0](https://oauth.net/2) to authenticate requests against our API
We use [OAuth2.0](https://oauth.net/2) to authenticate requests against our API. Each API call will need to have a valid token populated on the API client to succeed. In a tokenSet will be an *access_token* which lasts for 30 minutes, and a *refresh_token* which lasts for 30 days. If you don't want to require your users to re-authenticate each time you want to call the API on their behalf, you will need a datastore for these tokens and will be required to refresh the tokens at least once per 30 days to avoid expiration. The `offline_access` scope is required for refresh tokens to work.

In Xero a user can belong to multiple organisations. Tokens are ultimately associated with a Xero user, who can belong to multiple tenants/organisations. If your user 'Allows Access' to multiple organisations, be hyper aware of which `tenantId` you are passing to each function.

**Step 1:** Redirect user to xero authentication page
---

**Step 1:** Initialize the `XeroClient`, and redirect user to xero auth flow

**Step 2:** Call `apiCallback` to get your tokenSet

**Step 2:** Call `apiCallback` to populate additional tenant data and get your tokenSet
**Step 3:** Call `updateTenats` to populate additional tenant data

---

## Step 1
* Configure client and generate Authorization URL.
* Choose your [XeroAPI Scopes](https://developer.xero.com/documentation/oauth2/scopes) based on the access you want the user to allow on their behalf.
* Configure client and generate Authorization URL
* Choose [XeroAPI Scopes](https://developer.xero.com/documentation/oauth2/scopes) based on the access you need
* `initialize()` the client to set up the 'openid-client'
* Build the `consentUrl`
* Redirect to auth flow
```js
const port = process.env.PORT || 3000

const xero = new XeroClient({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
redirectUris: [`http://localhost:${port}/callback`],
scopes: 'openid profile email accounting.transactions accounting.settings offline_access'.split(" ")
scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
});

await xero.initialize();
Expand All @@ -72,14 +81,14 @@ res.redirect(consentUrl);
```

## Step 2
Call xero-node's `apiCallback` function. This will:
* Populate the XeroClients active tenant data
* Return a tokenSet which you can save in your datastore
* `tokenSet` will automatically be set on the `xero` client object to be accessed as `xero.readTokenSet()` but you can use the return value to persist and attribute it to a user/session. Helper functions explained below.
Call the `apiCallback` function with the response url which returns a tokenSet you can save in your datastore for future API calls.

*The `tokenSet` can also be accessed from the client as `xero.readTokenSet()`.*

```js
const tokenSet = await xero.apiCallback(req.url);
```
The tokenSet will contain your access_token and refresh_token and will look like this:
The `tokenSet` will contain your access_token and refresh_token as well as other information regarding your connection.
```js
{
id_token: 'eyJhxxxx.yyy',
Expand All @@ -92,16 +101,18 @@ The tokenSet will contain your access_token and refresh_token and will look like
}
```

The `apiCallback` function will also fetch additional metadata about each of your authorized organisations (aka tenants) so you can display the name, etc. In Xero a user can belong to multiple organisations. A single token could be authorized to call the API for a single user to multiple tenants - so please be hyper aware of which `tenantId` you are passing to each xero-node function, as a user could accidently authenticate to multiple orgs if they belong to many.
## Step 3 (convenience step)

Populate the XeroClient's active tenant data

For most integrations you will always want to display the org name and additional metadata about the connected org. The `/connections` endpoint does not currently serialize that data so requires developers to make additional api calls for each org that your user connects to surface that information.

The `updatedTenants` function will query & nest the additional orgData results in your xeroClient under each connection/tenant object and return the array of tenants.

So to re-iterate - after calling
```javascript
await xero.apiCallback(req.url);
```
You can then access your tenant data from the initial client instance.
```js
console.log(xero.tenants)
const tenants = await xero.updateTenants()

console.log(tenants || xero.tenants)
[
{
id: 'xxx-yyy-zzz-xxx-yyy',
Expand All @@ -112,6 +123,8 @@ console.log(xero.tenants)
orgData: {
organisationID: 'xxx-yyy-zzz-xxx-yyy',
name: 'My first org',
version: 'US',
shortCode: '!2h37s',
...
}
},
Expand All @@ -124,12 +137,31 @@ console.log(xero.tenants)
orgData: {
organisationID: 'xxx-yyy-zzz-xxx-yyy',
name: 'My second org',
version: 'AUS',
shortCode: '!yrcgp',
...
}
}
]
```

---
## Making **offline_access** calls

Once you have a valid token saved you can set the token on the client without going through the callback by calling `setTokenSet`.

For example - once a user authenticates you can refresh the token (which will also set the new token on the client) to make authorized api calls.
```js
const tokenSet = getTokenFromDatabase(userId) // example function name

await xero.setTokenSet(tokenSet)

// you can call this to fetch/set your connected tenant data on your client, or you could also store this information in a database
await xero.updateTenants()

await xero.accountingApi.getInvoices(xero.tenants[0].tenantId)
```

## Usage
> Full API documentation: https://xeroapi.github.io/xero-node/v4/
Expand All @@ -138,9 +170,9 @@ console.log(xero.tenants)
const activeTenantId = xero.tenants[0].tenantId

const getOrgs = await xero.accountingApi.getOrganisations(activeTenantId)
const getOrgs.body.organisations
const orgCountry= getOrgs.body.organisations[0].countryCode

const contactsResponse = await xero.accountingApi.getContacts(activeTenantId);
const contactsResponse = await xero.accountingApi.getContacts(activeTenantId)
const contactId = getContactsResponse.body.contacts[0].contactID

---
Expand Down Expand Up @@ -171,16 +203,16 @@ const invoices = {
]
};

const createdInvoices = await xero.accountingApi.createInvoices(activeTenantId, invoices);
const createdInvoice = await xero.accountingApi.createInvoices(activeTenantId, invoices)
```

## Sample App
For more robust examples in how to utilize our accounting api we have (roughly) every single endpoint mapped out with an example in our sample app - complete with showing the Xero data dependencies required for interaction with many objects ( ie. types, assoc. accounts, tax types, date formats).
For more robust examples in how to utilize our accounting api we have *(roughly)* every single endpoint mapped out with an example in our sample app - complete with showing the Xero data dependencies required for interaction with many objects ( ie. types, assoc. accounts, tax types, date formats).

Just visit the repo https://github.com/XeroAPI/xero-node-oauth2-app configure your credentials & get started exploring.
Just visit the repo https://github.com/XeroAPI/xero-node-oauth2-app configure your credentials & get started.

### Other Helper functions
```javascript
```js
// xero.tenants
xero.tenants

Expand All @@ -196,7 +228,7 @@ if (tokenSet.expired()) {
}

// refreshToken()
await xero.refreshToken()
const validTokenSet = await xero.refreshToken()

// refreshTokenUsingTokenSet()
await xero.refreshTokenUsingTokenSet(tokenSet)
Expand All @@ -210,6 +242,7 @@ await xero.readIdTokenClaims()
// readTokenSet()
await xero.readTokenSet()

// setTokenSet()
await xero.setTokenSet()
// setTokenSet(tokenSet)
const tokenSet = await xero.readTokenSet()
await xero.setTokenSet(tokenSet)
```
Loading

0 comments on commit 75f510e

Please sign in to comment.