Skip to content

Commit

Permalink
Merge branch 'develop' into ankurvr-payment-method-page-error
Browse files Browse the repository at this point in the history
  • Loading branch information
sirugh authored Feb 23, 2021
2 parents e752235 + 00b0136 commit 6420448
Show file tree
Hide file tree
Showing 34 changed files with 641 additions and 140 deletions.
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ const jestConfig = {
})),
configureProject('pagebuilder', 'Pagebuilder', testReactComponents),
configureProject('peregrine', 'Peregrine', inPackage => ({
// Make sure we can test extension files.
moduleFileExtensions: [
'ee.js',
'ce.js',
'js',
'json',
'jsx',
'node'
],
// Define global variables.
globals,
// Expose jsdom to tests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@ import typePolicies from '../policies';

import { clearCartDataFromCache } from '../clearCartDataFromCache';

const persistor = {
persistor: {
storage: {
key: 'unit test key'
}
},
persist: jest.fn()
};

const log = jest.fn();

const Component = () => {
const client = useApolloClient();
client.persistor = persistor;

const initialCacheData = Object.assign({}, client.cache.data.data);
log(initialCacheData);
Expand Down
125 changes: 125 additions & 0 deletions packages/peregrine/lib/Apollo/__tests__/deleteCacheEntry.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import { deleteCacheEntry } from '../deleteCacheEntry';
const log = jest.fn();

const persistor = {
persistor: {
storage: {
key: 'unit test key'
}
},
persist: jest.fn()
};

Expand Down Expand Up @@ -137,3 +142,123 @@ test('handle function call with no persistor', async () => {

expect(spy).toHaveBeenCalledTimes(0);
});

describe('deleteInactiveCachesEntry', () => {
let previousLocalStorage;
const getItemMock = jest.fn();
const setItemMock = jest.fn();
const localStorageMock = (function() {
const store = {
'active apollo cache': JSON.stringify({ active: 'cache' }),
'apollo-cache-persist-inactive': JSON.stringify({
inactive: 'cache'
}),
'some-other-storage-key': JSON.stringify({ other: 'value' })
};

return {
...store,
getItem: getItemMock,
setItem: setItemMock
};
})();
const client = {
// Purposefully supply a falsy cache to early out of deleteActiveCacheEntry.
cache: null,
persistor: {
persistor: {
storage: {
key: 'active apollo cache'
}
}
}
};
const predicate = jest.fn();

beforeAll(() => {
previousLocalStorage = window.localStorage;

Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
writable: true
});
});
afterEach(() => {
getItemMock.mockRestore();
setItemMock.mockRestore();
predicate.mockReset();
});
afterAll(() => {
Object.defineProperty(window, 'localStorage', {
value: previousLocalStorage,
writable: true
});
});

test('it bails when no client', async () => {
// Arrange.
const testClient = null;

// Act.
await deleteCacheEntry(testClient, predicate);

// Assert.
expect(predicate).not.toHaveBeenCalled();
});

test('it bails when no client persistor', async () => {
// Arrange.
const testClient = {};

// Act.
await deleteCacheEntry(testClient, predicate);

// Assert.
expect(predicate).not.toHaveBeenCalled();
});

test('only attempts to delete from inactive apollo caches', async () => {
// Arrange.

// Act.
await deleteCacheEntry(client, predicate);

// Assert.
expect(setItemMock).toHaveBeenCalledTimes(1);
// The key 'inactive' only appears in the inactive cache mock.
expect(predicate).toHaveBeenCalledWith('inactive');
expect(predicate).not.toHaveBeenCalledWith('active');
expect(predicate).not.toHaveBeenCalledWith('other');
});

test('deletes keys that satisfy the predicate', async () => {
// Arrange.
predicate.mockReturnValue(true);

// Act.
await deleteCacheEntry(client, predicate);

// Assert.
expect(setItemMock).toHaveBeenCalledTimes(1);
expect(setItemMock).toHaveBeenCalledWith(
'apollo-cache-persist-inactive',
'{}' // the only entry was deleted
);
});

test('does not delete keys that dont satisfy the predicate', async () => {
// Arrange.
predicate.mockReturnValue(false);

// Act.
await deleteCacheEntry(client, predicate);

// Assert.
const previousValue = localStorageMock['apollo-cache-persist-inactive'];
expect(setItemMock).toHaveBeenCalledTimes(1);
expect(setItemMock).toHaveBeenCalledWith(
'apollo-cache-persist-inactive',
previousValue
);
});
});
2 changes: 2 additions & 0 deletions packages/peregrine/lib/Apollo/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is used here in peregrine and in the storefront.
export const CACHE_PERSIST_PREFIX = 'apollo-cache-persist';
44 changes: 43 additions & 1 deletion packages/peregrine/lib/Apollo/deleteCacheEntry.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CACHE_PERSIST_PREFIX } from '@magento/peregrine/lib/Apollo/constants';

/**
* Deletes specific entry/entries from the apollo cache and then tries to
* persist the deletions.
Expand All @@ -6,6 +8,11 @@
* @param {Function} predicate a matching function
*/
export const deleteCacheEntry = async (client, predicate) => {
await deleteActiveCacheEntry(client, predicate);
await deleteInactiveCachesEntry(client, predicate);
};

const deleteActiveCacheEntry = async (client, predicate) => {
// If there is no client or cache then just back out since it doesn't matter :D
if (
!client ||
Expand All @@ -21,14 +28,49 @@ export const deleteCacheEntry = async (client, predicate) => {
return;
}

// Remove from the active cache.
Object.keys(client.cache.data.data).forEach(key => {
if (predicate(key)) {
client.cache.data.delete(key);
}
});

// Immediately persist the cache changes.
// Immediately persist the cache changes to the active cache storage.
if (client.persistor) {
await client.persistor.persist();
}
};

const deleteInactiveCachesEntry = async (client, predicate) => {
if (!client || !client.persistor) return;

const activeApolloCacheLocalStorageKey =
client.persistor.persistor.storage.key;

const isAnInactiveApolloCache = ([key]) => {
return (
key.startsWith(CACHE_PERSIST_PREFIX) &&
key !== activeApolloCacheLocalStorageKey
);
};

Object.entries(localStorage)
.filter(isAnInactiveApolloCache)
.forEach(([inactiveCacheKey, inactiveCacheValue]) => {
const inactiveApolloCache = JSON.parse(inactiveCacheValue);

Object.keys(inactiveApolloCache).forEach(key => {
if (predicate(key)) {
delete inactiveApolloCache[key];
}
});

// We're done deleting keys that match the predicate,
// but we've only mutated the object in memory.
// Write the updated inactive cache back out to localStorage.
localStorage.setItem(
inactiveCacheKey,
JSON.stringify(inactiveApolloCache)
);
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ const thunkArgs = [
dispatch,
getState,
{
apolloClient: {}
apolloClient: {
persistor: {
persistor: {
storage: {
key: 'unit test key'
}
}
}
}
}
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ const thunkArgs = [
dispatch,
getState,
{
apolloClient: {}
apolloClient: {
persistor: {
persistor: {
storage: {
key: 'unit test key'
}
}
}
}
}
];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { gql } from '@apollo/client';

export const DiscountSummaryFragment = gql`
fragment DiscountSummaryFragment on CartPrices {
discounts {
amount {
currency
value
}
label
}
}
`;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { gql } from '@apollo/client';

import { DiscountSummaryFragment } from './discountSummary';
import { DiscountSummaryFragment } from './discountSummary.gql';
import { GiftCardSummaryFragment } from './queries/giftCardSummary';
import { ShippingSummaryFragment } from './shippingSummary';
import { TaxSummaryFragment } from './taxSummary';
import { ShippingSummaryFragment } from './shippingSummary.gql';
import { TaxSummaryFragment } from './taxSummary.gql';

export const GrandTotalFragment = gql`
fragment GrandTotalFragment on CartPrices {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { gql } from '@apollo/client';

export const GiftCardSummaryFragment = gql`
fragment GiftCardSummaryFragment on Cart {
id
__typename
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { gql } from '@apollo/client';

export const GiftCardSummaryFragment = gql`
fragment GiftCardSummaryFragment on Cart {
id
applied_gift_cards {
# code is "id" of the gift cards, used to merge cache data with incoming.
code
applied_balance {
value
currency
}
}
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { gql } from '@apollo/client';

export const ShippingSummaryFragment = gql`
fragment ShippingSummaryFragment on Cart {
id
shipping_addresses {
selected_shipping_method {
amount {
currency
value
}
}
street
}
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { gql } from '@apollo/client';

export const TaxSummaryFragment = gql`
fragment TaxSummaryFragment on CartPrices {
applied_taxes {
amount {
currency
value
}
}
}
`;
Loading

0 comments on commit 6420448

Please sign in to comment.