Skip to content

Commit

Permalink
feat(cart): throw unrecoverable errors in magento driver (#2488)
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 committed Jun 29, 2023
1 parent d82d703 commit 18bca84
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 53 deletions.
249 changes: 197 additions & 52 deletions libs/cart/driver/magento/src/cart.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
APOLLO_TESTING_CACHE,
} from 'apollo-angular/testing';
import { GraphQLError } from 'graphql';
import { of } from 'rxjs';
import {
catchError,
of,
} from 'rxjs';

import {
DaffCart,
Expand All @@ -27,6 +30,8 @@ import {
DaffMagentoCartTransformer,
createCart,
getCart,
magentoMergeCartsMutation,
MagentoMergeCartResponse,
} from '@daffodil/cart/driver/magento';
import {
MagentoCartFactory,
Expand Down Expand Up @@ -59,6 +64,7 @@ describe('@daffodil/cart/driver/magento | DaffMagentoCartService', () => {
let mockDaffCartItem: DaffCartItem;
let mockCartResponse: MagentoGetCartResponse;
let mockCreateCartResponse: MagentoCreateCartResponse;
let mockMergeCartsResponse: MagentoMergeCartResponse;

beforeEach(() => {
TestBed.configureTestingModule({
Expand Down Expand Up @@ -112,6 +118,9 @@ describe('@daffodil/cart/driver/magento | DaffMagentoCartService', () => {
__typename: 'Cart',
cart: mockMagentoCart,
};
mockMergeCartsResponse = {
mergeCarts: mockMagentoCart,
};

magentoCartTransformerSpy.transform.and.returnValue(mockDaffCart);
magentoCartItemSpy.list.and.returnValue(of(mockDaffCart.items));
Expand Down Expand Up @@ -153,62 +162,87 @@ describe('@daffodil/cart/driver/magento | DaffMagentoCartService', () => {
});

describe('when there are graphQL errors', () => {
it('should return those errors', done => {
service.get(cartId).subscribe(result => {
expect(result.errors).toContain(jasmine.any(DaffCartNotFoundError));
expect(result.errors).toContain(jasmine.any(DaffProductOutOfStockError));
done();
});

const op = controller.expectOne(addTypenameToDocument(getCart([])));

op.flush({
errors: [new GraphQLError(
'Can\'t find a cart with that ID.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
), new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)],
describe('and some of the errors are unrecoverable', () => {
it('should throw the first unrecoverable error', done => {
service.get(cartId).pipe(
catchError((err) => {
expect(err).toEqual(jasmine.any(DaffCartNotFoundError));
done();
return of();
}),
).subscribe(result => {
fail('get should throw, not emit');
});

const op = controller.expectOne(addTypenameToDocument(getCart([])));

op.flush({
errors: [new GraphQLError(
'Can\'t find a cart with that ID.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
), new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)],
});
});
});

it('should should set out of stock errors as recoverable', done => {
service.get(cartId).subscribe(result => {
expect(result.errors.find(error => error.code === DaffCartDriverErrorCodes.PRODUCT_OUT_OF_STOCK).recoverable).toBeTrue();
done();
describe('and all of the errors are recoverable', () => {
it('should return those errors', done => {
service.get(cartId).subscribe(result => {
expect(result.errors).toContain(jasmine.any(DaffProductOutOfStockError));
done();
});

const op = controller.expectOne(addTypenameToDocument(getCart([])));

op.flush({
errors: [
new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
),
],
});
});

const op = controller.expectOne(addTypenameToDocument(getCart([])));

op.flush({
errors: [new GraphQLError(
'Can\'t find a cart with that ID.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
), new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)],
it('should should set out of stock errors as recoverable', done => {
service.get(cartId).subscribe(result => {
expect(result.errors.find(error => error.code === DaffCartDriverErrorCodes.PRODUCT_OUT_OF_STOCK).recoverable).toBeTrue();
done();
});

const op = controller.expectOne(addTypenameToDocument(getCart([])));

op.flush({
errors: [
new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
),
],
});
});
});
});
Expand Down Expand Up @@ -262,4 +296,115 @@ describe('@daffodil/cart/driver/magento | DaffMagentoCartService', () => {
controller.verify();
});
});

describe('merge', () => {
let customerCartId: DaffCart['id'];

beforeEach(() => {
customerCartId = 'customerCartId';
});

it('should return the correct value', done => {
service.merge(cartId, customerCartId).subscribe(result => {
expect(result.response).toEqual(jasmine.objectContaining(mockDaffCart));
done();
});

const op = controller.expectOne(addTypenameToDocument(magentoMergeCartsMutation([])));

op.flush({
data: mockMergeCartsResponse,
});
});

describe('when there are graphQL errors', () => {
describe('and some of the errors are unrecoverable', () => {
it('should throw the first unrecoverable error', done => {
service.merge(cartId, customerCartId).pipe(
catchError((err) => {
expect(err).toEqual(jasmine.any(DaffCartNotFoundError));
done();
return of();
}),
).subscribe(result => {
fail('get should throw, not emit');
});

const op = controller.expectOne(addTypenameToDocument(magentoMergeCartsMutation([])));

op.flush({
errors: [new GraphQLError(
'Can\'t find a cart with that ID.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
), new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
)],
});
});
});

describe('and all of the errors are recoverable', () => {
it('should return those errors', done => {
service.merge(cartId, customerCartId).subscribe(result => {
expect(result.errors).toContain(jasmine.any(DaffProductOutOfStockError));
done();
});

const op = controller.expectOne(addTypenameToDocument(magentoMergeCartsMutation([])));

op.flush({
errors: [
new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
),
],
});
});

it('should should set out of stock errors as recoverable', done => {
service.merge(cartId, customerCartId).subscribe(result => {
expect(result.errors.find(error => error.code === DaffCartDriverErrorCodes.PRODUCT_OUT_OF_STOCK).recoverable).toBeTrue();
done();
});

const op = controller.expectOne(addTypenameToDocument(magentoMergeCartsMutation([])));

op.flush({
errors: [
new GraphQLError(
'Some of the products are out of stock.',
null,
null,
null,
null,
null,
{ category: 'graphql-no-such-entity' },
),
],
});
});
});
});

afterEach(() => {
controller.verify();
});
});
});
14 changes: 13 additions & 1 deletion libs/cart/driver/magento/src/cart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,18 @@ export class DaffMagentoCartService implements DaffCartServiceInterface<DaffCart
errors: errors?.map(e => {
const error = transformMagentoCartGraphQlError(e);

if (DAFF_MAGENTO_GET_RECOVERABLE_ERRORS.filter(klass => error instanceof klass).length > 0) {
if (DAFF_MAGENTO_GET_RECOVERABLE_ERRORS.find(klass => error instanceof klass)) {
error.recoverable = true;
}

return error;
}) || [],
})),
switchMap((resp) =>
resp.errors.reduce((acc, err) => acc && err.recoverable, true)
? of(resp)
: throwError(() => resp.errors.filter((err) => !err.recoverable)[0]),
),
);
}

Expand Down Expand Up @@ -126,6 +131,8 @@ export class DaffMagentoCartService implements DaffCartServiceInterface<DaffCart
source: guestCart,
destination: customerCart,
},
errorPolicy: 'all',
fetchPolicy: 'network-only',
}).pipe(
map(({ data, errors }) => ({
response: data ? this.cartTransformer.transform(data.mergeCarts) : undefined,
Expand All @@ -139,6 +146,11 @@ export class DaffMagentoCartService implements DaffCartServiceInterface<DaffCart
return error;
}) || [],
})),
switchMap((resp) =>
resp.errors.reduce((acc, err) => acc && err.recoverable, true)
? of(resp)
: throwError(() => resp.errors.filter((err) => !err.recoverable)[0]),
),
);
};
}

0 comments on commit 18bca84

Please sign in to comment.