Skip to content

Commit

Permalink
fix: gracefully handle broken backlinks suggestion error
Browse files Browse the repository at this point in the history
  • Loading branch information
dzehnder committed Aug 5, 2024
1 parent 468e7ee commit 9123d43
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/backlinks/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,24 @@ export default async function auditBrokenBacklinks(message, context) {
const filteredBacklinks = result?.backlinks?.filter(
(backlink) => !excludedURLs?.includes(backlink.url_to),
);
const brokenBacklinks = await filterOutValidBacklinks(filteredBacklinks, log);
let brokenBacklinks = await filterOutValidBacklinks(filteredBacklinks, log);
try {
const topPages = await dataAccess.getTopPagesForSite(siteId, 'ahrefs', 'global');
const keywords = topPages.map(
(page) => ({
url: page.getURL(),
keyword: page.getTopKeyword(),
traffic: page.getTraffic(),
}),
);
brokenBacklinks = enhanceBacklinksWithFixes(brokenBacklinks, keywords, log);
} catch (e) {
log.error(`Enhancing backlinks with fixes for siteId ${siteId} failed with error: ${e.message}`, e);
}

const topPages = await dataAccess.getTopPagesForSite(siteId, 'ahrefs', 'global');
const keywords = topPages.map(
(page) => (
{ url: page.getURL(), keyword: page.getTopKeyword(), traffic: page.getTraffic() }
),
);
const enhancedBacklinks = enhanceBacklinksWithFixes(brokenBacklinks, keywords, log);
auditResult = {
finalUrl: auditContext.finalUrl,
brokenBacklinks: enhancedBacklinks,
brokenBacklinks,
fullAuditRef,
};
} catch (e) {
Expand Down
50 changes: 50 additions & 0 deletions test/audits/backlinks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,56 @@ describe('Backlinks Tests', function () {
.calledWith(context.env.AUDIT_RESULTS_QUEUE_URL, expectedMessage);
});

it('should detect broken backlinks and save the proper audit result, even if the suggested fix fails', async () => {
mockDataAccess.getSiteByID = sinon.stub().withArgs('site1').resolves(site);
mockDataAccess.getTopPagesForSite.resolves([createSiteTopPage({
siteId: site.getId(),
url: `${site.getBaseURL()}/foo.html`,
traffic: 1000,
source: 'ahrefs',
geo: 'global',
importedAt: new Date('2024-06-18').toISOString(),
topKeyword: 'c++',
})]);
const brokenBacklink = {
backlinks: [
{
title: 'backlink that has a faulty path',
url_from: 'https://from.com/from-1',
url_to: 'https://foo.com/c++',
domain_traffic: 4000,
}],
};
mockDataAccess.getConfiguration = sinon.stub().resolves(configuration);
nock(site.getBaseURL())
.get(/.*/)
.reply(200);

nock('https://ahrefs.com')
.get(/.*/)
.reply(200, brokenBacklink);

const expectedMessage = {
type: message.type,
url: site.getBaseURL(),
auditContext: {
finalUrl: 'bar.foo.com',
},
auditResult: {
finalUrl: 'bar.foo.com',
brokenBacklinks: brokenBacklink.backlinks,
fullAuditRef: 'https://ahrefs.com/site-explorer/broken-backlinks?select=title%2Curl_from%2Curl_to%2Ctraffic_domain&limit=50&mode=prefix&order_by=domain_rating_source%3Adesc%2Ctraffic_domain%3Adesc&target=bar.foo.com&output=json&where=%7B%22and%22%3A%5B%7B%22field%22%3A%22is_dofollow%22%2C%22is%22%3A%5B%22eq%22%2C1%5D%7D%2C%7B%22field%22%3A%22is_content%22%2C%22is%22%3A%5B%22eq%22%2C1%5D%7D%2C%7B%22field%22%3A%22domain_rating_source%22%2C%22is%22%3A%5B%22gte%22%2C29.5%5D%7D%2C%7B%22field%22%3A%22traffic_domain%22%2C%22is%22%3A%5B%22gte%22%2C500%5D%7D%2C%7B%22field%22%3A%22links_external%22%2C%22is%22%3A%5B%22lte%22%2C300%5D%7D%5D%7D',
},
};
const response = await auditBrokenBacklinks(message, context);

expect(response.status).to.equal(204);
expect(mockDataAccess.addAudit).to.have.been.calledOnce;
expect(context.sqs.sendMessage).to.have.been.calledOnce;
expect(context.sqs.sendMessage).to.have.been
.calledWith(context.env.AUDIT_RESULTS_QUEUE_URL, expectedMessage);
});

it('should successfully perform an audit to detect broken backlinks and set finalUrl, for baseUrl redirecting to www domain', async () => {
mockDataAccess.getSiteByID = sinon.stub().withArgs('site2').resolves(site2);
mockDataAccess.getTopPagesForSite.resolves([]);
Expand Down

0 comments on commit 9123d43

Please sign in to comment.