-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a checkout adapter that supports persistence
- Loading branch information
Mina Smart
committed
Feb 19, 2016
1 parent
9cc9a16
commit 43b1aa9
Showing
2 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import ajax from 'buy-button-sdk/ajax'; | ||
import CoreObject from 'buy-button-sdk/metal/core-object'; | ||
|
||
const CheckoutAdapter = CoreObject.extend({ | ||
ajax, | ||
|
||
constructor(config) { | ||
this.config = config; | ||
}, | ||
|
||
get base64ApiKey() { | ||
return btoa(this.config.apiKey); | ||
}, | ||
|
||
get baseUrl() { | ||
const { myShopifyDomain } = this.config; | ||
|
||
return `https://${myShopifyDomain}.myshopify.com/anywhere`; | ||
}, | ||
|
||
get headers() { | ||
return { | ||
Authorization: `Basic ${this.base64ApiKey}` | ||
}; | ||
}, | ||
|
||
idKeyForType() { | ||
return 'token'; | ||
}, | ||
|
||
pathForType(type) { | ||
return `/${type}`; | ||
}, | ||
|
||
buildUrl(singleOrMultiple, type, idOrQuery) { | ||
switch (singleOrMultiple) { | ||
case 'multiple': | ||
return this.buildMultipleUrl(type, idOrQuery); | ||
case 'single': | ||
return this.buildSingleUrl(type, idOrQuery); | ||
default: | ||
return ''; | ||
} | ||
}, | ||
|
||
buildMultipleUrl(type, query = {}) { | ||
const url = `${this.baseUrl}${this.pathForType(type)}.json`; | ||
const paramNames = Object.keys(query); | ||
|
||
if (paramNames.length > 0) { | ||
throw new Error('Querying checkouts is not allowed'); | ||
} | ||
|
||
return url; | ||
}, | ||
|
||
buildSingleUrl(type, id) { | ||
return `${this.baseUrl}${this.pathForType(type)}/${id}.json`; | ||
}, | ||
|
||
fetchSingle(/* type, id */) { | ||
const url = this.buildUrl('single', ...arguments); | ||
|
||
return this.ajax('get', url, { headers: this.headers }).then(response => { | ||
return response.json; | ||
}); | ||
}, | ||
|
||
create(type, payload) { | ||
const url = this.buildUrl('multiple', type); | ||
|
||
return this.ajax('post', url, { headers: this.headers, body: JSON.stringify(payload) }).then(response => { | ||
return response.json; | ||
}); | ||
}, | ||
|
||
update(type, id, payload) { | ||
const url = this.buildUrl('single', type, id); | ||
|
||
return this.ajax('patch', url, { headers: this.headers, body: JSON.stringify(payload) }).then(response => { | ||
return response.json; | ||
}); | ||
} | ||
}); | ||
|
||
export default CheckoutAdapter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import { module, test } from 'qunit'; | ||
import CheckoutAdapter from 'buy-button-sdk/adapters/checkout-adapter'; | ||
import assign from 'buy-button-sdk/metal/assign'; | ||
import Promise from 'promise'; | ||
|
||
let adapter; | ||
|
||
const myShopifyDomain = 'buckets-o-stuff'; | ||
const baseUrl = `https://${myShopifyDomain}.myshopify.com/anywhere`; | ||
const apiKey = 'abc123def456ghi'; | ||
const base64ApiKey = btoa(apiKey); | ||
|
||
function resolvingPromise(data = {}) { | ||
return new Promise(function (resolve) { | ||
resolve(data); | ||
}); | ||
} | ||
|
||
module('Unit | CheckoutAdapter', { | ||
setup() { | ||
adapter = new CheckoutAdapter(); | ||
}, | ||
teardown() { | ||
adapter = null; | ||
} | ||
}); | ||
|
||
test('it builds an appropriate baseUrl based on configured values', function (assert) { | ||
assert.expect(1); | ||
|
||
adapter.config = { myShopifyDomain }; | ||
|
||
assert.equal(adapter.baseUrl, baseUrl); | ||
}); | ||
|
||
test('it builds auth headers using the base64 encoded api key', function (assert) { | ||
assert.expect(1); | ||
|
||
adapter.config = { apiKey }; | ||
|
||
assert.deepEqual(adapter.headers, { | ||
Authorization: `Basic ${base64ApiKey}` | ||
}); | ||
}); | ||
|
||
test('it builds the url for all checkouts (used on #create)', function (assert) { | ||
assert.expect(1); | ||
|
||
adapter.config = { myShopifyDomain }; | ||
|
||
assert.equal(adapter.buildUrl('multiple', 'checkouts'), `${baseUrl}/checkouts.json`); | ||
}); | ||
|
||
test('it builds the url for a single checkout', function (assert) { | ||
assert.expect(1); | ||
|
||
const token = 'abc123'; | ||
|
||
adapter.config = { myShopifyDomain }; | ||
|
||
assert.equal(adapter.buildUrl('single', 'checkouts', token), `${baseUrl}/checkouts/${token}.json`); | ||
}); | ||
|
||
test('it throws if someone attempts to query the checkout endpoint', function (assert) { | ||
assert.expect(1); | ||
|
||
const token = 'abc123'; | ||
|
||
adapter.config = { myShopifyDomain }; | ||
|
||
assert.throws(function () { | ||
adapter.buildUrl('multiple', 'checkouts', { token }); | ||
}, 'querying checkouts should produce an error'); | ||
}); | ||
|
||
test('it sends a GET, the correct url, and auth headers for fetchSingle to #ajax', function (assert) { | ||
assert.expect(3); | ||
|
||
const token = 'abc123'; | ||
|
||
adapter.config = { myShopifyDomain, apiKey }; | ||
|
||
adapter.ajax = function (method, url, opts) { | ||
assert.equal(method, 'get'); | ||
assert.equal(url, `${baseUrl}/checkouts/${token}.json`); | ||
assert.deepEqual(opts.headers, { Authorization: `Basic ${base64ApiKey}` }); | ||
return resolvingPromise(); | ||
}; | ||
|
||
adapter.fetchSingle('checkouts', token); | ||
}); | ||
|
||
test('it sends a POST, the correct url, and auth headers to #ajax on #create', function (assert) { | ||
assert.expect(4); | ||
|
||
const done = assert.async(); | ||
|
||
const checkoutJson = { token: 'abc123' }; | ||
|
||
adapter.config = { myShopifyDomain, apiKey }; | ||
|
||
adapter.ajax = function (method, url, opts) { | ||
assert.equal(method, 'post'); | ||
assert.equal(url, `${baseUrl}/checkouts.json`); | ||
assert.deepEqual(opts.headers, { Authorization: `Basic ${base64ApiKey}` }); | ||
return resolvingPromise({ json: checkoutJson }); | ||
}; | ||
|
||
adapter.create('checkouts').then(result => { | ||
assert.equal(result, checkoutJson); | ||
done(); | ||
}).catch(() => { | ||
assert.ok(false); | ||
done(); | ||
}); | ||
}); | ||
|
||
test('it sends a PATCH, the correct url, and auth headers to #ajax on #update', function (assert) { | ||
assert.expect(4); | ||
|
||
const done = assert.async(); | ||
|
||
const id = 'abc123'; | ||
const payload = { checkout: { id, line_items: [] } }; | ||
const serverResponse = assign({}, payload); | ||
|
||
adapter.config = { myShopifyDomain, apiKey }; | ||
|
||
adapter.ajax = function (method, url, opts) { | ||
assert.equal(method, 'patch'); | ||
assert.equal(url, `${baseUrl}/checkouts/${id}.json`); | ||
assert.deepEqual(opts.headers, { Authorization: `Basic ${base64ApiKey}` }); | ||
return resolvingPromise({ json: serverResponse }); | ||
}; | ||
|
||
adapter.update('checkouts', id, payload).then(result => { | ||
assert.equal(result, serverResponse); | ||
done(); | ||
}).catch(() => { | ||
assert.ok(false); | ||
done(); | ||
}); | ||
}); |