Skip to content

Commit

Permalink
feat: high bounce rate and low ctr opportunities (#384)
Browse files Browse the repository at this point in the history
* feat: high bounce rate and low ctr opportunities

* feat: high bounce rate and low ctr opportunities

* fix(exp-opportunities): bump the rumapi client version and rename the audit

* fix(exp-opportunities): centralize wwwUrlResolver

* fix(exp-opportunities): package-lock.json
  • Loading branch information
ekremney committed Sep 3, 2024
1 parent c79e6b3 commit 33aa025
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 83 deletions.
18 changes: 2 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion src/common/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
* governing permissions and limitations under the License.
*/

import { composeAuditURL } from '@adobe/spacecat-shared-utils';
import { composeAuditURL, hasText } from '@adobe/spacecat-shared-utils';
import { ok } from '@adobe/spacecat-shared-http-utils';
import URI from 'urijs';
import { retrieveSiteBySiteId } from '../utils/data-access.js';

export async function defaultMessageSender(resultMessage, context) {
Expand Down Expand Up @@ -52,6 +53,12 @@ export async function defaultUrlResolver(site) {
return composeAuditURL(site.getBaseURL());
}

export function wwwUrlResolver(site) {
const baseURL = site.getBaseURL();
const uri = new URI(baseURL);
return hasText(uri.subdomain()) ? baseURL.replace(/https?:\/\//, '') : baseURL.replace(/https?:\/\//, 'www.');
}

export async function noopUrlResolver(site) {
return site.getBaseURL();
}
Expand Down
15 changes: 4 additions & 11 deletions src/cwv/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,18 @@
*/

import RUMAPIClient from '@adobe/spacecat-shared-rum-api-client';
import URI from 'urijs';
import { hasText } from '@adobe/spacecat-shared-utils';
import { getRUMDomainkey } from '../support/utils.js';
import { AuditBuilder } from '../common/audit-builder.js';
import { wwwUrlResolver } from '../common/audit.js';

const DAILY_THRESHOLD = 1000;
const INTERVAL = 7; // days

export function getAuditUrl(baseURL) {
const uri = new URI(baseURL);
return hasText(uri.subdomain()) ? baseURL.replace(/https?:\/\//, '') : baseURL.replace(/https?:\/\//, 'www.');
}

export async function CWVRunner(auditUrl, context, site) {
const rumAPIClient = RUMAPIClient.createFrom(context);
const domainkey = await getRUMDomainkey(site.getBaseURL(), context);
const finalUrl = getAuditUrl(auditUrl);
const options = {
domain: finalUrl,
domain: auditUrl,
domainkey,
interval: INTERVAL,
granularity: 'hourly',
Expand All @@ -44,11 +37,11 @@ export async function CWVRunner(auditUrl, context, site) {

return {
auditResult,
fullAuditRef: finalUrl,
fullAuditRef: auditUrl,
};
}

export default new AuditBuilder()
.withUrlResolver((site) => site.getBaseURL())
.withUrlResolver(wwwUrlResolver)
.withRunner(CWVRunner)
.build();
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
* governing permissions and limitations under the License.
*/

/* c8 ignore start */
import RUMAPIClient from '@adobe/spacecat-shared-rum-api-client';
import { AuditBuilder } from '../common/audit-builder.js';
import { getRUMDomainkey } from '../support/utils.js';
import { wwwUrlResolver } from '../common/audit.js';

const DAYS = 30;

let log = console;
const OPPTY_QUERIES = [
'rageclick',
'high-inorganic-high-bounce-rate',
'high-organic-low-ctr',
];

/**
* Audit handler container for all the opportunities
Expand All @@ -27,10 +30,8 @@ let log = console;
* @returns
*/

export async function opportunitiesHandler(auditUrl, context, site) {
log = context.log;
log.info(`Received Opportunities audit request for ${auditUrl}`);
const startTime = process.hrtime();
export async function handler(auditUrl, context, site) {
const { log } = context;

const rumAPIClient = RUMAPIClient.createFrom(context);
const domainkey = await getRUMDomainkey(site.getBaseURL(), context);
Expand All @@ -40,30 +41,21 @@ export async function opportunitiesHandler(auditUrl, context, site) {
interval: DAYS,
granularity: 'hourly',
};
const experimentationHandlers = ['rageclick'];
const queryResults = await rumAPIClient.queryMulti(experimentationHandlers, options);
const auditData = {
experimentationOpportunities: [],
};
for (const queryResult of Object.keys(queryResults)) {
if (experimentationHandlers.includes(queryResult)) {
auditData.experimentationOpportunities.push(...queryResults[queryResult]);
}
}

const endTime = process.hrtime(startTime);
const elapsedSeconds = endTime[0] + endTime[1] / 1e9;
const formattedElapsed = elapsedSeconds.toFixed(2);
const queryResults = await rumAPIClient.queryMulti(OPPTY_QUERIES, options);
const experimentationOpportunities = Object.values(queryResults).flatMap((oppty) => oppty);

log.info(`Opportunities Audit is completed in ${formattedElapsed} seconds for ${auditUrl}`);
log.info(`Found ${experimentationOpportunities.length} many experimentation opportunites for ${auditUrl}`);

return {
auditResult: auditData,
auditResult: {
experimentationOpportunities,
},
fullAuditRef: auditUrl,
};
}

export default new AuditBuilder()
.withRunner(opportunitiesHandler)
.withRunner(handler)
.withUrlResolver(wwwUrlResolver)
.build();
/* c8 ignore stop */
10 changes: 5 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +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 opportunities from './opportunities/opportunities.js';
import experimentationOpportunities from './experimentation-opportunities/experimentation-opportunities.js';
import costs from './costs/handler.js';
import structuredData from './structured-data/handler.js';

Expand All @@ -46,7 +46,7 @@ const HANDLERS = {
conversion,
'experimentation-ess-daily': essExperimentationDaily,
'experimentation-ess-all': essExperimentationAll,
opportunities,
'experimentation-opportunities': experimentationOpportunities,
costs,
'structured-data': structuredData,
dummy: (message) => ok(message),
Expand All @@ -68,7 +68,7 @@ async function run(message, context) {
const { log } = context;
const { type, url } = message;

log.info(`Audit req received for url: ${url}`);
log.info(`Received ${type} audit request for: ${url}`);

const handler = HANDLERS[type];
if (!handler) {
Expand All @@ -82,11 +82,11 @@ async function run(message, context) {
try {
const result = await (typeof handler.run === 'function' ? handler.run(message, context) : handler(message, context));

log.info(`Audit for ${type} completed in ${getElapsedSeconds(startTime)} seconds`);
log.info(`${type} audit for ${url} completed in ${getElapsedSeconds(startTime)} seconds`);

return result;
} catch (e) {
log.error(`Audit failed after ${getElapsedSeconds(startTime)} seconds`, e);
log.error(`${type} audit for ${url} failed after ${getElapsedSeconds(startTime)} seconds`, e);
return internalServerError();
}
}
Expand Down
13 changes: 2 additions & 11 deletions test/audits/cwv.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import nock from 'nock';
import { createSite } from '@adobe/spacecat-shared-data-access/src/models/site.js';
import { CWVRunner, getAuditUrl } from '../../src/cwv/handler.js';
import { CWVRunner } from '../../src/cwv/handler.js';
import { rumData } from '../fixtures/rum-data.js';

use(sinonChai);
Expand Down Expand Up @@ -59,7 +59,7 @@ describe('Index Tests', () => {
});

it('cwv audit runs rum api client cwv query', async () => {
const result = await CWVRunner('https://spacecat.com', context, site);
const result = await CWVRunner('www.spacecat.com', context, site);
expect(result).to.deep.equal({
auditResult: {
cwv: rumData.filter((data) => data.pageviews >= 7000),
Expand All @@ -70,13 +70,4 @@ describe('Index Tests', () => {
fullAuditRef: auditUrl,
});
});

it('audit url calculated correctly', async () => {
expect(getAuditUrl('http://spacecat.com')).to.equal('www.spacecat.com');
expect(getAuditUrl('https://spacecat.com')).to.equal('www.spacecat.com');
expect(getAuditUrl('http://www.spacecat.com')).to.equal('www.spacecat.com');
expect(getAuditUrl('https://www.spacecat.com')).to.equal('www.spacecat.com');
expect(getAuditUrl('http://blog.spacecat.com')).to.equal('blog.spacecat.com');
expect(getAuditUrl('https://blog.spacecat.com')).to.equal('blog.spacecat.com');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { expect, use } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import nock from 'nock';
import { opportunitiesHandler } from '../../src/opportunities/opportunities.js';
import { handler } from '../../src/experimentation-opportunities/experimentation-opportunities.js';
import { MockContextBuilder } from '../shared.js';
import opportunitiesData from '../fixtures/opportunitiesdata.json' assert { type: 'json' };

Expand Down Expand Up @@ -91,19 +91,22 @@ describe('Opportunities Tests', () => {
const site = {
getBaseURL: () => 'https://abc.com',
};
const auditData = await opportunitiesHandler(url, context, site);
const auditData = await handler(url, context, site);

expect(context.rumApiClient.queryMulti).calledWith(
['rageclick'],
{
domain: 'https://abc.com',
domainkey: 'abc_dummy_key',
interval: 30,
granularity: 'hourly',
},
);
const expected = Object.values(opportunitiesData).flatMap((data) => data);

expect(context.rumApiClient.queryMulti).calledWith([
'rageclick',
'high-inorganic-high-bounce-rate',
'high-organic-low-ctr',
], {
domain: 'https://abc.com',
domainkey: 'abc_dummy_key',
interval: 30,
granularity: 'hourly',
});
expect(
auditData.auditResult.experimentationOpportunities,
).to.deep.equal(opportunitiesData.rageclick);
).to.deep.equal(expected);
});
});
16 changes: 14 additions & 2 deletions test/common/audit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ import { createOrganization } from '@adobe/spacecat-shared-data-access/src/model
import { createConfiguration } from '@adobe/spacecat-shared-data-access/src/models/configuration.js';
import { composeAuditURL, prependSchema } from '@adobe/spacecat-shared-utils';
import {
defaultMessageSender, defaultOrgProvider,
defaultMessageSender,
defaultOrgProvider,
defaultPersister,
defaultSiteProvider,
defaultUrlResolver, noopUrlResolver,
defaultUrlResolver,
noopUrlResolver,
wwwUrlResolver,
} from '../../src/common/audit.js';
import { AuditBuilder } from '../../src/common/audit-builder.js';
import { MockContextBuilder } from '../shared.js';
Expand Down Expand Up @@ -326,4 +329,13 @@ describe('Audit tests', () => {
expect(context.sqs.sendMessage).to.have.been.calledOnce;
expect(context.sqs.sendMessage).to.have.been.calledWith(queueUrl, expectedMessage);
});

it('wwwUrlResolver calculates audit urls correctly', async () => {
expect(wwwUrlResolver(createSite({ baseURL: 'http://spacecat.com' }))).to.equal('www.spacecat.com');
expect(wwwUrlResolver(createSite({ baseURL: 'https://spacecat.com' }))).to.equal('www.spacecat.com');
expect(wwwUrlResolver(createSite({ baseURL: 'http://www.spacecat.com' }))).to.equal('www.spacecat.com');
expect(wwwUrlResolver(createSite({ baseURL: 'https://www.spacecat.com' }))).to.equal('www.spacecat.com');
expect(wwwUrlResolver(createSite({ baseURL: 'http://blog.spacecat.com' }))).to.equal('blog.spacecat.com');
expect(wwwUrlResolver(createSite({ baseURL: 'https://blog.spacecat.com' }))).to.equal('blog.spacecat.com');
});
});
Loading

0 comments on commit 33aa025

Please sign in to comment.