Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: [ON HOLD]Implement new get request subscription endpoint #979

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/client/src/__tests__/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ Object {
"PreOwned": "PreOwned",
"SubBrand": "SubBrand",
},
"ChannelVNext": Object {
"Email": "Email",
"None": "None",
"Sms": "Sms",
},
"ChargeDeclineCode": Object {
"Default": "Default",
"Generic": "Generic",
Expand Down Expand Up @@ -394,6 +399,11 @@ Object {
"FFCountry": "FF-Country",
"FFCurrency": "FF-Currency",
},
"InvalidationsVNext": Object {
"InvCountryCodeLib": "InvCountryCodeLib",
"InvCulturalCodeApi": "InvCulturalCodeApi",
"InvCulturalCodeLib": "InvCulturalCodeLib",
},
"MerchantLocationWeekday": Object {
"0": "Sunday",
"1": "Monday",
Expand Down Expand Up @@ -1188,6 +1198,7 @@ Object {
"getStaffMember": [Function],
"getSubscriptionPackages": [Function],
"getSubscriptions": [Function],
"getSubscriptionsVNext": [Function],
"getTheme": [Function],
"getTopCategories": [Function],
"getTranslations": [Function],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { rest, type RestHandler } from 'msw';
import type { SubscriptionVNext } from '../types/index.js';

const path = '/api/marketing/vNext/Subscriptions';

const fixtures = {
success: (response: SubscriptionVNext[]): RestHandler =>
rest.get(path, (_req, res, ctx) =>
res(ctx.status(200), ctx.json(response)),
),
failure: (): RestHandler =>
rest.get(path, (_req, res, ctx) =>
res(ctx.status(404), ctx.json({ message: 'stub error' })),
),
};

export default fixtures;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getSubscriptionsVNext should receive a client request error 1`] = `
Object {
"code": "-1",
"message": "stub error",
"name": "AxiosError",
"status": 404,
"transportLayerErrorCode": "ERR_BAD_REQUEST",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { getSubscriptionsVNext } from '../index.js';
import { mockGetSubscriptionsVNext } from 'tests/__fixtures__/subscriptions/index.mjs';
import client from '../../helpers/client/index.js';
import fixtures from '../__fixtures__/getSubscriptions.vnext.fixtures.js';
import join from 'proper-url-join';
import mswServer from '../../../tests/mswServer.js';

describe('getSubscriptionsVNext', () => {
const expectedConfig = undefined;
const spy = jest.spyOn(client, 'get');
const defaultUrl = join('/marketing/vNext/Subscriptions', {
query: mockGetSubscriptionsVNext.query,
});

it('should handle a client request successfully', async () => {
mswServer.use(fixtures.success(mockGetSubscriptionsVNext.response));

await expect(
getSubscriptionsVNext(mockGetSubscriptionsVNext.query),
).resolves.toEqual(mockGetSubscriptionsVNext.response);

expect(spy).toHaveBeenCalledWith(defaultUrl, expectedConfig);
});

it('should receive a client request error', async () => {
mswServer.use(fixtures.failure());

await expect(
getSubscriptionsVNext(mockGetSubscriptionsVNext.query),
).rejects.toMatchSnapshot();

expect(spy).toHaveBeenCalledWith(defaultUrl, expectedConfig);
});
});
9 changes: 2 additions & 7 deletions packages/client/src/subscriptions/getSubscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,17 @@ import join from 'proper-url-join';
import type { GetSubscriptions } from './types/index.js';

/**
* @deprecated Use `getSubscriptionsVNext` instead.
* Method responsible for retrieving data from subscriptions endpoint on MKT API.
*
* @param query - Query parameters to apply.
* @param config - Custom configurations to send to the client instance (axios).
*
* @returns Promise that will resolve when the call to the endpoint finishes.
*/

const getSubscriptions: GetSubscriptions = (query, config) =>
client
.get(
join('/marketing/v1/subscriptions', {
query,
}),
config,
)
.get(join('/marketing/v1/subscriptions', { query }), config)
.then(response => response.data)
.catch(error => {
throw adaptError(error);
Expand Down
22 changes: 22 additions & 0 deletions packages/client/src/subscriptions/getSubscriptions.vnext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { adaptError } from '../helpers/client/formatError.js';
import client from '../helpers/client/index.js';
import join from 'proper-url-join';
import type { GetSubscriptionsVNext } from './types/index.js';

/**
* Method responsible for retrieving data from subscriptions endpoint on MKT API.
*
* @param query - Query parameters to apply.
* @param config - Custom configurations to send to the client instance (axios).
*
* @returns Promise that will resolve when the call to the endpoint finishes.
*/
const getSubscriptionsVNext: GetSubscriptionsVNext = (query, config) =>
client
.get(join('marketing/vNext/Subscriptions', { query }), config)
.then(({ data }) => data)
.catch(error => {
throw adaptError(error);
});

export default getSubscriptionsVNext;
1 change: 1 addition & 0 deletions packages/client/src/subscriptions/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as putSubscriptions } from './putSubscriptions.js';
export { default as getSubscriptions } from './getSubscriptions.js';
export { default as getSubscriptionsVNext } from './getSubscriptions.vnext.js';
export { default as getSubscriptionPackages } from './getSubscriptionPackages.js';
export { default as deleteSubscription } from './deleteSubscription.js';
export { default as deleteSubscriptionTopicRecipient } from './deleteSubscriptionTopicRecipient.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { Config } from '../../types/index.js';

export type GetSubscriptionsVNext = (
query: GetSubscriptionsQueryVNext,
config?: Config,
) => Promise<SubscriptionVNext[]>;

export type SubscriptionVNext = {
id: string;
userId?: string;
tenantId: number;
metadata?: SubscriptionMetadataVNext;
topics: SubscriptionTopicVNext[];
invalidMessages?: SubscriptionInvalidationVNext;
};

// * used: "#/components/schemas/SubscriptionInvalidation"
export type SubscriptionInvalidationVNext = {
code?: InvalidationsVNext;
description?: string;
};

// * used: "#/components/schemas/Invalidations"
export enum InvalidationsVNext {
InvCountryCodeLib = 'InvCountryCodeLib',
InvCulturalCodeLib = 'InvCulturalCodeLib',
InvCulturalCodeApi = 'InvCulturalCodeApi',
}

export type SubscriptionMetadataVNext = Record<string, string>;

// * used: "#/components/schemas/SubscriptionTopicResponse"
export type SubscriptionTopicVNext = {
name?: string;
specification?: Record<string, unknown>;
channels?: SubscriptionDeliveryChannelVNext[];
};

// * used: "#/components/schemas/DeliveryChannelResponse"
export type SubscriptionDeliveryChannelVNext = {
chanel: ChannelVNext;
recipient?: string;
source?: string;
};

// * used: "#/components/schemas/Channel"
export enum ChannelVNext {
None = 'None',
Email = 'Email',
Sms = 'Sms',
}

/**
/v1/Subscriptions
get:
tags:
- Subscriptions
*/
export type GetSubscriptionsQueryVNext = {
/**
* Subscription id. Use this when you do not have a registered user in conjunction with recipientHash.
*/
id?: string;

/**
* User id. Use this when you have a registered user. This parameter is mutually
* exclusive with `recipientHash`.
*/
userId?: string;

/**
* Hash of the recipient's email. Use this when you do not have a registered user.
* This parameter is mutually exclusive with `userId`.
*/
recipient?: string;
};
1 change: 1 addition & 0 deletions packages/client/src/subscriptions/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './getSubscriptionPackages.types.js';
export * from './deleteSubscription.types.js';
export * from './deleteSubscriptionTopicRecipient.js';
export * from './putSubscriptions.types.js';
export * from './getSubscriptions.vnext.types.js';
16 changes: 16 additions & 0 deletions packages/redux/src/subscriptions/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,19 @@ export const CLEAR_UNSUBSCRIBE_SUBSCRIPTION_TOPIC_RECIPIENT_REQUEST =
*/
export const CLEAR_ALL_UNSUBSCRIBE_SUBSCRIPTION_TOPIC_RECIPIENT_FROM_REQUESTS =
'@farfetch/blackout-redux/CLEAR_ALL_UNSUBSCRIBE_SUBSCRIPTION_TOPIC_RECIPIENT_FROM_REQUESTS';

/**
* xNext - Action type dispatched when the fetch user subscriptions request fails.
*/
export const FETCH_USER_SUBSCRIPTIONS_FAILURE_VNEXT =
'@farfetch/blackout-redux/FETCH_USER_SUBSCRIPTIONS_FAILURE_VNEXT';
/**
* xNext - Action type dispatched when the fetch user subscriptions request starts.
*/
export const FETCH_USER_SUBSCRIPTIONS_REQUEST_VNEXT =
'@farfetch/blackout-redux/FETCH_USER_SUBSCRIPTIONS_REQUEST_VNEXT';
/**
* xNext - Action type dispatched when the fetch user subscriptions request succeeds.
*/
export const FETCH_USER_SUBSCRIPTIONS_SUCCESS_VNEXT =
'@farfetch/blackout-redux/FETCH_USER_SUBSCRIPTIONS_SUCCESS_VNEXT';
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Subscriptions redux actions fetchUserSubscriptionsVNext() action creator Should create the correct actions for when the get subscriptions is successful: Fetch subscriptions success payload 1`] = `
Object {
"payload": Array [
Object {
"id": "8c2b5c3e3acb4bdd9c26ba46",
"metadata": Object {
"meta": "data",
},
"tenantId": 19934,
"topics": Array [
Object {
"channels": Array [
Object {
"chanel": "None",
"recipient": "1ca9c02be7e27f42bdfdca1afef2618003bbdc7d08fe2e9b54d2ac5af8b37127",
"source": "My Account",
},
Object {
"chanel": "Email",
"recipient": "3c2b5c3e3acb4bdd9c26ba46",
"source": "My Account",
},
Object {
"chanel": "Sms",
"recipient": "1234567890",
"source": "My Account",
},
],
"name": "Any",
"specification": Object {
"type": "Any",
},
},
],
},
],
"type": "@farfetch/blackout-redux/FETCH_USER_SUBSCRIPTIONS_SUCCESS_VNEXT",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as actionTypes from '../../actionTypes.js';
import { fetchUserSubscriptionsVNext } from '../index.js';
import { find } from 'lodash-es';
import { getSubscriptionsVNext } from '@farfetch/blackout-client';
import { mockGetSubscriptionsVNext } from 'tests/__fixtures__/subscriptions/index.mjs';
import { mockStore } from '../../../../tests/index.js';
import reducer from '../../reducer/index.js';

jest.mock('@farfetch/blackout-client', () => {
return {
...jest.requireActual('@farfetch/blackout-client'),
getSubscriptionsVNext: jest.fn(),
};
});

const randomAction = { type: 'this_is_a_random_action' };
const subscriptionsMockStore = (state = {}) =>
mockStore({ getSubscriptionsVNext: reducer(undefined, randomAction) }, state);

describe('Subscriptions redux actions', () => {
let store: ReturnType<typeof subscriptionsMockStore>;

beforeEach(jest.clearAllMocks);

describe('fetchUserSubscriptionsVNext() action creator', () => {
beforeEach(() => {
store = subscriptionsMockStore();
});

it('Should create the correct actions for when the get subscription fails', async () => {
const expectedError = new Error('get subscriptions error');

(getSubscriptionsVNext as jest.Mock).mockRejectedValueOnce(expectedError);

await expect(
async () =>
await fetchUserSubscriptionsVNext(mockGetSubscriptionsVNext.query)(
store.dispatch,
),
).rejects.toThrow(expectedError);

expect(getSubscriptionsVNext).toHaveBeenCalledTimes(1);
expect(getSubscriptionsVNext).toHaveBeenCalledWith(
mockGetSubscriptionsVNext.query,
undefined,
);
expect(store.getActions()).toEqual(
expect.arrayContaining([
{ type: actionTypes.FETCH_USER_SUBSCRIPTIONS_REQUEST_VNEXT },
{
type: actionTypes.FETCH_USER_SUBSCRIPTIONS_FAILURE,
payload: { error: expectedError },
},
]),
);
});

it('Should create the correct actions for when the get subscriptions is successful', async () => {
(getSubscriptionsVNext as jest.Mock).mockResolvedValueOnce(
mockGetSubscriptionsVNext.response,
);

await fetchUserSubscriptionsVNext(mockGetSubscriptionsVNext.query)(
store.dispatch,
).then(clientResult => {
expect(clientResult).toBe(mockGetSubscriptionsVNext.response);
});

const actionResults = store.getActions();

expect(getSubscriptionsVNext).toHaveBeenCalledTimes(1);
expect(getSubscriptionsVNext).toHaveBeenCalledWith(
mockGetSubscriptionsVNext.query,
undefined,
);
expect(actionResults).toMatchObject([
{ type: actionTypes.FETCH_USER_SUBSCRIPTIONS_REQUEST_VNEXT },
{
payload: expect.any(Object),
type: actionTypes.FETCH_USER_SUBSCRIPTIONS_SUCCESS_VNEXT,
},
]);
expect(
find(actionResults, {
type: actionTypes.FETCH_USER_SUBSCRIPTIONS_SUCCESS_VNEXT,
}),
).toMatchSnapshot('Fetch subscriptions success payload');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import type { FetchUserSubscriptionsFactory } from './types/index.js';

/**
* @deprecated Prefer to use `fetchUserSubscriptionsFactoryVNext`
* Method to create a thunk factory configured with the specified client.
*
* @param getSubscriptions - Get subscriptions client.
Expand Down