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

GraphQL sitemap now parses personalize data from site queries #1005

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
GraphQLSitemapServiceConfig,
languageError,
} from './graphql-sitemap-service';
import sitemapQueryResult from '../testData/sitemapQueryResult.json';
import sitemapDefaultQueryResult from '../testData/sitemapDefaultQueryResult.json';
import sitemapPersonalizeQueryResult from '../testData/sitemapPersonalizeQueryResult.json';
import sitemapServiceResult from '../testData/sitemapServiceResult';
import { GraphQLClient, GraphQLRequestClient } from '@sitecore-jss/sitecore-jss/graphql';

Expand Down Expand Up @@ -47,7 +48,6 @@ it('should return null if no app root found', async () => {
});
*/
describe('GraphQLSitemapService', () => {
const rootItemId = '{GUID}';
const endpoint = 'http://site';
const apiKey = 'some-api-key';
const siteName = 'site-name';
Expand All @@ -58,11 +58,11 @@ describe('GraphQLSitemapService', () => {

const mockPathsRequest = (results?: { url: { path: string } }[]) => {
nock(endpoint)
.post('/', /SitemapQuery/gi)
.post('/', /DefaultSitemapQuery/gi)
.reply(
200,
results === undefined
? sitemapQueryResult
? sitemapDefaultQueryResult
: {
data: {
site: {
Expand All @@ -85,7 +85,7 @@ describe('GraphQLSitemapService', () => {
it('should work when 1 language is requested', async () => {
mockPathsRequest();

const service = new GraphQLSitemapService({ endpoint, apiKey, siteName, rootItemId });
const service = new GraphQLSitemapService({ endpoint, apiKey, siteName });
const sitemap = await service.fetchSSGSitemap(['ua']);
expect(sitemap).to.deep.equal(sitemapServiceResult);

Expand Down Expand Up @@ -170,6 +170,62 @@ describe('GraphQLSitemapService', () => {
]);
});

it('should return personalized paths when personalize data is requested and returned', async () => {
const lang = 'ua';

nock(endpoint)
.post('/', /PersonalizeSitemapQuery/gi)
.reply(200, sitemapPersonalizeQueryResult);

const service = new GraphQLSitemapService({
endpoint,
apiKey,
siteName,
includePersonalizedRoutes: true,
});
const sitemap = await service.fetchSSGSitemap([lang]);

expect(sitemap).to.deep.equal([
{
params: {
path: [''],
},
locale: lang,
},
{
params: {
path: ['_segmentId_green'],
},
locale: lang,
},
{
params: {
path: ['y1', 'y2', 'y3', 'y4'],
},
locale: lang,
},
{
params: {
path: ['_segmentId_green', 'y1', 'y2', 'y3', 'y4'],
},
locale: lang,
},
{
params: {
path: ['_segmentId_red', 'y1', 'y2', 'y3', 'y4'],
},
locale: lang,
},
{
params: {
path: ['_segmentId_purple', 'y1', 'y2', 'y3', 'y4'],
},
locale: lang,
},
]);
return expect(nock.isDone()).to.be.true;
});

it('should work when multiple languages are requested', async () => {
const lang1 = 'ua';
const lang2 = 'da-DK';
Expand Down Expand Up @@ -320,7 +376,7 @@ describe('GraphQLSitemapService', () => {

nock(endpoint)
.post('/', (body) => body.variables.pageSize === customPageSize)
.reply(200, sitemapQueryResult);
.reply(200, sitemapDefaultQueryResult);

const service = new GraphQLSitemapService({
endpoint,
Expand All @@ -341,7 +397,7 @@ describe('GraphQLSitemapService', () => {
(body) =>
body.query.indexOf('$pageSize: Int = 10') > 0 && body.variables.pageSize === undefined
)
.reply(200, sitemapQueryResult);
.reply(200, sitemapDefaultQueryResult);

const service = new GraphQLSitemapService({
endpoint,
Expand All @@ -366,7 +422,7 @@ describe('GraphQLSitemapService', () => {

it('should throw error if SitemapQuery fails', async () => {
nock(endpoint)
.post('/', /SitemapQuery/gi)
.post('/', /DefaultSitemapQuery/gi)
.reply(500, 'Error 😥');

const service = new GraphQLSitemapService({ endpoint, apiKey, siteName });
Expand Down Expand Up @@ -424,7 +480,7 @@ describe('GraphQLSitemapService', () => {

it('should throw error if SitemapQuery fails', async () => {
nock(endpoint)
.post('/', /SitemapQuery/gi)
.post('/', /DefaultSitemapQuery/gi)
.reply(500, 'Error 😥');

const service = new GraphQLSitemapService({ endpoint, apiKey, siteName });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,48 @@ export const languageError = 'The list of languages cannot be empty';

const languageEmptyError = 'The language must be a non-empty string';

const defaultQuery = /* GraphQL */ `
query SitemapQuery(
$siteName: String!
$language: String!
$includedPaths: [String]
$excludedPaths: [String]
$pageSize: Int = 10
$after: String
) {
site {
siteInfo(site: $siteName) {
routes(
language: $language
includedPaths: $includedPaths
excludedPaths: $excludedPaths
first: $pageSize
after: $after
) {
total
pageInfo {
endCursor
hasNext
}
results {
path: routePath
/**
* GQL query made dynamic based on schema differences between SXP and XM Cloud
* @param {boolean} usesPersonalize flag to detrmine which variation of a query to run
* @returns GraphQL query to fetch site paths with
*/
const defaultQuery = (usesPersonalize: boolean) => /* GraphQL */ `
query ${usesPersonalize ? 'PersonalizeSitemapQuery' : 'DefaultSitemapQuery'}(
$siteName: String!,
$language: String!,
$includedPaths: String[],
$excludedPaths: String[],
$pageSize: Int = 10,
$after: String
) {
site {
siteInfo(site: $siteName) {
routes(
language: $language
includedPaths: $includedPaths
excludedPaths: $excludedPaths
first: $pageSize
after: $after
){
total
pageInfo {
endCursor
hasNext
}
results: routesResult{
path: routePath
${
usesPersonalize
? `personalize: {
variantIds
}`
: ''
}
}
}
}
}
}
`;
/**
* type for input variables for the site routes query
Expand Down Expand Up @@ -89,6 +101,9 @@ export interface SiteRouteQueryResult<T> {
*/
export type RouteListQueryResult = {
path: string;
personalize?: {
variantIds: string[];
};
};

/**
Expand All @@ -104,6 +119,12 @@ export interface GraphQLSitemapServiceConfig extends Omit<SiteRouteQueryVariable
* The API key to use for authentication.
*/
apiKey: string;

/**
* A flag for whether to include personalized routes in service output - only works on XM Cloud
* turned off by default
*/
includePersonalizedRoutes?: boolean;
}

/**
Expand All @@ -128,7 +149,7 @@ export class GraphQLSitemapService {
* Gets the default query used for fetching the list of site pages
*/
protected get query(): string {
return defaultQuery;
return defaultQuery(this.options.includePersonalizedRoutes === true);
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -185,6 +206,8 @@ export class GraphQLSitemapService {
languages: string[],
formatStaticPath: (path: string[], language: string) => StaticPath
): Promise<StaticPath[]> {
const segmentPrefix = '_segmentId_';

if (!languages.length) {
throw new RangeError(languageError);
}
Expand All @@ -208,9 +231,22 @@ export class GraphQLSitemapService {
debug.sitemap('fetching sitemap data for %s', language);

return this.fetchLanguageSitePaths(this.query, args).then((results) => {
return results.map((item) =>
formatStaticPath(item.path.replace(/^\/|\/$/g, '').split('/'), language)
);
const formatPath = (path: string) =>
formatStaticPath(path.replace(/^\/|\/$/g, '').split('/'), language);
const aggregatedPaths: StaticPath[] = [];
results.forEach((item) => {
aggregatedPaths.push(formatPath(item.path));
// check for type safety's sake - personalize may be empty depending on query type
if (item.personalize?.variantIds.length) {
art-alexeyenko marked this conversation as resolved.
Show resolved Hide resolved
aggregatedPaths.push(
...item.personalize?.variantIds.map((varId) =>
formatPath(`/${segmentPrefix}${varId}${item.path}`)
)
);
}
});

return aggregatedPaths;
});
})
);
Expand Down
29 changes: 0 additions & 29 deletions packages/sitecore-jss-nextjs/src/testData/sitemapQueryResult.json

This file was deleted.