Skip to content

Commit 22388c6

Browse files
rpapaniclaude
andauthored
feat: rename ahrefs references to seo in opportunity status processor (#246)
Part of the Ahrefs → SEO data provider migration. - Rename dependency key `AHREFSImport` → `SEOImport` in opportunity dependency map - Rename `isAHREFSImportDataAvailable` → `isSEOImportDataAvailable` - Update SiteTopPage query source from `'ahrefs'` to `'seo'` - Update all variable names, Slack messages, and response object keys - Update all test assertions and fixtures Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 134bc9e commit 22388c6

File tree

5 files changed

+68
-68
lines changed

5 files changed

+68
-68
lines changed

src/tasks/opportunity-status-processor/handler.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,25 @@ async function isRUMAvailable(domain, context) {
4747
}
4848

4949
/**
50-
* Checks if AHREFSImport data is available by checking if top pages exist for the site
50+
* Checks if SEO import data is available by checking if top pages exist for the site
5151
* @param {string} siteId - The site ID to check
5252
* @param {object} dataAccess - The data access object
5353
* @param {object} context - The context object with log
54-
* @returns {Promise<boolean>} True if AHREFS Import data is available, false otherwise
54+
* @returns {Promise<boolean>} True if SEO import data is available, false otherwise
5555
*/
56-
async function isAHREFSImportDataAvailable(siteId, dataAccess, context) {
56+
async function isSEOImportDataAvailable(siteId, dataAccess, context) {
5757
const { log } = context;
5858
const { SiteTopPage } = dataAccess;
5959

6060
try {
61-
const topPages = await SiteTopPage.allBySiteIdAndSourceAndGeo(siteId, 'ahrefs', 'global');
61+
const topPages = await SiteTopPage.allBySiteIdAndSourceAndGeo(siteId, 'seo', 'global');
6262

6363
const hasData = topPages && topPages.length > 0;
64-
log.info(`AHREFS Import data availability for site ${siteId}: ${hasData ? 'Available' : 'Not available'} (${topPages?.length || 0} top pages)`);
64+
log.info(`SEO Import data availability for site ${siteId}: ${hasData ? 'Available' : 'Not available'} (${topPages?.length || 0} top pages)`);
6565

6666
return hasData;
6767
} catch (error) {
68-
log.error(`Error checking AHREFS Import data availability for site ${siteId}: ${error.message}`);
68+
log.error(`Error checking SEO Import data availability for site ${siteId}: ${error.message}`);
6969
return false;
7070
}
7171
}
@@ -304,8 +304,8 @@ async function analyzeMissingOpportunities(
304304
for (const dep of dependencies) {
305305
if (dep === 'RUM' && !serviceStatus.rum) {
306306
unmetDeps.push('RUM');
307-
} else if (dep === 'AHREFSImport' && !serviceStatus.ahrefsImport) {
308-
unmetDeps.push('AHREFS Import');
307+
} else if (dep === 'SEOImport' && !serviceStatus.seoImport) {
308+
unmetDeps.push('SEO Import');
309309
} else if (dep === 'scraping' && !serviceStatus.scraping) {
310310
unmetDeps.push('Scraping');
311311
}
@@ -376,7 +376,7 @@ export async function runOpportunityStatusProcessor(message, context) {
376376

377377
// Check data source availability and service preconditions
378378
let rumAvailable = false;
379-
let ahrefsImportAvailable = false;
379+
let seoImportAvailable = false;
380380
let gscConfigured = false;
381381
let scrapingAvailable = false;
382382

@@ -406,7 +406,7 @@ export async function runOpportunityStatusProcessor(message, context) {
406406
});
407407

408408
const needsRUM = requiredDependencies.has('RUM');
409-
const needsAHREFSImport = requiredDependencies.has('AHREFSImport');
409+
const needsSEOImport = requiredDependencies.has('SEOImport');
410410
const needsScraping = requiredDependencies.has('scraping');
411411
const needsGSC = requiredDependencies.has('GSC');
412412

@@ -506,14 +506,14 @@ export async function runOpportunityStatusProcessor(message, context) {
506506
}
507507
}
508508

509-
if (needsAHREFSImport) {
510-
ahrefsImportAvailable = await isAHREFSImportDataAvailable(siteId, dataAccess, context);
509+
if (needsSEOImport) {
510+
seoImportAvailable = await isSEOImportDataAvailable(siteId, dataAccess, context);
511511
}
512512

513513
// Determine service status for dependency checking
514514
const serviceStatus = {
515515
rum: rumAvailable,
516-
ahrefsImport: ahrefsImportAvailable,
516+
seoImport: seoImportAvailable,
517517
gsc: gscConfigured,
518518
scraping: scrapingAvailable,
519519
};
@@ -549,12 +549,12 @@ export async function runOpportunityStatusProcessor(message, context) {
549549

550550
// Data source and service precondition status
551551
const rumStatus = rumAvailable ? ':white_check_mark:' : ':x:';
552-
const ahrefsImportStatus = ahrefsImportAvailable ? ':white_check_mark:' : ':x:';
552+
const seoImportStatus = seoImportAvailable ? ':white_check_mark:' : ':x:';
553553
const gscStatus = gscConfigured ? ':white_check_mark:' : ':x:';
554554
const scrapingStatus = scrapingAvailable ? ':white_check_mark:' : ':x:';
555555

556556
statusMessages.push(`RUM ${rumStatus}`);
557-
statusMessages.push(`AHREFS Import ${ahrefsImportStatus}`);
557+
statusMessages.push(`SEO Import ${seoImportStatus}`);
558558
statusMessages.push(`GSC ${gscStatus}`);
559559
statusMessages.push(`Scraping ${scrapingStatus}`);
560560

@@ -614,8 +614,8 @@ export async function runOpportunityStatusProcessor(message, context) {
614614
if (needsRUM) {
615615
dataSourceMessages.push(`RUM ${rumAvailable ? ':white_check_mark:' : ':x:'}`);
616616
}
617-
if (needsAHREFSImport) {
618-
dataSourceMessages.push(`AHREFS Import ${ahrefsImportAvailable ? ':white_check_mark:' : ':x:'}`);
617+
if (needsSEOImport) {
618+
dataSourceMessages.push(`SEO Import ${seoImportAvailable ? ':white_check_mark:' : ':x:'}`);
619619
}
620620
if (needsGSC) {
621621
dataSourceMessages.push(`GSC ${gscConfigured ? ':white_check_mark:' : ':x:'}`);
@@ -635,7 +635,7 @@ export async function runOpportunityStatusProcessor(message, context) {
635635
await say(env, log, slackContext, `*Opportunity Statuses for site ${siteUrl}*`);
636636
const opportunityMessages = statusMessages.filter(
637637
(msg) => !msg.includes('RUM')
638-
&& !msg.includes('AHREFS Import')
638+
&& !msg.includes('SEO Import')
639639
&& !msg.includes('GSC')
640640
&& !msg.includes('Scraping'),
641641
);
@@ -690,11 +690,11 @@ export async function runOpportunityStatusProcessor(message, context) {
690690
opportunitiesProcessed: opportunities.length,
691691
dataSources: {
692692
rum: rumAvailable,
693-
ahrefsImport: ahrefsImportAvailable,
693+
seoImport: seoImportAvailable,
694694
gsc: gscConfigured,
695695
},
696696
servicePreconditions: {
697-
import: ahrefsImportAvailable, // Import and AHREFS are the same
697+
import: seoImportAvailable,
698698
scraping: scrapingAvailable,
699699
},
700700
};

src/tasks/opportunity-status-processor/opportunity-dependency-map.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212

1313
/**
1414
* Maps opportunity types to their required dependencies
15-
* Dependencies can be data sources (RUM, AHREFSImport, GSC, scraping)
15+
* Dependencies can be data sources (RUM, SEOImport, GSC, scraping)
1616
*
1717
* Key: Opportunity type
1818
* Value: Array of required dependencies for this opportunity to be generated
1919
*/
2020
export const OPPORTUNITY_DEPENDENCY_MAP = {
2121
cwv: ['RUM'],
2222
'high-organic-low-ctr': ['RUM'],
23-
'broken-internal-links': ['RUM', 'AHREFSImport'],
24-
'meta-tags': ['AHREFSImport', 'scraping'], // meta-tags audit uses scraping
25-
'broken-backlinks': ['AHREFSImport', 'scraping'], // broken-backlinks audit uses scraping
26-
'alt-text': ['AHREFSImport', 'scraping'], // alt-text audit uses scraping
23+
'broken-internal-links': ['RUM', 'SEOImport'],
24+
'meta-tags': ['SEOImport', 'scraping'], // meta-tags audit uses scraping
25+
'broken-backlinks': ['SEOImport', 'scraping'], // broken-backlinks audit uses scraping
26+
'alt-text': ['SEOImport', 'scraping'], // alt-text audit uses scraping
2727
'form-accessibility': ['RUM', 'scraping'], // forms audit uses scraping
2828
'forms-opportunities': ['RUM', 'scraping'], // forms audit uses scraping
2929
};

test/tasks/disable-import-audit-processor/disable-import-audit-processor.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe('Disable Import Audit Processor', () => {
9292
siteUrl: 'https://example.com',
9393
organizationId: 'test-org-id',
9494
taskContext: {
95-
importTypes: ['ahrefs', 'screaming-frog'],
95+
importTypes: ['seo', 'screaming-frog'],
9696
auditTypes: ['cwv', 'broken-links'],
9797
slackContext: 'test-slack-context',
9898
},
@@ -113,7 +113,7 @@ describe('Disable Import Audit Processor', () => {
113113
taskType: 'disable-import-audit-processor',
114114
siteId: 'test-site-id',
115115
organizationId: 'test-org-id',
116-
importTypes: ['ahrefs', 'screaming-frog'],
116+
importTypes: ['seo', 'screaming-frog'],
117117
auditTypes: ['cwv', 'broken-links'],
118118
scheduledRun: false,
119119
});
@@ -123,7 +123,7 @@ describe('Disable Import Audit Processor', () => {
123123
expect(mockSite.getConfig).to.have.been.calledOnce;
124124

125125
// Verify import types were disabled
126-
expect(mockSiteConfig.disableImport).to.have.been.calledWith('ahrefs');
126+
expect(mockSiteConfig.disableImport).to.have.been.calledWith('seo');
127127
expect(mockSiteConfig.disableImport).to.have.been.calledWith('screaming-frog');
128128
expect(mockSiteConfig.disableImport).to.have.callCount(2);
129129

@@ -149,7 +149,7 @@ describe('Disable Import Audit Processor', () => {
149149
context.env,
150150
context.log,
151151
'test-slack-context',
152-
':broom: *For site: https://example.com: Disabled imports*: ahrefs, screaming-frog *and audits*: cwv, broken-links',
152+
':broom: *For site: https://example.com: Disabled imports*: seo, screaming-frog *and audits*: cwv, broken-links',
153153
);
154154
expect(mockSay.secondCall).to.have.been.calledWith(
155155
context.env,
@@ -240,7 +240,7 @@ describe('Disable Import Audit Processor', () => {
240240
taskType: 'disable-import-audit-processor',
241241
siteId: 'test-site-id',
242242
organizationId: 'test-org-id',
243-
importTypes: ['ahrefs', 'screaming-frog'],
243+
importTypes: ['seo', 'screaming-frog'],
244244
auditTypes: ['cwv', 'broken-links'],
245245
scheduledRun: true,
246246
});

test/tasks/opportunity-status-processor/opportunity-dependency-map.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ describe('Opportunity Dependency Map', () => {
3232
it('should map opportunities to dependencies correctly', () => {
3333
expect(OPPORTUNITY_DEPENDENCY_MAP.cwv).to.deep.equal(['RUM']);
3434
expect(OPPORTUNITY_DEPENDENCY_MAP['high-organic-low-ctr']).to.deep.equal(['RUM']);
35-
expect(OPPORTUNITY_DEPENDENCY_MAP['broken-internal-links']).to.deep.equal(['RUM', 'AHREFSImport']);
36-
expect(OPPORTUNITY_DEPENDENCY_MAP['meta-tags']).to.deep.equal(['AHREFSImport', 'scraping']);
37-
expect(OPPORTUNITY_DEPENDENCY_MAP['broken-backlinks']).to.deep.equal(['AHREFSImport', 'scraping']);
38-
expect(OPPORTUNITY_DEPENDENCY_MAP['alt-text']).to.deep.equal(['AHREFSImport', 'scraping']);
35+
expect(OPPORTUNITY_DEPENDENCY_MAP['broken-internal-links']).to.deep.equal(['RUM', 'SEOImport']);
36+
expect(OPPORTUNITY_DEPENDENCY_MAP['meta-tags']).to.deep.equal(['SEOImport', 'scraping']);
37+
expect(OPPORTUNITY_DEPENDENCY_MAP['broken-backlinks']).to.deep.equal(['SEOImport', 'scraping']);
38+
expect(OPPORTUNITY_DEPENDENCY_MAP['alt-text']).to.deep.equal(['SEOImport', 'scraping']);
3939
expect(OPPORTUNITY_DEPENDENCY_MAP['form-accessibility']).to.deep.equal(['RUM', 'scraping']);
4040
expect(OPPORTUNITY_DEPENDENCY_MAP['forms-opportunities']).to.deep.equal(['RUM', 'scraping']);
4141
});
@@ -53,7 +53,7 @@ describe('Opportunity Dependency Map', () => {
5353
expect(dependencies).to.be.an('array');
5454
expect(dependencies).to.have.lengthOf(2);
5555
expect(dependencies).to.include('RUM');
56-
expect(dependencies).to.include('AHREFSImport');
56+
expect(dependencies).to.include('SEOImport');
5757
});
5858

5959
it('should return empty array for opportunity with no dependencies', () => {

test/tasks/opportunity-status-processor/opportunity-status-processor.test.js

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,10 @@ describe('Opportunity Status Processor', () => {
300300
expect(mockSite.getOpportunities.called).to.be.true;
301301
});
302302

303-
it('should check AHREFS Import data availability', async () => {
304-
// Set audit type that requires AHREFSImport
303+
it('should check SEO Import data availability', async () => {
304+
// Set audit type that requires SEOImport
305305
message.taskContext.auditTypes = ['meta-tags'];
306-
// Mock AHREFSImport data available
306+
// Mock SEOImport data available
307307
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.resolves([
308308
{ url: 'https://example.com/page1', traffic: 100 },
309309
{ url: 'https://example.com/page2', traffic: 50 },
@@ -319,14 +319,14 @@ describe('Opportunity Status Processor', () => {
319319

320320
await runOpportunityStatusProcessor(message, context);
321321

322-
expect(context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.calledWith('test-site-id', 'ahrefs', 'global')).to.be.true;
323-
expect(context.log.info.calledWith('AHREFS Import data availability for site test-site-id: Available (2 top pages)')).to.be.true;
322+
expect(context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.calledWith('test-site-id', 'seo', 'global')).to.be.true;
323+
expect(context.log.info.calledWith('SEO Import data availability for site test-site-id: Available (2 top pages)')).to.be.true;
324324
});
325325

326-
it('should handle AHREFSImport data not available', async () => {
327-
// Set audit type that requires AHREFSImport
326+
it('should handle SEOImport data not available', async () => {
327+
// Set audit type that requires SEOImport
328328
message.taskContext.auditTypes = ['meta-tags'];
329-
// Mock AHREFSImport data not available
329+
// Mock SEOImport data not available
330330
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.resolves([]);
331331

332332
const mockOpportunities = [
@@ -339,13 +339,13 @@ describe('Opportunity Status Processor', () => {
339339

340340
await runOpportunityStatusProcessor(message, context);
341341

342-
expect(context.log.info.calledWith('AHREFS Import data availability for site test-site-id: Not available (0 top pages)')).to.be.true;
342+
expect(context.log.info.calledWith('SEO Import data availability for site test-site-id: Not available (0 top pages)')).to.be.true;
343343
});
344344

345-
it('should handle AHREFSImport check errors', async () => {
346-
// Set audit type that requires AHREFSImport
345+
it('should handle SEOImport check errors', async () => {
346+
// Set audit type that requires SEOImport
347347
message.taskContext.auditTypes = ['meta-tags'];
348-
// Mock AHREFSImport check error
348+
// Mock SEOImport check error
349349
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.rejects(new Error('Database error'));
350350

351351
const mockOpportunities = [
@@ -358,7 +358,7 @@ describe('Opportunity Status Processor', () => {
358358

359359
await runOpportunityStatusProcessor(message, context);
360360

361-
expect(context.log.error.calledWith('Error checking AHREFS Import data availability for site test-site-id: Database error')).to.be.true;
361+
expect(context.log.error.calledWith('Error checking SEO Import data availability for site test-site-id: Database error')).to.be.true;
362362
});
363363
});
364364

@@ -817,12 +817,12 @@ describe('Opportunity Status Processor', () => {
817817
expect(context.log.info.calledWithMatch('Processing opportunities')).to.be.true;
818818
});
819819

820-
it('should detect AHREFSImport failure from runbook', async () => {
820+
it('should detect SEOImport failure from runbook', async () => {
821821
const mockOpportunities = [
822822
{
823823
getType: () => 'seo',
824824
getSuggestions: sinon.stub().resolves([]),
825-
getData: () => ({ runbook: 'AHREFSImport data is required for this analysis' }),
825+
getData: () => ({ runbook: 'SEOImport data is required for this analysis' }),
826826
},
827827
];
828828
mockSite.getOpportunities.resolves(mockOpportunities);
@@ -1045,35 +1045,35 @@ describe('Opportunity Status Processor', () => {
10451045
});
10461046
});
10471047

1048-
describe('Import and AHREFSImport Checks', () => {
1049-
it('should handle AHREFSImport check errors gracefully', async () => {
1050-
// Set audit type that requires AHREFSImport
1048+
describe('Import and SEOImport Checks', () => {
1049+
it('should handle SEOImport check errors gracefully', async () => {
1050+
// Set audit type that requires SEOImport
10511051
message.taskContext.auditTypes = ['meta-tags'];
10521052
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo.rejects(new Error('Database error'));
10531053

10541054
await runOpportunityStatusProcessor(message, context);
10551055

1056-
expect(context.log.error.calledWithMatch('Error checking AHREFS Import data availability')).to.be.true;
1056+
expect(context.log.error.calledWithMatch('Error checking SEO Import data availability')).to.be.true;
10571057
});
10581058

1059-
it('should check AHREFSImport data with specific source and geo parameters', async () => {
1060-
// Set audit type that requires AHREFSImport
1059+
it('should check SEOImport data with specific source and geo parameters', async () => {
1060+
// Set audit type that requires SEOImport
10611061
message.taskContext.auditTypes = ['meta-tags'];
10621062
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
1063-
.withArgs('test-site-id', 'ahrefs', 'global')
1063+
.withArgs('test-site-id', 'seo', 'global')
10641064
.resolves([{ url: 'https://example.com/page1' }]);
10651065

10661066
await runOpportunityStatusProcessor(message, context);
10671067

10681068
expect(context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
1069-
.calledWith('test-site-id', 'ahrefs', 'global')).to.be.true;
1069+
.calledWith('test-site-id', 'seo', 'global')).to.be.true;
10701070
});
10711071

1072-
it('should log AHREFS Import data availability with page count', async () => {
1073-
// Set audit type that requires AHREFSImport
1072+
it('should log SEO Import data availability with page count', async () => {
1073+
// Set audit type that requires SEOImport
10741074
message.taskContext.auditTypes = ['meta-tags'];
10751075
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
1076-
.withArgs('test-site-id', 'ahrefs', 'global')
1076+
.withArgs('test-site-id', 'seo', 'global')
10771077
.resolves([
10781078
{ url: 'https://example.com/page1' },
10791079
{ url: 'https://example.com/page2' },
@@ -1082,7 +1082,7 @@ describe('Opportunity Status Processor', () => {
10821082

10831083
await runOpportunityStatusProcessor(message, context);
10841084

1085-
expect(context.log.info.calledWithMatch('AHREFS Import data availability')).to.be.true;
1085+
expect(context.log.info.calledWithMatch('SEO Import data availability')).to.be.true;
10861086
expect(context.log.info.calledWithMatch('3 top pages')).to.be.true;
10871087
});
10881088
});
@@ -1560,9 +1560,9 @@ describe('Opportunity Status Processor', () => {
15601560
};
15611561
message.taskContext.auditTypes = ['cwv', 'broken-backlinks'];
15621562

1563-
// Mock AHREFSImport and Import available
1563+
// Mock SEOImport and Import available
15641564
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
1565-
.withArgs(message.siteId, 'ahrefs', 'global')
1565+
.withArgs(message.siteId, 'seo', 'global')
15661566
.resolves([{ url: 'https://example.com/page1' }]);
15671567

15681568
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
@@ -1578,7 +1578,7 @@ describe('Opportunity Status Processor', () => {
15781578
{
15791579
getType: () => 'broken-backlinks',
15801580
getSuggestions: sinon.stub().resolves([]),
1581-
getData: () => ({ runbook: 'AHREFSImport data required' }),
1581+
getData: () => ({ runbook: 'SEOImport data required' }),
15821582
},
15831583
];
15841584
mockSite.getOpportunities.resolves(mockOpportunities);
@@ -1893,13 +1893,13 @@ describe('Opportunity Status Processor', () => {
18931893
threadTs: 'test-thread',
18941894
};
18951895

1896-
// Mock import and AHREFSImport as available
1896+
// Mock import and SEOImport as available
18971897
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo = sinon.stub();
18981898
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
18991899
.withArgs(message.siteId)
19001900
.resolves([{ url: 'https://example.com/page1' }]);
19011901
context.dataAccess.SiteTopPage.allBySiteIdAndSourceAndGeo
1902-
.withArgs(message.siteId, 'ahrefs', 'global')
1902+
.withArgs(message.siteId, 'seo', 'global')
19031903
.resolves([{ url: 'https://example.com/page1', traffic: 1000 }]);
19041904

19051905
const mockOpportunities = [
@@ -1912,7 +1912,7 @@ describe('Opportunity Status Processor', () => {
19121912

19131913
await runOpportunityStatusProcessor(message, context);
19141914

1915-
// When no siteUrl, RUM/GSC/Scraping are false, but AHREFSImport and Import are true
1915+
// When no siteUrl, RUM/GSC/Scraping are false, but SEOImport and Import are true
19161916
// This will trigger "Services requiring log analysis" log,
19171917
// not "All service preconditions passed"
19181918
// The test verifies the function executes without errors

0 commit comments

Comments
 (0)