Skip to content

Commit

Permalink
fix: rename to pdp-indexability
Browse files Browse the repository at this point in the history
  • Loading branch information
dzehnder committed Aug 19, 2024
1 parent 2d048db commit 42a9dbf
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 98 deletions.
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import experimentation from './experimentation/handler.js';
import conversion from './conversion/handler.js';
import essExperimentationDaily from './experimentation-ess/daily.js';
import essExperimentationAll from './experimentation-ess/all.js';
import pdpIndexability from './url-inspect/pdp-handler.js';

const HANDLERS = {
apex,
Expand All @@ -43,6 +44,7 @@ const HANDLERS = {
conversion,
'experimentation-ess-daily': essExperimentationDaily,
'experimentation-ess-all': essExperimentationAll,
'pdp-indexability': pdpIndexability,
};

function getElapsedSeconds(startTime) {
Expand Down
34 changes: 17 additions & 17 deletions src/urlInspect/handler.js → src/url-inspect/pdp-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import GoogleClient from '@adobe/spacecat-shared-google-client';
import { AuditBuilder } from '../common/audit-builder.js';

/**
* Processes an audit of the top pages of a site using Google's URL inspection tool.
* Processes an audit of the product detail pages of a site using Google's URL inspection tool.
*
* @async
* @function
Expand All @@ -28,21 +28,21 @@ import { AuditBuilder } from '../common/audit-builder.js';
* @throws {Error} - Throws an error if the audit process fails.
*/
async function processAudit(baseURL, context, site) {
const { dataAccess, log } = context;
const { log } = context;
const siteId = site.getId();

const topPages = await dataAccess.getTopPagesForSite(siteId, 'ahrefs', 'global');
if (!topPages || topPages.length === 0) {
log.warn(`No top pages found for site ID: ${siteId}`);
return [];
const productDetailPages = await site.getConfig().getProductDetailPages('pdp-indexability');
if (!productDetailPages || productDetailPages.length === 0) {
log.error(`No top pages found for site ID: ${siteId}`);
throw new Error(`No top pages found for site: ${baseURL}`);
}

const google = GoogleClient.createFrom(context, baseURL);

const urlInspectionResult = topPages.map(async (page) => {
const urlInspectionResult = productDetailPages.map(async (pdp) => {
try {
const { inspectionResult } = await google.urlInspect(page.url);
log.info(`Successfully inspected URL: ${page.url}`);
const { inspectionResult } = await google.urlInspect(pdp);
log.info(`Successfully inspected URL: ${pdp}`);

const filteredIndexStatusResult = {
verdict: inspectionResult.indexStatusResult.verdict,
Expand All @@ -69,20 +69,20 @@ async function processAudit(baseURL, context, site) {

if (filteredRichResults.length > 0) {
filteredRichResults.verdict = inspectionResult.richResultsResult.verdict;
log.info(`Found ${filteredRichResults.length} rich results issues for URL: ${page.url}`);
log.info(`Found ${filteredRichResults.length} rich results issues for URL: ${pdp}`);
} else {
log.info(`No rich results issues found for URL: ${page.url}`);
log.info(`No rich results issues found for URL: ${pdp}`);
}

return {
inspectionUrl: page.url,
inspectionUrl: pdp,
indexStatusResult: filteredIndexStatusResult,
richResults: filteredRichResults,
};
} catch (error) {
log.error(`Failed to inspect URL: ${page.url}. Error: ${error.message}`);
log.error(`Failed to inspect URL: ${pdp}. Error: ${error.message}`);
return {
inspectionUrl: page.url,
inspectionUrl: pdp,
error: error.message,
};
}
Expand All @@ -91,9 +91,9 @@ async function processAudit(baseURL, context, site) {
return Promise.all(urlInspectionResult);
}

export async function urlInspectRunner(baseURL, context, site) {
export async function pdpIndexabilityRunner(baseURL, context, site) {
const { log } = context;
log.info(`Received URL Inspect audit request for ${baseURL}`);
log.info(`Received Product Detail Page indexability audit request for ${baseURL}`);
const startTime = process.hrtime();

const auditResult = await processAudit(baseURL, context, site);
Expand All @@ -111,6 +111,6 @@ export async function urlInspectRunner(baseURL, context, site) {
}

export default new AuditBuilder()
.withRunner(urlInspectRunner)
.withRunner(pdpIndexabilityRunner)
.withUrlResolver((site) => site.getBaseURL())
.build();
171 changes: 90 additions & 81 deletions test/audits/urlInspect.test.js → test/audits/pdp.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,95 +15,27 @@ import chai from 'chai';
import sinonChai from 'sinon-chai';
import sinon from 'sinon';
import GoogleClient from '@adobe/spacecat-shared-google-client';
import { urlInspectRunner } from '../../src/urlInspect/handler.js';
import { pdpIndexabilityRunner } from '../../src/url-inspect/pdp-handler.js';

chai.use(sinonChai);
const { expect } = chai;
const sandbox = sinon.createSandbox();

describe('URLInspect Audit', () => {
let context;
let dataAccess;
let googleClientStub;
let urlInspectStub;
let siteStub;

const fullUrlInspectionResult = {
inspectionResult: {
inspectionResultLink: 'https://search.google.com/search-console/inspect?resource_id=https://www.example.com/',
indexStatusResult: {
verdict: 'PASS',
coverageState: 'Submitted and indexed',
robotsTxtState: 'ALLOWED',
indexingState: 'INDEXING_ALLOWED',
lastCrawlTime: '2024-08-13T22:35:22Z',
pageFetchState: 'SUCCESSFUL',
googleCanonical: 'https://www.example.com/foo',
userCanonical: 'https://www.example.com/foo',
referringUrls: [
'https://www.example.com/bar',
],
crawledAs: 'MOBILE',
},
mobileUsabilityResult: {
verdict: 'VERDICT_UNSPECIFIED',
},
richResultsResult: {
verdict: 'PASS',
detectedItems: [
{
richResultType: 'Product snippets',
items: [
{
name: 'Example Product Name',
issues: [
{
issueMessage: 'Missing field "image"',
severity: 'ERROR',
},
],
},
],
},
{
richResultType: 'Merchant listings',
items: [
{
name: 'Example Product Name',
issues: [
{
issueMessage: 'Missing field "hasMerchantReturnPolicy"',
severity: 'WARNING',
},
{
issueMessage: 'Missing field "shippingDetails"',
severity: 'ERROR',
},
],
},
],
},
],
},
},
};

const topPages = [
{ url: 'https://example.com/foo' },
{ url: 'https://example.com/bar' },
];
let fullUrlInspectionResult;

beforeEach(() => {
dataAccess = {
getTopPagesForSite: sinon.stub(),
};
context = {
log: {
info: sinon.stub(),
warn: sinon.stub(),
error: sinon.stub(),
},
dataAccess,
};

googleClientStub = {
Expand All @@ -113,6 +45,69 @@ describe('URLInspect Audit', () => {
urlInspectStub = googleClientStub.urlInspect;
siteStub = {
getId: () => '123',
getConfig: () => ({
getProductDetailPages: () => ['https://example.com/product/1', 'https://example.com/product/2'],
}),
};

fullUrlInspectionResult = {
inspectionResult: {
inspectionResultLink: 'https://search.google.com/search-console/inspect?resource_id=https://www.example.com/',
indexStatusResult: {
verdict: 'PASS',
coverageState: 'Submitted and indexed',
robotsTxtState: 'ALLOWED',
indexingState: 'INDEXING_ALLOWED',
lastCrawlTime: '2024-08-13T22:35:22Z',
pageFetchState: 'SUCCESSFUL',
googleCanonical: 'https://www.example.com/foo',
userCanonical: 'https://www.example.com/foo',
referringUrls: [
'https://www.example.com/bar',
],
crawledAs: 'MOBILE',
},
mobileUsabilityResult: {
verdict: 'VERDICT_UNSPECIFIED',
},
richResultsResult: {
verdict: 'PASS',
detectedItems: [
{
richResultType: 'Product snippets',
items: [
{
name: 'Example Product Name',
issues: [
{
issueMessage: 'Missing field "image"',
severity: 'ERROR',
},
],
},
],
},
{
richResultType: 'Merchant listings',
items: [
{
name: 'Example Product Name',
issues: [
{
issueMessage: 'Missing field "hasMerchantReturnPolicy"',
severity: 'WARNING',
},
{
issueMessage: 'Missing field "shippingDetails"',
severity: 'ERROR',
},
],
},
],
},
],
},
},
};
});

Expand All @@ -121,16 +116,14 @@ describe('URLInspect Audit', () => {
});

it('should successfully return a filtered result of the url inspection result', async () => {
dataAccess.getTopPagesForSite.resolves(topPages);

urlInspectStub.resolves(fullUrlInspectionResult);

const auditData = await urlInspectRunner('https://www.example.com', context, siteStub);
const auditData = await pdpIndexabilityRunner('https://www.example.com', context, siteStub);

expect(auditData.auditResult).to.deep.equal(
[
{
inspectionUrl: 'https://example.com/foo',
inspectionUrl: 'https://example.com/product/1',
indexStatusResult: {
verdict: fullUrlInspectionResult.inspectionResult.indexStatusResult.verdict,
lastCrawlTime: fullUrlInspectionResult.inspectionResult.indexStatusResult.lastCrawlTime,
Expand Down Expand Up @@ -179,7 +172,7 @@ describe('URLInspect Audit', () => {
],
},
{
inspectionUrl: 'https://example.com/bar',
inspectionUrl: 'https://example.com/product/2',
indexStatusResult: {
verdict: fullUrlInspectionResult.inspectionResult.indexStatusResult.verdict,
lastCrawlTime: fullUrlInspectionResult.inspectionResult.indexStatusResult.lastCrawlTime,
Expand Down Expand Up @@ -232,19 +225,35 @@ describe('URLInspect Audit', () => {
});

it('returns no rich results when there are no rich results errors', async () => {
dataAccess.getTopPagesForSite.resolves(topPages);
delete fullUrlInspectionResult.inspectionResult.richResultsResult;
urlInspectStub.resolves(fullUrlInspectionResult);

const auditData = await urlInspectRunner('https://www.example.com', context, siteStub);
const auditData = await pdpIndexabilityRunner('https://www.example.com', context, siteStub);

expect(auditData.auditResult[0].richResults).to.equal(undefined);
});

it('returns an empty array if there are no top pages', async () => {
dataAccess.getTopPagesForSite.resolves([]);
it('returns no rich results when there are no errors in rich results', async () => {
fullUrlInspectionResult.inspectionResult
.richResultsResult.detectedItems[0].items[0].issues = [];
delete fullUrlInspectionResult.inspectionResult
.richResultsResult.detectedItems[1].items[0].issues[1];
urlInspectStub.resolves(fullUrlInspectionResult);

const auditData = await urlInspectRunner('https://www.example.com', context, siteStub);
const auditData = await pdpIndexabilityRunner('https://www.example.com', context, siteStub);

expect(auditData.auditResult[0].richResults).to.deep.equal([]);
expect(auditData.auditResult[1].richResults).to.deep.equal([]);
});

expect(auditData.auditResult).to.deep.equal([]);
it('throws error if there are no configured PDPs', async () => {
siteStub.getConfig = () => ({
getProductDetailPages: () => [],
});
try {
await pdpIndexabilityRunner('https://www.example.com', context, siteStub);
} catch (error) {
expect(error.message).to.equal('No top pages found for site: https://www.example.com');
}
});
});

0 comments on commit 42a9dbf

Please sign in to comment.