Skip to content

Commit

Permalink
Add JSON:API helpers (#249)
Browse files Browse the repository at this point in the history
* Add JSON:API helpers

* Update tests to use JSON:API helpers

* Fix paths to SDK in tests

* Fix variable name and tests

* Add findSingleRelationshipDocument
  • Loading branch information
tniezg authored Sep 13, 2021
1 parent 6c3f237 commit 17b765b
Show file tree
Hide file tree
Showing 14 changed files with 125 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/errors/CastError.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import SpreeSDKError from './SpreeSDKError'

export default class CastError extends SpreeSDKError {
constructor(name: string) {
super(name)
constructor(message: string) {
super(message)
Object.setPrototypeOf(this, CastError.prototype)
this.name = 'CastError'
}
Expand Down
4 changes: 2 additions & 2 deletions src/errors/DeserializeError.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import SpreeSDKError from './SpreeSDKError'

export default class DeserializeError extends SpreeSDKError {
constructor(name: string) {
super(name)
constructor(message: string) {
super(message)
Object.setPrototypeOf(this, DeserializeError.prototype)
this.name = 'DeserializeError'
}
Expand Down
9 changes: 9 additions & 0 deletions src/errors/DocumentRelationshipError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import SpreeSDKError from './SpreeSDKError'

export default class DocumentRelationshipError extends SpreeSDKError {
constructor(message: string) {
super(message)
Object.setPrototypeOf(this, DocumentRelationshipError.prototype)
this.name = 'DocumentRelationshipError'
}
}
4 changes: 3 additions & 1 deletion src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import NoResponseError from './NoResponseError'
import SpreeError from './SpreeError'
import SpreeSDKError from './SpreeSDKError'
import FetchError from './FetchError'
import DocumentRelationshipError from './DocumentRelationshipError'

export {
BasicSpreeError,
Expand All @@ -13,5 +14,6 @@ export {
NoResponseError,
SpreeError,
SpreeSDKError,
FetchError
FetchError,
DocumentRelationshipError
}
61 changes: 61 additions & 0 deletions src/helpers/jsonApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { JsonApiDocument, JsonApiResponse } from '../interfaces/JsonApi'
import type { RelationType } from '../interfaces/Relationships'
import { DocumentRelationshipError } from '../errors'

const findDocument = <DocumentType extends JsonApiDocument>(
spreeSuccessResponse: JsonApiResponse,
relationType: RelationType
): DocumentType | null => {
if (!spreeSuccessResponse.included) {
return null
}

return (
(spreeSuccessResponse.included.find(
(includedObject) => includedObject.type === relationType.type && includedObject.id === relationType.id
) as DocumentType) || null
)
}

const findRelationshipDocuments = <DocumentType extends JsonApiDocument>(
spreeSuccessResponse: JsonApiResponse,
sourceDocument: JsonApiDocument,
relationshipName: string
): DocumentType[] => {
if (!spreeSuccessResponse.included) {
return []
}

const oneOrManyDocumentReferences = sourceDocument.relationships[relationshipName]?.data
let documentReferences: RelationType[]

if (!oneOrManyDocumentReferences) {
throw new DocumentRelationshipError(`Incorrect relationship ${relationshipName}.`)
}

if (Array.isArray(oneOrManyDocumentReferences)) {
documentReferences = oneOrManyDocumentReferences
} else {
documentReferences = [oneOrManyDocumentReferences]
}

return documentReferences
.map<DocumentType>((relationType: RelationType) => findDocument<DocumentType>(spreeSuccessResponse, relationType))
.filter(Boolean)
}

const findSingleRelationshipDocument = <DocumentType extends JsonApiDocument>(
spreeSuccessResponse: JsonApiResponse,
sourceDocument: JsonApiDocument,
relationshipName: string
): DocumentType | null => {
const documents = findRelationshipDocuments<DocumentType>(spreeSuccessResponse, sourceDocument, relationshipName)

if (documents.length === 0) {
return null
}

return documents[0]
}

export { findDocument, findRelationshipDocuments, findSingleRelationshipDocument }
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Client from './Client'
import * as errors from './errors'
import * as result from './helpers/result'
import * as jsonApi from './helpers/jsonApi'
import Http from './Http'
import routes, { storefrontPath } from './routes'
import * as endpoints from './endpoints'
import makeClient from './makeClient'

export { Client, Http, result, errors, makeClient, endpoints, routes, storefrontPath }
export { Client, Http, result, errors, makeClient, endpoints, routes, storefrontPath, jsonApi }
6 changes: 6 additions & 0 deletions tests/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"rules": {
"@typescript-eslint/no-non-null-assertion": "off",
"max-lines-per-function": "off"
}
}
34 changes: 24 additions & 10 deletions tests/e2e/spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// To import @spree/storefront-api-v2-sdk, run 'npm link' and 'npm link @spree/storefront-api-v2-sdk'
// in the project's root directory.
import { Client, makeClient, result } from '@spree/storefront-api-v2-sdk'
import { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'
import { Client, makeClient, result, jsonApi } from '@spree/storefront-api-v2-sdk'
import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'
import type { FetcherStrategies } from '@spree/storefront-api-v2-sdk/types/interfaces/ClientConfig'

// eslint-disable-next-line max-lines-per-function
const createTests = function () {
it('completes guest order', function () {
const { orderFullAddress } = this
Expand All @@ -19,12 +19,14 @@ const createTests = function () {
return cy
.wrap(null)
.then(function () {
return client.products.list({}, { include: 'variants' })
return client.products.list({}, { include: 'default_variant' })
})
.then(function (variantsResponse) {
const variantId = variantsResponse
.success()
.included.find((variant) => variant.type === 'variant' && variant.attributes.in_stock).id
const variantId = jsonApi.findSingleRelationshipDocument(
variantsResponse.success(),
variantsResponse.success().data[0],
'default_variant'
).id

return client.cart.addItem({ orderToken }, { variant_id: variantId, quantity: 1 })
})
Expand Down Expand Up @@ -58,7 +60,7 @@ const createTests = function () {
.then(function (paymentsResponse) {
const checkPaymentId = paymentsResponse
.success()
.data.find((paymentMethod) => paymentMethod.attributes.type === 'Spree::PaymentMethod::Check').id
.data.find((paymentMethod) => paymentMethod.attributes.type === 'Spree::PaymentMethod::Check')!.id

return client.checkout.orderUpdate(
{ orderToken },
Expand Down Expand Up @@ -140,7 +142,13 @@ const createTests = function () {
})
}

const createServerVersionInTheBrowserTests = ({ host, fetcherType }: { host: string; fetcherType: string }) => {
const createServerVersionInTheBrowserTests = ({
host,
fetcherType
}: {
host: string
fetcherType: FetcherStrategies
}) => {
describe(`server version (i.e. CJS module) in the browser using ${fetcherType}`, function () {
beforeEach(function () {
const client = makeClient({ host, fetcherType })
Expand All @@ -152,7 +160,13 @@ const createServerVersionInTheBrowserTests = ({ host, fetcherType }: { host: str
})
}

const createClientVersionInTheBrowserTests = ({ host, fetcherType }: { host: string; fetcherType: string }) => {
const createClientVersionInTheBrowserTests = ({
host,
fetcherType
}: {
host: string
fetcherType: FetcherStrategies
}) => {
describe(`client version (window global) in the browser using ${fetcherType}`, function () {
beforeEach(function () {
cy.readFile('/sdk/dist/client/index.js').then(function (spreeClientScript) {
Expand Down
2 changes: 1 addition & 1 deletion types/errors/CastError.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import SpreeSDKError from './SpreeSDKError';
export default class CastError extends SpreeSDKError {
constructor(name: string);
constructor(message: string);
}
2 changes: 1 addition & 1 deletion types/errors/DeserializeError.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import SpreeSDKError from './SpreeSDKError';
export default class DeserializeError extends SpreeSDKError {
constructor(name: string);
constructor(message: string);
}
4 changes: 4 additions & 0 deletions types/errors/DocumentRelationshipError.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import SpreeSDKError from './SpreeSDKError';
export default class DocumentRelationshipError extends SpreeSDKError {
constructor(message: string);
}
3 changes: 2 additions & 1 deletion types/errors/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ import NoResponseError from './NoResponseError';
import SpreeError from './SpreeError';
import SpreeSDKError from './SpreeSDKError';
import FetchError from './FetchError';
export { BasicSpreeError, ExpandedSpreeError, MisconfigurationError, NoResponseError, SpreeError, SpreeSDKError, FetchError };
import DocumentRelationshipError from './DocumentRelationshipError';
export { BasicSpreeError, ExpandedSpreeError, MisconfigurationError, NoResponseError, SpreeError, SpreeSDKError, FetchError, DocumentRelationshipError };
6 changes: 6 additions & 0 deletions types/helpers/jsonApi.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { JsonApiDocument, JsonApiResponse } from '../interfaces/JsonApi';
import type { RelationType } from '../interfaces/Relationships';
declare const findDocument: <DocumentType_1 extends JsonApiDocument>(spreeSuccessResponse: JsonApiResponse, relationType: RelationType) => DocumentType_1;
declare const findRelationshipDocuments: <DocumentType_1 extends JsonApiDocument>(spreeSuccessResponse: JsonApiResponse, sourceDocument: JsonApiDocument, relationshipName: string) => DocumentType_1[];
declare const findSingleRelationshipDocument: <DocumentType_1 extends JsonApiDocument>(spreeSuccessResponse: JsonApiResponse, sourceDocument: JsonApiDocument, relationshipName: string) => DocumentType_1;
export { findDocument, findRelationshipDocuments, findSingleRelationshipDocument };
3 changes: 2 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Client from './Client';
import * as errors from './errors';
import * as result from './helpers/result';
import * as jsonApi from './helpers/jsonApi';
import Http from './Http';
import routes, { storefrontPath } from './routes';
import * as endpoints from './endpoints';
import makeClient from './makeClient';
export { Client, Http, result, errors, makeClient, endpoints, routes, storefrontPath };
export { Client, Http, result, errors, makeClient, endpoints, routes, storefrontPath, jsonApi };

0 comments on commit 17b765b

Please sign in to comment.