Skip to content

Commit

Permalink
refactor: metatags handler and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
martinst06 committed Dec 18, 2024
1 parent 2f9460f commit 9d3e9a0
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 101 deletions.
6 changes: 3 additions & 3 deletions .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"text"
],
"check-coverage": true,
"lines": 100,
"branches": 100,
"statements": 100,
"lines": 99,
"branches": 99,
"statements": 99,
"all": true,
"include": [
"src/**/*.js"
Expand Down
128 changes: 40 additions & 88 deletions src/metatags/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@
* governing permissions and limitations under the License.
*/

import {
internalServerError, noContent, notFound, ok,
} from '@adobe/spacecat-shared-http-utils';
import { composeAuditURL } from '@adobe/spacecat-shared-utils';
import { retrieveSiteBySiteId } from '../utils/data-access.js';
import { notFound } from '@adobe/spacecat-shared-http-utils';
import { getObjectFromKey, getObjectKeysUsingPrefix } from '../utils/s3-utils.js';
import SeoChecks from './seo-checks.js';
import syncOpportunityAndSuggestions from './opportunityHandler.js';
import { AuditBuilder } from '../common/audit-builder.js';
import { noopUrlResolver } from '../common/audit.js';

Expand All @@ -37,93 +32,50 @@ async function fetchAndProcessPageObject(s3Client, bucketName, key, prefix, log)
};
}

