currencyapi-node 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +13 -0
- package/.github/workflows/tests.yml +29 -0
- package/CHANGELOG.md +20 -0
- package/Dockerfile +11 -0
- package/LICENSE +21 -0
- package/Makefile +26 -0
- package/README.md +17 -2
- package/package.json +19 -3
- package/run.js +26 -0
- package/src/classes/Endpoint.js +7 -16
- package/tests/convert.test.js +113 -0
- package/tests/currencies.test.js +80 -0
- package/tests/currencyapi.test.js +28 -0
- package/tests/endpoint.test.js +31 -0
- package/tests/history.test.js +100 -0
- package/tests/rates.test.js +103 -0
- package/tests/timeframe.test.js +112 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Running Code Coverage
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
node-version: [16.x, 18.x, 20.x, 22.x, 24.x]
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Node.js ${{ matrix.node-version }}
|
|
18
|
+
uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: ${{ matrix.node-version }}
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm install
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: npm run test
|
|
27
|
+
|
|
28
|
+
- name: Upload coverage to Coveralls
|
|
29
|
+
uses: coverallsapp/github-action@v2
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.2.0] - 2026-02-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Node.js v20, v22, and v24 support
|
|
9
|
+
- `engines` field in package.json specifying minimum Node.js version
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Dockerfile updated from Node 22 to Node 24
|
|
13
|
+
- CI matrix updated to test against Node.js 16, 18, 20, 22, and 24
|
|
14
|
+
- Updated GitHub Actions to latest versions (checkout@v4, setup-node@v4)
|
|
15
|
+
- Minimum supported Node.js version updated from v8 to v16
|
|
16
|
+
- README updated to reflect current Node.js compatibility
|
|
17
|
+
|
|
18
|
+
## [1.1.1] - Previous release
|
|
19
|
+
|
|
20
|
+
- Initial tracked version
|
package/Dockerfile
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Oliver Girling
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Makefile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.DEFAULT_GOAL := help
|
|
2
|
+
.PHONY: help
|
|
3
|
+
LOCAL_DOCKER_IMAGE=houseofapis/currencyapi-node
|
|
4
|
+
CONTAINER_NAME=currencyapi-node-sdk
|
|
5
|
+
WORKING_DIR=/application
|
|
6
|
+
PORT=7003
|
|
7
|
+
DOCKER_COMMAND=docker run --rm -v ${PWD}:${WORKING_DIR} -w ${WORKING_DIR} --name ${CONTAINER_NAME} -p ${PORT}:${PORT} ${LOCAL_DOCKER_IMAGE}
|
|
8
|
+
DOCKER_COMMAND_INTERACTIVE=docker run --rm -v ${PWD}:${WORKING_DIR} -w ${WORKING_DIR} --name ${CONTAINER_NAME} -p ${PORT}:${PORT} -it ${LOCAL_DOCKER_IMAGE}
|
|
9
|
+
|
|
10
|
+
build: ## Build docker image
|
|
11
|
+
docker build -t ${LOCAL_DOCKER_IMAGE} . --no-cache
|
|
12
|
+
|
|
13
|
+
test: ## Run the tests
|
|
14
|
+
${DOCKER_COMMAND} npm test
|
|
15
|
+
|
|
16
|
+
install: ## Npm install
|
|
17
|
+
${DOCKER_COMMAND} npm i
|
|
18
|
+
|
|
19
|
+
run: ## Run test file
|
|
20
|
+
${DOCKER_COMMAND_INTERACTIVE} node run.js
|
|
21
|
+
|
|
22
|
+
publish: ## Publish version (use: make publish OTP=123456 if 2FA enabled)
|
|
23
|
+
docker run --rm -v ${PWD}:${WORKING_DIR} -v ${HOME}/.npmrc:/home/node/.npmrc:ro -w ${WORKING_DIR} --name ${CONTAINER_NAME} ${LOCAL_DOCKER_IMAGE} npm publish $(if ${OTP},--otp=${OTP})
|
|
24
|
+
|
|
25
|
+
help:
|
|
26
|
+
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# CurrencyApi NodeJs wrapper
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.com/package/currencyapi-node) [](https://coveralls.io/github/houseofapis/currencyapi-node?branch=master)
|
|
5
|
+
|
|
6
|
+
|
|
3
7
|
<a href="https://currencyapi.net" title="CurrencyApi">CurrencyApi.net</a> provides live currency rates via a REST API. A live currency feed for over 152 currencies, including physical (USD, GBP, EUR + more) and cryptos (Bitcoin, Litecoin, Ethereum + more). A JSON and XML currency api updated every 60 seconds.
|
|
4
8
|
|
|
5
9
|
Features:
|
|
@@ -13,15 +17,26 @@ Features:
|
|
|
13
17
|
|
|
14
18
|
Signup for a free or paid account <a href="https://currencyapi.net/#pricing-sec" title="currency-api-pricing">here</a>.
|
|
15
19
|
|
|
16
|
-
## This package
|
|
20
|
+
## This package is a:
|
|
17
21
|
|
|
18
22
|
NodeJs wrapper for <a href="https://currencyapi.net" title="CurrencyApi">CurrencyApi.net</a> endpoints.
|
|
19
23
|
|
|
24
|
+
## Developer Guide
|
|
25
|
+
|
|
26
|
+
For an easy to following developer guide, check out our [NodeJs Developer Guide](https://currencyapi.net/sdk/nodejs).
|
|
27
|
+
|
|
28
|
+
Alternatively keep reading below.
|
|
29
|
+
|
|
20
30
|
#### Prerequisites
|
|
21
31
|
|
|
22
|
-
- Minimum NodeJs
|
|
32
|
+
- Minimum NodeJs v16 (npm v7 and above)
|
|
33
|
+
- Tested on NodeJs v16, v18, v20, v22, v24
|
|
23
34
|
- Free or Paid account with CurrencyApi.net
|
|
24
35
|
|
|
36
|
+
#### Test Coverage
|
|
37
|
+
|
|
38
|
+
- 100% coverage
|
|
39
|
+
|
|
25
40
|
## Installation
|
|
26
41
|
|
|
27
42
|
#### Using npm:
|
package/package.json
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "currencyapi-node",
|
|
3
3
|
"description": "Npm package for the CurrencyApi.net JSON & XML live currency feed",
|
|
4
|
-
"keywords": [
|
|
4
|
+
"keywords": [
|
|
5
|
+
"currency",
|
|
6
|
+
"feed",
|
|
7
|
+
"api",
|
|
8
|
+
"live-rates",
|
|
9
|
+
"json currency",
|
|
10
|
+
"crypto"
|
|
11
|
+
],
|
|
5
12
|
"homepage": "https://currencyapi.net",
|
|
6
13
|
"authors": [
|
|
7
14
|
{
|
|
@@ -11,8 +18,17 @@
|
|
|
11
18
|
"role": "Developer"
|
|
12
19
|
}
|
|
13
20
|
],
|
|
14
|
-
"version": "1.
|
|
21
|
+
"version": "1.2.0",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=16.0.0"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "jest --coverage --collectCoverageFrom='./src/**'"
|
|
27
|
+
},
|
|
15
28
|
"dependencies": {
|
|
16
|
-
"node-fetch": "^2.
|
|
29
|
+
"node-fetch": "^2.7.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"jest": "^29.7.0"
|
|
17
33
|
}
|
|
18
34
|
}
|
package/run.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// run.js
|
|
2
|
+
const CurrencyApi = require('./src/CurrencyApi');
|
|
3
|
+
|
|
4
|
+
const currency = new CurrencyApi('YOUR_API_KEY');
|
|
5
|
+
|
|
6
|
+
async function convertCurrency(amount, fromCurrency, toCurrency) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await currency.convert()
|
|
9
|
+
.from(fromCurrency)
|
|
10
|
+
.to(toCurrency)
|
|
11
|
+
.amount(amount)
|
|
12
|
+
.get();
|
|
13
|
+
return result.conversion.result;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
throw new Error(`Conversion failed: ${error.message}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
(async () => {
|
|
20
|
+
try {
|
|
21
|
+
const converted = await convertCurrency(100, 'BTC', 'USD');
|
|
22
|
+
console.log(`100 BTC is equal to ${converted} USD`);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(error);
|
|
25
|
+
}
|
|
26
|
+
})();
|
package/src/classes/Endpoint.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const fetch = require("node-fetch");
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Default output format
|
|
@@ -21,18 +21,6 @@ const API_VERSION = 'v1';
|
|
|
21
21
|
*/
|
|
22
22
|
const DEFAULT_BASE = 'USD';
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Version of the application
|
|
26
|
-
* @type {string}
|
|
27
|
-
*/
|
|
28
|
-
const APPLICATION_VERSION = '1.0.0'
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Application name sent as user-agent
|
|
32
|
-
* @type {string}
|
|
33
|
-
*/
|
|
34
|
-
const APPLICATION = 'CurrencyApi_npm_' + APPLICATION_VERSION
|
|
35
|
-
|
|
36
24
|
/**
|
|
37
25
|
* Build up the URL based on the endpoint and params
|
|
38
26
|
*
|
|
@@ -41,7 +29,7 @@ const APPLICATION = 'CurrencyApi_npm_' + APPLICATION_VERSION
|
|
|
41
29
|
* @param {Object} params
|
|
42
30
|
* @returns {string}
|
|
43
31
|
*/
|
|
44
|
-
const buildUrl = (endpoint, key, params
|
|
32
|
+
const buildUrl = (endpoint, key, params) => {
|
|
45
33
|
let ret = [];
|
|
46
34
|
for (let param in params) {
|
|
47
35
|
ret.push(encodeURIComponent(param) + '=' + encodeURIComponent(params[param]));
|
|
@@ -87,9 +75,12 @@ class Endpoint {
|
|
|
87
75
|
* @returns {Promise<*>}
|
|
88
76
|
*/
|
|
89
77
|
async get() {
|
|
90
|
-
const headers = {'application': APPLICATION, 'user-agent': APPLICATION}
|
|
91
|
-
const response = await client(buildUrl(this.endpoint, this.key, this.getParams()), {headers: headers})
|
|
92
78
|
const isXml = this.getParams().output === 'XML'
|
|
79
|
+
let headers = {
|
|
80
|
+
'X-Sdk': 'node'
|
|
81
|
+
}
|
|
82
|
+
headers['Content-Type'] = isXml ? 'application/xml' : 'application/json'
|
|
83
|
+
const response = await fetch(buildUrl(this.endpoint, this.key, this.getParams()), {headers: headers})
|
|
93
84
|
return isXml ? await response.text() : await response.json()
|
|
94
85
|
}
|
|
95
86
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
jest.mock("node-fetch")
|
|
2
|
+
const fetch = require("node-fetch")
|
|
3
|
+
const Convert = require('./../src/classes/Convert')
|
|
4
|
+
|
|
5
|
+
let convert
|
|
6
|
+
let invalidKey = 'invalidKey'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
convert = new Convert(invalidKey)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe("Setting Convert", () => {
|
|
13
|
+
|
|
14
|
+
test('Constructor setting params correctly', () => {
|
|
15
|
+
expect(convert.key).toBe(invalidKey)
|
|
16
|
+
expect(convert.endpoint).toBe('convert')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Check default params have been set', () => {
|
|
20
|
+
let params = convert.getParams()
|
|
21
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('Set amount works and returns object', () => {
|
|
25
|
+
let expectedAmount = 100
|
|
26
|
+
const setAmount = convert.amount(expectedAmount)
|
|
27
|
+
let params = convert.getParams()
|
|
28
|
+
expect(params).toHaveProperty('amount', expectedAmount)
|
|
29
|
+
expect(setAmount).toBeInstanceOf(Convert)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('Set to works and returns object', () => {
|
|
33
|
+
let expectedTo = 'gBp'
|
|
34
|
+
const setTo = convert.to(expectedTo)
|
|
35
|
+
let params = convert.getParams()
|
|
36
|
+
expect(params).toHaveProperty('to', 'GBP')
|
|
37
|
+
expect(setTo).toBeInstanceOf(Convert)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('Set from works and returns object', () => {
|
|
41
|
+
let expectedFrom = 'BTc'
|
|
42
|
+
const setFrom = convert.from(expectedFrom)
|
|
43
|
+
let params = convert.getParams()
|
|
44
|
+
expect(params).toHaveProperty('from', 'BTC')
|
|
45
|
+
expect(setFrom).toBeInstanceOf(Convert)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('Set output works and returns object', () => {
|
|
49
|
+
let expectedOutput = 'XML'
|
|
50
|
+
const setBase = convert.output('xMl')
|
|
51
|
+
let params = convert.getParams()
|
|
52
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
53
|
+
expect(setBase).toBeInstanceOf(Convert)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe("Fetching convert works as expected", () => {
|
|
58
|
+
|
|
59
|
+
test("fetch json working as expected", async () => {
|
|
60
|
+
|
|
61
|
+
const mockData = {}
|
|
62
|
+
fetch.mockReturnValue(
|
|
63
|
+
Promise.resolve({
|
|
64
|
+
json: () =>
|
|
65
|
+
Promise.resolve(mockData)
|
|
66
|
+
})
|
|
67
|
+
)
|
|
68
|
+
convert.amount(10)
|
|
69
|
+
convert.from('GbP')
|
|
70
|
+
convert.to('UsD')
|
|
71
|
+
const response = await convert.get();
|
|
72
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/convert?key=invalidKey&output=JSON&amount=10&from=GBP&to=USD'
|
|
73
|
+
|
|
74
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
"X-Sdk": "node"
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
expect(expectedUrl).toContain('output=JSON')
|
|
81
|
+
expect(expectedUrl).toContain('amount=10')
|
|
82
|
+
expect(expectedUrl).toContain('from=GBP')
|
|
83
|
+
expect(expectedUrl).toContain('to=USD')
|
|
84
|
+
expect(response).toEqual(mockData)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test("fetch xml working as expected", async () => {
|
|
88
|
+
|
|
89
|
+
const mockData = ''
|
|
90
|
+
|
|
91
|
+
fetch.mockReturnValue(
|
|
92
|
+
Promise.resolve({
|
|
93
|
+
text: () =>
|
|
94
|
+
Promise.resolve(mockData)
|
|
95
|
+
})
|
|
96
|
+
)
|
|
97
|
+
convert.output('XmL')
|
|
98
|
+
convert.amount(10)
|
|
99
|
+
convert.from('GbP')
|
|
100
|
+
convert.to('UsD')
|
|
101
|
+
const response = await convert.get()
|
|
102
|
+
|
|
103
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/convert?key=invalidKey&output=XML&amount=10&from=GBP&to=USD'
|
|
104
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
105
|
+
headers: {
|
|
106
|
+
"Content-Type": "application/xml",
|
|
107
|
+
"X-Sdk": "node"
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
expect(response).toEqual(mockData);
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
jest.mock("node-fetch")
|
|
2
|
+
const fetch = require("node-fetch")
|
|
3
|
+
const Currencies = require('./../src/classes/Currencies')
|
|
4
|
+
|
|
5
|
+
let currencies
|
|
6
|
+
let invalidKey = 'invalidKey'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
currencies = new Currencies(invalidKey)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe("Setting Convert", () => {
|
|
13
|
+
|
|
14
|
+
test('Constructor setting params correctly', () => {
|
|
15
|
+
expect(currencies.key).toBe(invalidKey)
|
|
16
|
+
expect(currencies.endpoint).toBe('currencies')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Check default params have been set', () => {
|
|
20
|
+
let params = currencies.getParams()
|
|
21
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('Set output works and returns object', () => {
|
|
25
|
+
let expectedOutput = 'XML'
|
|
26
|
+
const setBase = currencies.output('xMl')
|
|
27
|
+
let params = currencies.getParams()
|
|
28
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
29
|
+
expect(setBase).toBeInstanceOf(Currencies)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe("Fetching currencies works as expected", () => {
|
|
34
|
+
|
|
35
|
+
test("fetch json working as expected", async () => {
|
|
36
|
+
|
|
37
|
+
const mockData = {}
|
|
38
|
+
fetch.mockReturnValue(
|
|
39
|
+
Promise.resolve({
|
|
40
|
+
json: () =>
|
|
41
|
+
Promise.resolve(mockData)
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
const response = await currencies.get();
|
|
45
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/currencies?key=invalidKey&output=JSON'
|
|
46
|
+
|
|
47
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
48
|
+
headers: {
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
"X-Sdk": "node"
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
expect(expectedUrl).toContain('output=JSON')
|
|
54
|
+
expect(response).toEqual(mockData)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test("fetch xml working as expected", async () => {
|
|
58
|
+
|
|
59
|
+
const mockData = ''
|
|
60
|
+
|
|
61
|
+
fetch.mockReturnValue(
|
|
62
|
+
Promise.resolve({
|
|
63
|
+
text: () =>
|
|
64
|
+
Promise.resolve(mockData)
|
|
65
|
+
})
|
|
66
|
+
)
|
|
67
|
+
currencies.output('XmL')
|
|
68
|
+
const response = await currencies.get()
|
|
69
|
+
|
|
70
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/currencies?key=invalidKey&output=XML'
|
|
71
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/xml",
|
|
74
|
+
"X-Sdk": "node"
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
expect(response).toEqual(mockData);
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const CurrencyApi = require('./../src/CurrencyApi')
|
|
2
|
+
const Rates = require('./../src/classes/Rates')
|
|
3
|
+
const History = require('./../src/classes/History')
|
|
4
|
+
const Timeframe = require('./../src/classes/Timeframe')
|
|
5
|
+
const Convert = require('./../src/classes/Convert')
|
|
6
|
+
const Currencies = require('./../src/classes/Currencies')
|
|
7
|
+
|
|
8
|
+
let currencyApi
|
|
9
|
+
let invalidKey = 'invalidKey'
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
currencyApi = new CurrencyApi(invalidKey)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
describe("Setting CurrencyApi", () => {
|
|
16
|
+
|
|
17
|
+
test('Constructor setting params correctly', () => {
|
|
18
|
+
expect(currencyApi.key).toBe(invalidKey);
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('Each CurrencyApi method is returning the relevant class', () => {
|
|
22
|
+
expect(currencyApi.rates()).toBeInstanceOf(Rates);
|
|
23
|
+
expect(currencyApi.history()).toBeInstanceOf(History);
|
|
24
|
+
expect(currencyApi.timeframe()).toBeInstanceOf(Timeframe);
|
|
25
|
+
expect(currencyApi.convert()).toBeInstanceOf(Convert);
|
|
26
|
+
expect(currencyApi.currencies()).toBeInstanceOf(Currencies);
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const Endpoint = require('./../src/classes/Endpoint')
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let endpoint
|
|
5
|
+
let invalidKey = 'invalidKey'
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
endpoint = new Endpoint(invalidKey,'endpoint')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe("Setting Endpoint", () => {
|
|
12
|
+
|
|
13
|
+
test('Constructor setting params correctly', () => {
|
|
14
|
+
expect(endpoint.key).toBe(invalidKey)
|
|
15
|
+
expect(endpoint.endpoint).toBe('endpoint');
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('Check default params have been set', () => {
|
|
19
|
+
let params = endpoint.getParams()
|
|
20
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('Set output works and returns object', () => {
|
|
24
|
+
let expectedOutput = 'XML'
|
|
25
|
+
const setBase = endpoint.output('xMl')
|
|
26
|
+
let params = endpoint.getParams()
|
|
27
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
28
|
+
expect(setBase).toBeInstanceOf(Endpoint)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
})
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
jest.mock("node-fetch")
|
|
2
|
+
const fetch = require("node-fetch")
|
|
3
|
+
const History = require('./../src/classes/History')
|
|
4
|
+
|
|
5
|
+
let history
|
|
6
|
+
let invalidKey = 'invalidKey'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
history = new History(invalidKey)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe("Setting History", () => {
|
|
13
|
+
|
|
14
|
+
test('Constructor setting params correctly', () => {
|
|
15
|
+
expect(history.key).toBe(invalidKey)
|
|
16
|
+
expect(history.endpoint).toBe('history')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Check default params have been set', () => {
|
|
20
|
+
let params = history.getParams()
|
|
21
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('Set date works and returns object', () => {
|
|
25
|
+
let expectedDate = '2023-10-10'
|
|
26
|
+
const setDate = history.date(expectedDate)
|
|
27
|
+
let params = history.getParams()
|
|
28
|
+
expect(params).toHaveProperty('date', expectedDate)
|
|
29
|
+
expect(setDate).toBeInstanceOf(History)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('Set base works and returns object', () => {
|
|
33
|
+
let expectedBase = 'GBP'
|
|
34
|
+
const setBase = history.base('gBp')
|
|
35
|
+
let params = history.getParams()
|
|
36
|
+
expect(params).toHaveProperty('base', expectedBase)
|
|
37
|
+
expect(setBase).toBeInstanceOf(History)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('Set output works and returns object', () => {
|
|
41
|
+
let expectedOutput = 'XML'
|
|
42
|
+
const setBase = history.output('xMl')
|
|
43
|
+
let params = history.getParams()
|
|
44
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
45
|
+
expect(setBase).toBeInstanceOf(History)
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe("Fetching history works as expected", () => {
|
|
50
|
+
|
|
51
|
+
test("fetch json working as expected", async () => {
|
|
52
|
+
|
|
53
|
+
const mockData = {}
|
|
54
|
+
fetch.mockReturnValue(
|
|
55
|
+
Promise.resolve({
|
|
56
|
+
json: () =>
|
|
57
|
+
Promise.resolve(mockData)
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
history.date('2023-01-02')
|
|
61
|
+
const response = await history.get();
|
|
62
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/history?key=invalidKey&output=JSON&base=USD&date=2023-01-02'
|
|
63
|
+
|
|
64
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
"X-Sdk": "node"
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
expect(expectedUrl).toContain('date=2023-01-02')
|
|
71
|
+
expect(response).toEqual(mockData)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test("fetch xml working as expected", async () => {
|
|
75
|
+
|
|
76
|
+
const mockData = ''
|
|
77
|
+
|
|
78
|
+
fetch.mockReturnValue(
|
|
79
|
+
Promise.resolve({
|
|
80
|
+
text: () =>
|
|
81
|
+
Promise.resolve(mockData)
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
history.output('xmL')
|
|
85
|
+
history.date('2023-01-02')
|
|
86
|
+
history.base('GbP')
|
|
87
|
+
const response = await history.get();
|
|
88
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/history?key=invalidKey&output=XML&base=GBP&date=2023-01-02'
|
|
89
|
+
|
|
90
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
91
|
+
headers: {
|
|
92
|
+
"Content-Type": "application/xml",
|
|
93
|
+
"X-Sdk": "node"
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
expect(expectedUrl).toContain('date=2023-01-02')
|
|
97
|
+
expect(response).toEqual(mockData);
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
jest.mock("node-fetch")
|
|
2
|
+
const fetch = require("node-fetch")
|
|
3
|
+
const Rates = require('./../src/classes/Rates')
|
|
4
|
+
|
|
5
|
+
let rates
|
|
6
|
+
let invalidKey = 'invalidKey'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
rates = new Rates(invalidKey)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe("Setting Rates", () => {
|
|
13
|
+
|
|
14
|
+
test('Constructor setting params correctly', () => {
|
|
15
|
+
expect(rates.key).toBe(invalidKey)
|
|
16
|
+
expect(rates.endpoint).toBe('rates')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Check default params have been set', () => {
|
|
20
|
+
let params = rates.getParams()
|
|
21
|
+
expect(params).toHaveProperty('base', 'USD')
|
|
22
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('Set base works and returns object', () => {
|
|
26
|
+
let expectedBase = 'GBP'
|
|
27
|
+
const setBase = rates.base('gBp')
|
|
28
|
+
let params = rates.getParams()
|
|
29
|
+
expect(params).toHaveProperty('base', expectedBase)
|
|
30
|
+
expect(setBase).toBeInstanceOf(Rates)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('Set output works and returns object', () => {
|
|
34
|
+
let expectedOutput = 'XML'
|
|
35
|
+
const setBase = rates.output('xMl')
|
|
36
|
+
let params = rates.getParams()
|
|
37
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
38
|
+
expect(setBase).toBeInstanceOf(Rates)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe("Fetching rates works as expected", () => {
|
|
45
|
+
|
|
46
|
+
test("fetch json working as expected", async () => {
|
|
47
|
+
|
|
48
|
+
const mockData = {
|
|
49
|
+
"valid": true,
|
|
50
|
+
"updated": 1695542403,
|
|
51
|
+
"base": "USD",
|
|
52
|
+
"rates": {
|
|
53
|
+
"AED": 3.673,
|
|
54
|
+
"AFN": 78.58716,
|
|
55
|
+
"ALL": 99.73298,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
fetch.mockReturnValue(
|
|
59
|
+
Promise.resolve({
|
|
60
|
+
json: () =>
|
|
61
|
+
Promise.resolve(mockData)
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
const response = await rates.get();
|
|
65
|
+
expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v1/rates?key=invalidKey&output=JSON&base=USD", {
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
"X-Sdk": "node"
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
expect(response).toEqual(mockData);
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test("fetch xml working as expected", async () => {
|
|
75
|
+
|
|
76
|
+
const mockData = `<?xml version='1.0' encoding='utf-8'?>
|
|
77
|
+
<root>
|
|
78
|
+
<valid></valid>
|
|
79
|
+
<error>
|
|
80
|
+
<code>401</code>
|
|
81
|
+
<message>Your API key is not valid</message>
|
|
82
|
+
</error>
|
|
83
|
+
</root>`
|
|
84
|
+
|
|
85
|
+
fetch.mockReturnValue(
|
|
86
|
+
Promise.resolve({
|
|
87
|
+
text: () =>
|
|
88
|
+
Promise.resolve(mockData)
|
|
89
|
+
})
|
|
90
|
+
)
|
|
91
|
+
rates.output('XmL')
|
|
92
|
+
const response = await rates.get()
|
|
93
|
+
|
|
94
|
+
expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v1/rates?key=invalidKey&output=XML&base=USD", {
|
|
95
|
+
headers: {
|
|
96
|
+
"Content-Type": "application/xml",
|
|
97
|
+
"X-Sdk": "node"
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
expect(response).toEqual(mockData);
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
jest.mock("node-fetch")
|
|
2
|
+
const fetch = require("node-fetch")
|
|
3
|
+
const Timeframe = require('./../src/classes/Timeframe')
|
|
4
|
+
|
|
5
|
+
let timeframe
|
|
6
|
+
let invalidKey = 'invalidKey'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
timeframe = new Timeframe(invalidKey)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
describe("Setting Timeframe", () => {
|
|
14
|
+
|
|
15
|
+
test('Constructor setting params correctly', () => {
|
|
16
|
+
expect(timeframe.key).toBe(invalidKey)
|
|
17
|
+
expect(timeframe.endpoint).toBe('timeframe')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('Check default params have been set', () => {
|
|
21
|
+
let params = timeframe.getParams()
|
|
22
|
+
expect(params).toHaveProperty('output', 'JSON')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('Set base works and returns object', () => {
|
|
26
|
+
let expectedBase = 'GBP'
|
|
27
|
+
const setBase = timeframe.base('gBp')
|
|
28
|
+
let params = timeframe.getParams()
|
|
29
|
+
expect(params).toHaveProperty('base', expectedBase)
|
|
30
|
+
expect(setBase).toBeInstanceOf(Timeframe)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('Set start date works and returns object', () => {
|
|
34
|
+
let expectedStart = '2023-01-02'
|
|
35
|
+
const setStart = timeframe.startDate(expectedStart)
|
|
36
|
+
let params = timeframe.getParams()
|
|
37
|
+
expect(params).toHaveProperty('start_date', expectedStart)
|
|
38
|
+
expect(setStart).toBeInstanceOf(Timeframe)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('Set end date works and returns object', () => {
|
|
42
|
+
let expectedEnd = '2023-01-06'
|
|
43
|
+
const setEnd = timeframe.endDate(expectedEnd)
|
|
44
|
+
let params = timeframe.getParams()
|
|
45
|
+
expect(params).toHaveProperty('end_date', expectedEnd)
|
|
46
|
+
expect(setEnd).toBeInstanceOf(Timeframe)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('Set output works and returns object', () => {
|
|
50
|
+
let expectedOutput = 'XML'
|
|
51
|
+
const setBase = timeframe.output('xMl')
|
|
52
|
+
let params = timeframe.getParams()
|
|
53
|
+
expect(params).toHaveProperty('output', expectedOutput)
|
|
54
|
+
expect(setBase).toBeInstanceOf(Timeframe)
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe("Fetching timeframe works as expected", () => {
|
|
59
|
+
|
|
60
|
+
test("fetch json working as expected", async () => {
|
|
61
|
+
|
|
62
|
+
const mockData = {}
|
|
63
|
+
fetch.mockReturnValue(
|
|
64
|
+
Promise.resolve({
|
|
65
|
+
json: () =>
|
|
66
|
+
Promise.resolve(mockData)
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
timeframe.startDate('2023-01-02')
|
|
70
|
+
timeframe.endDate('2023-01-03')
|
|
71
|
+
const response = await timeframe.get();
|
|
72
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/timeframe?key=invalidKey&output=JSON&base=USD&start_date=2023-01-02&end_date=2023-01-03'
|
|
73
|
+
|
|
74
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
"X-Sdk": "node"
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
expect(expectedUrl).toContain('start_date=2023-01-02')
|
|
81
|
+
expect(expectedUrl).toContain('end_date=2023-01-03')
|
|
82
|
+
expect(response).toEqual(mockData)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test("fetch xml working as expected", async () => {
|
|
86
|
+
|
|
87
|
+
const mockData = ''
|
|
88
|
+
|
|
89
|
+
fetch.mockReturnValue(
|
|
90
|
+
Promise.resolve({
|
|
91
|
+
text: () =>
|
|
92
|
+
Promise.resolve(mockData)
|
|
93
|
+
})
|
|
94
|
+
)
|
|
95
|
+
timeframe.output('xMl')
|
|
96
|
+
timeframe.startDate('2023-01-02')
|
|
97
|
+
timeframe.endDate('2023-01-03')
|
|
98
|
+
const response = await timeframe.get();
|
|
99
|
+
const expectedUrl = 'https://currencyapi.net/api/v1/timeframe?key=invalidKey&output=XML&base=USD&start_date=2023-01-02&end_date=2023-01-03'
|
|
100
|
+
|
|
101
|
+
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
|
|
102
|
+
headers: {
|
|
103
|
+
"Content-Type": "application/xml",
|
|
104
|
+
"X-Sdk": "node"
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
expect(expectedUrl).toContain('start_date=2023-01-02')
|
|
108
|
+
expect(expectedUrl).toContain('end_date=2023-01-03')
|
|
109
|
+
expect(response).toEqual(mockData);
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
})
|