-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into bendvc/W-15226710-fix-promo-code
Signed-off-by: Ben Chypak <[email protected]>
- Loading branch information
Showing
14 changed files
with
212 additions
and
9 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
16 changes: 16 additions & 0 deletions
16
packages/commerce-sdk-react/src/hooks/ShopperSeo/index.test.ts
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,16 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import {ShopperSeo} from 'commerce-sdk-isomorphic' | ||
import {getUnimplementedEndpoints} from '../../test-utils' | ||
import * as queries from './query' | ||
|
||
describe('Shopper Seo hooks', () => { | ||
test('all endpoints have hooks', () => { | ||
const unimplemented = getUnimplementedEndpoints(ShopperSeo, queries) | ||
expect(unimplemented).toEqual([]) | ||
}) | ||
}) |
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,8 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
export * from './query' |
12 changes: 12 additions & 0 deletions
12
packages/commerce-sdk-react/src/hooks/ShopperSeo/paramKeys.ts
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,12 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
const getUrlMapping = ['organizationId', 'urlSegment', 'siteId', 'locale'] as const | ||
|
||
export default { | ||
getUrlMapping | ||
} |
58 changes: 58 additions & 0 deletions
58
packages/commerce-sdk-react/src/hooks/ShopperSeo/query.test.ts
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,58 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import nock from 'nock' | ||
import { | ||
mockQueryEndpoint, | ||
renderHookWithProviders, | ||
waitAndExpectError, | ||
waitAndExpectSuccess | ||
} from '../../test-utils' | ||
import * as queries from './query' | ||
|
||
jest.mock('../../auth/index.ts', () => { | ||
const {default: mockAuth} = jest.requireActual('../../auth/index.ts') | ||
mockAuth.prototype.ready = jest.fn().mockResolvedValue({access_token: 'access_token'}) | ||
return mockAuth | ||
}) | ||
|
||
type Queries = typeof queries | ||
const seoEndpoint = '/site/shopper-seo' | ||
// Not all endpoints use all parameters, but unused parameters are safely discarded | ||
const OPTIONS = {parameters: {urlSegment: '/something'}} | ||
|
||
/** Map of query name to returned data type */ | ||
type DataType<K extends keyof Queries> = NonNullable<ReturnType<Queries[K]>['data']> | ||
type TestMap = {[K in keyof Queries]: DataType<K>} | ||
// This is an object rather than an array to more easily ensure we cover all hooks | ||
const testMap: TestMap = { | ||
// Type assertion so we don't need to use the full type | ||
useUrlMapping: {urlSegment: '/sample-product-redirected'} as DataType<'useUrlMapping'> | ||
} | ||
// Type assertion is necessary because `Object.entries` is limited | ||
const testCases = Object.entries(testMap) as Array<[keyof TestMap, TestMap[keyof TestMap]]> | ||
describe('Shopper SEO query hooks', () => { | ||
beforeEach(() => nock.cleanAll()) | ||
afterEach(() => { | ||
expect(nock.pendingMocks()).toHaveLength(0) | ||
}) | ||
test.each(testCases)('`%s` returns data on success', async (queryName, data) => { | ||
mockQueryEndpoint(seoEndpoint, data) | ||
const {result} = renderHookWithProviders(() => { | ||
return queries[queryName](OPTIONS) | ||
}) | ||
await waitAndExpectSuccess(() => result.current) | ||
expect(result.current.data).toEqual(data) | ||
}) | ||
|
||
test.each(testCases)('`%s` returns error on error', async (queryName) => { | ||
mockQueryEndpoint(seoEndpoint, {}, 400) | ||
const {result} = renderHookWithProviders(() => { | ||
return queries[queryName](OPTIONS) | ||
}) | ||
await waitAndExpectError(() => result.current) | ||
}) | ||
}) |
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,57 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import {UseQueryResult} from '@tanstack/react-query' | ||
import {ApiClients, ApiQueryOptions, Argument, DataType, NullableParameters} from '../types' | ||
import useCommerceApi from '../useCommerceApi' | ||
import {useQuery} from '../useQuery' | ||
import {getCustomKeys, mergeOptions, omitNullableParameters, pick} from '../utils' | ||
import * as queryKeyHelpers from './queryKeyHelpers' | ||
import paramKeysMap from './paramKeys' | ||
|
||
type Client = ApiClients['shopperSeo'] | ||
|
||
/** | ||
* Gets URL mapping information for a URL that a shopper clicked or typed in. | ||
* | ||
* The mapping information is based on URL rules and redirects set up in Business Manager. | ||
* For more information about prerequisites and sample usage, see [URL Resolution](https://developer.salesforce.com/docs/commerce/commerce-api/guide/url-resolution.html). You can customize the behavior of this endpoint by using hooks. | ||
* @group ShopperSeo | ||
* @category Query | ||
* @parameter apiOptions - Options to pass through to `commerce-sdk-isomorphic`, with `null` accepted for unset API parameters. | ||
* @parameter queryOptions - TanStack Query query options, with `enabled` by default set to check that all required API parameters have been set. | ||
* @returns A TanStack Query query hook with data from the Shopper Seo `getUrlMapping` endpoint. | ||
* @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-seo?meta=getUrlMapping| Salesforce Developer Center} for more information about the API endpoint. | ||
* @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperseo.shopperseo-1.html#geturlmapping | `commerce-sdk-isomorphic` documentation} for more information on the parameters and returned data type. | ||
* @see {@link https://tanstack.com/query/latest/docs/react/reference/useQuery | TanStack Query `useQuery` reference} for more information about the return value. | ||
*/ | ||
export const useUrlMapping = ( | ||
apiOptions: NullableParameters<Argument<Client['getUrlMapping']>>, | ||
queryOptions: ApiQueryOptions<Client['getUrlMapping']> = {} | ||
): UseQueryResult<DataType<Client['getUrlMapping']>> => { | ||
type Options = Argument<Client['getUrlMapping']> | ||
type Data = DataType<Client['getUrlMapping']> | ||
const {shopperSeo: client} = useCommerceApi() | ||
const methodName = 'getUrlMapping' | ||
const requiredParameters = ['organizationId', 'siteId'] as const | ||
|
||
// Parameters can be set in `apiOptions` or `client.clientConfig`; | ||
// we must merge them in order to generate the correct query key. | ||
const netOptions = omitNullableParameters(mergeOptions(client, apiOptions)) | ||
const paramKeys = [...paramKeysMap[methodName], ...getCustomKeys(netOptions.parameters)] | ||
const parameters = pick(netOptions.parameters, paramKeys) | ||
const queryKey = queryKeyHelpers[methodName].queryKey(netOptions.parameters) | ||
// We don't use `netOptions` here because we manipulate the options in `useQuery`. | ||
const method = async (options: Options) => await client[methodName](options) | ||
|
||
// For some reason, if we don't explicitly set these generic parameters, the inferred type for | ||
// `Data` sometimes, but not always, includes `Response`, which is incorrect. I don't know why. | ||
return useQuery<Client, Options, Data>({...netOptions, parameters}, queryOptions, { | ||
method, | ||
queryKey, | ||
requiredParameters | ||
}) | ||
} |
45 changes: 45 additions & 0 deletions
45
packages/commerce-sdk-react/src/hooks/ShopperSeo/queryKeyHelpers.ts
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,45 @@ | ||
/* | ||
* Copyright (c) 2024, Salesforce, Inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
import type {ShopperSeo} from 'commerce-sdk-isomorphic' | ||
import {Argument, ExcludeTail} from '../types' | ||
import {getCustomKeys, pick} from '../utils' | ||
import paramKeysMap from './paramKeys' | ||
// We must use a client with no parameters in order to have required/optional match the API spec | ||
type Client = ShopperSeo<{shortCode: string}> | ||
type Params<T extends keyof QueryKeys> = Partial<Argument<Client[T]>['parameters']> | ||
export type QueryKeys = { | ||
getUrlMapping: [ | ||
'/commerce-sdk-react', | ||
'/organizations/', | ||
string | undefined, | ||
'/url-mapping', | ||
Params<'getUrlMapping'> | ||
] | ||
} | ||
|
||
// This is defined here, rather than `types.ts`, because it relies on `Client` and `QueryKeys`, | ||
// and making those generic would add too much complexity. | ||
type QueryKeyHelper<T extends keyof QueryKeys> = { | ||
/** Generates the path component of the query key for an endpoint. */ | ||
path: (params: Params<T>) => ExcludeTail<QueryKeys[T]> | ||
/** Generates the full query key for an endpoint. */ | ||
queryKey: (params: Params<T>) => QueryKeys[T] | ||
} | ||
|
||
export const getUrlMapping: QueryKeyHelper<'getUrlMapping'> = { | ||
path: (params) => [ | ||
'/commerce-sdk-react', | ||
'/organizations/', | ||
params.organizationId, | ||
'/url-mapping' | ||
], | ||
queryKey: (params: Params<'getUrlMapping'>) => { | ||
const paramKeys = [...paramKeysMap['getUrlMapping'], ...getCustomKeys(params)] | ||
|
||
return [...getUrlMapping.path(params), pick(params, paramKeys)] | ||
} | ||
} |
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
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
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
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
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