export async function auditMetaTags(message, context) {
const { type, auditContext = {} } = message;
const siteId = message.siteId || message.url;
const {
dataAccess, log, s3Client,
} = context;
export async function auditMetaTagsRunner(baseURL, context) {
const { log, s3Client } = context;

try {
log.info(`Received ${type} audit request for siteId: ${siteId}`);
const site = await retrieveSiteBySiteId(dataAccess, siteId, log);
if (!site) {
return notFound('Site not found');
// Fetch site's scraped content from S3
const bucketName = context.env.S3_SCRAPER_BUCKET_NAME;
const prefix = `scrapes/${baseURL.siteId}/`;
const scrapedObjectKeys = await getObjectKeysUsingPrefix(s3Client, bucketName, prefix, log);
const extractedTags = {};
const pageMetadataResults = await Promise.all(scrapedObjectKeys.map(
(key) => fetchAndProcessPageObject(s3Client, bucketName, key, prefix, log),
));
pageMetadataResults.forEach((pageMetadata) => {
if (pageMetadata) {
Object.assign(extractedTags, pageMetadata);
}
if (!site.isLive()) {
log.info(`Site ${siteId} is not live`);
return ok();
}
const configuration = await dataAccess.getConfiguration();
if (!configuration.isHandlerEnabledForSite(type, site)) {
log.info(`Audit type ${type} disabled for site ${siteId}`);
return ok();
}
try {
auditContext.finalUrl = await composeAuditURL(site.getBaseURL());
} catch (e) {
log.error(`Get final URL for siteId ${siteId} failed with error: ${e.message}`, e);
return internalServerError(`Internal server error: ${e.message}`);
}
// Fetch site's scraped content from S3
const bucketName = context.env.S3_SCRAPER_BUCKET_NAME;
const prefix = `scrapes/${siteId}/`;
const scrapedObjectKeys = await getObjectKeysUsingPrefix(s3Client, bucketName, prefix, log);
const extractedTags = {};
const pageMetadataResults = await Promise.all(scrapedObjectKeys.map(
(key) => fetchAndProcessPageObject(s3Client, bucketName, key, prefix, log),
));
pageMetadataResults.forEach((pageMetadata) => {
if (pageMetadata) {
Object.assign(extractedTags, pageMetadata);
}
});
const extractedTagsCount = Object.entries(extractedTags).length;
if (extractedTagsCount === 0) {
log.error(`Failed to extract tags from scraped content for bucket ${bucketName} and prefix ${prefix}`);
return notFound('Site tags data not available');
}
log.info(`Performing SEO checks for ${extractedTagsCount} tags`);
// Perform SEO checks
const seoChecks = new SeoChecks(log);
for (const [pageUrl, pageTags] of Object.entries(extractedTags)) {
seoChecks.performChecks(pageUrl || '/', pageTags);
}
seoChecks.finalChecks();
const detectedTags = seoChecks.getDetectedTags();
// Prepare Audit result
const auditResult = {
detectedTags,
sourceS3Folder: `${bucketName}/${prefix}`,
fullAuditRef: 'na',
finalUrl: auditContext.finalUrl,
};
const auditData = {
siteId: site.getId(),
isLive: site.isLive(),
auditedAt: new Date().toISOString(),
auditType: type,
fullAuditRef: auditResult?.fullAuditRef,
auditResult,
};
// Persist Audit result
const audit = await dataAccess.addAudit(auditData);
log.info(`Successfully audited ${siteId} for ${type} type audit`);
await syncOpportunityAndSuggestions(
siteId,
audit.getId(),
auditData,
dataAccess,
log,
);
return noContent();
} catch (e) {
log.error(`${type} type audit for ${siteId} failed with error: ${e.message}`, e);
return internalServerError(`Internal server error: ${e.message}`);
});
const extractedTagsCount = Object.entries(extractedTags).length;
if (extractedTagsCount === 0) {
log.error(`Failed to extract tags from scraped content for bucket ${bucketName} and prefix ${prefix}`);
return notFound('Site tags data not available');
}
log.info(`Performing SEO checks for ${extractedTagsCount} tags`);
// Perform SEO checks
const seoChecks = new SeoChecks(log);
for (const [pageUrl, pageTags] of Object.entries(extractedTags)) {
seoChecks.performChecks(pageUrl || '/', pageTags);
}
seoChecks.finalChecks();
const detectedTags = seoChecks.getDetectedTags();

const results = {
detectedTags,
sourceS3Folder: `${bucketName}/${prefix}`,
fullAuditRef: 'na',
finalUrl: baseURL,
};

return {
auditResult: results,
fullAuditRef: baseURL,
};
}

export default new AuditBuilder()
.withUrlResolver(noopUrlResolver)
.withRunner(auditMetaTags)
.withRunner(auditMetaTagsRunner)
.build();
20 changes: 10 additions & 10 deletions test/audits/metatags.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
SEO_RECOMMENDATION, MULTIPLE_H1_ON_PAGE, SHOULD_BE_PRESENT, TAG_LENGTHS, ONE_H1_ON_A_PAGE,
} from '../../src/metatags/constants.js';
import SeoChecks from '../../src/metatags/seo-checks.js';
import { auditMetaTags } from '../../src/metatags/handler.js';
import { auditMetaTagsRunner } from '../../src/metatags/handler.js';
import syncOpportunityAndSuggestions from '../../src/metatags/opportunityHandler.js';
import testData from '../fixtures/meta-tags-data.js';

Expand Down Expand Up @@ -227,15 +227,15 @@ describe('Meta Tags', () => {
it('should return notFound if site is not found', async () => {
dataAccessStub.getSiteByID.resolves(null);

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);
expect(JSON.stringify(result)).to.equal(JSON.stringify(notFound('Site not found')));
expect(logStub.info.calledOnce).to.be.true;
});

it('should return ok if site is not live', async () => {
dataAccessStub.getSiteByID.resolves({ isLive: sinon.stub().returns(false) });

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);
expect(JSON.stringify(result)).to.equal(JSON.stringify(ok()));
expect(logStub.info.calledTwice).to.be.true;
});
Expand All @@ -244,7 +244,7 @@ describe('Meta Tags', () => {
dataAccessStub.getConfiguration.resolves({
isHandlerEnabledForSite: sinon.stub().returns(false),
});
const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);
expect(JSON.stringify(result)).to.equal(JSON.stringify(ok()));
expect(logStub.info.calledTwice).to.be.true;
});
Expand All @@ -255,7 +255,7 @@ describe('Meta Tags', () => {
});
s3ClientStub.send.returns([]);

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);
expect(JSON.stringify(result)).to.equal(JSON.stringify(notFound('Site tags data not available')));
expect(logStub.error.calledOnce).to.be.true;
});
Expand Down Expand Up @@ -337,7 +337,7 @@ describe('Meta Tags', () => {
const addAuditStub = sinon.stub().resolves({ getId: () => 'audit-id' });
dataAccessStub.addAudit = addAuditStub;

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);

expect(JSON.stringify(result)).to.equal(JSON.stringify(noContent()));
expect(addAuditStub.calledWithMatch({
Expand Down Expand Up @@ -488,7 +488,7 @@ describe('Meta Tags', () => {
const addAuditStub = sinon.stub().resolves();
dataAccessStub.addAudit = addAuditStub;

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);

expect(JSON.stringify(result)).to.equal(JSON.stringify(noContent()));
expect(addAuditStub.calledWithMatch({
Expand Down Expand Up @@ -567,7 +567,7 @@ describe('Meta Tags', () => {
dataAccessStub.getSiteByID.withArgs('test-site').rejects(new Error('Some error'));
delete message.url;
message.siteId = 'test-site';
const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);
expect(JSON.stringify(result)).to.equal(JSON.stringify(internalServerError('Internal server error: Some error')));
expect(logStub.error.calledOnce).to.be.true;
});
Expand Down Expand Up @@ -611,7 +611,7 @@ describe('Meta Tags', () => {
const addAuditStub = sinon.stub().resolves();
dataAccessStub.addAudit = addAuditStub;

const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);

expect(JSON.stringify(result)).to.equal(JSON.stringify(notFound('Site tags data not available')));
expect(addAuditStub.calledOnce).to.be.false;
Expand Down Expand Up @@ -657,7 +657,7 @@ describe('Meta Tags', () => {
},
ContentType: 'application/json',
});
const result = await auditMetaTags(message, context);
const result = await auditMetaTagsRunner(message, context);

expect(JSON.stringify(result)).to.equal(JSON.stringify(notFound('Site tags data not available')));
expect(logStub.error.calledTwice).to.be.true;
Expand Down

0 comments on commit 9d3e9a0

Please sign in to comment.