Skip to content

Commit

Permalink
feat: adding experiment function for rum bundler APIs (#264)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpapani committed Jun 20, 2024
1 parent 7e052dd commit b1a076d
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,6 @@ junit

# Files deliberately excluded from version control
*DO-NOT-COMMIT*

# Mac OS
.DS_Store
58 changes: 58 additions & 0 deletions packages/spacecat-shared-rum-api-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,64 @@ An example response:

```

### experiment

Lists all the experiments for a specified domain within the requested interval. The results are grouped by URL. The output includes all the URLs running the experiment, along with experiment id, variants, number of clicks/convert/formsubmit events per variant/selector and views for each of the variant in the experiment.


An example response:

```json
{
"https://www.aem.live/home": [
{
"experiment": "short-home",
"variants": [
{
"name": "challenger-1",
"views": 1300,
"click": {
".hero": 100,
".header #navmenu-0": 100,
".roi-calculator .button": 100,
".hero .button": 100
},
"convert": {},
"formsubmit": {}
},
{
"name": "control",
"views": 800,
"click": {
".hero .button": 100,
".header .button": 200,
".header #navmenu-0": 200
},
"convert": {},
"formsubmit": {}
}
]
}
],

"https://www.aem.live/new-exp-page": [
{
"experiment": "visitor-behavior",
"variants": [
{
"name": "https://www.aem.live/some-other-page",
"views": 500,
"click": {},
"convert": {},
"formsubmit": {}
}
]
}
]
}

```

## Linting
Lint the codebase using:
```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

const EXPERIMENT_CHECKPOINT = ['experiment'];
const METRIC_CHECKPOINTS = ['click', 'convert', 'formsubmit'];
const CHECKPOINTS = [...EXPERIMENT_CHECKPOINT, ...METRIC_CHECKPOINTS];

function toClassName(name) {
return typeof name === 'string'
? name.toLowerCase().replace(/[^0-9a-z]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')
: '';
}

function getOrCreateExperimentObject(urlInsights, experimentName) {
let experimentObject = urlInsights.find((e) => e.experiment === toClassName(experimentName));
if (!experimentObject) {
experimentObject = {
experiment: toClassName(experimentName),
variants: [],
};
urlInsights.push(experimentObject);
}
return experimentObject;
}

function getOrCreateVariantObject(variants, variantName) {
let variantObject = variants.find((v) => v.name === variantName);
if (!variantObject) {
variantObject = {
name: variantName,
views: 0,
click: {},
convert: {},
formsubmit: {},
};
variants.push(variantObject);
}
return variantObject;
}

function handler(bundles) {
const experimentInsights = {};
for (const bundle of bundles) {
const experimentEvent = bundle.events.find((e) => e.checkpoint === 'experiment');
if (experimentEvent) {
const { url, weight } = bundle;
if (!experimentInsights[url]) {
experimentInsights[url] = [];
}
const experimentName = experimentEvent.source;
const variantName = experimentEvent.target;
const experimentObject = getOrCreateExperimentObject(experimentInsights[url], experimentName);
const variantObject = getOrCreateVariantObject(experimentObject.variants, variantName);
variantObject.views += weight;

for (const event of bundle.events) {
if (METRIC_CHECKPOINTS.includes(event.checkpoint)) {
const { source, checkpoint } = event;
if (!variantObject[checkpoint][source]) {
variantObject[checkpoint][source] = weight;
} else {
variantObject[checkpoint][source] += weight;
}
}
}
}
}
return experimentInsights;
}

export default {
handler,
checkpoints: CHECKPOINTS,
};
2 changes: 2 additions & 0 deletions packages/spacecat-shared-rum-api-client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
import { fetchBundles } from './common/rum-bundler-client.js';
import notfound from './functions/404.js';
import cwv from './functions/cwv.js';
import experiment from './functions/experiment.js';

const HANDLERS = {
404: notfound,
cwv,
experiment,
};

export default class RUMAPIClient {
Expand Down
17 changes: 17 additions & 0 deletions packages/spacecat-shared-rum-api-client/test/fixtures/bundles.json
Original file line number Diff line number Diff line change
Expand Up @@ -18048,6 +18048,23 @@
"timeDelta": 541
}
]
},
{
"id": "1656750620-1715646747687-ccd3b6776f8fc",
"host": "rum.hlx.page",
"time": "2024-05-07T06:00:00.001Z",
"timeSlot": "2024-05-07T06:00:00.000Z",
"url": "https://www.aem.live/new-exp-page",
"userAgent": "desktop:windows",
"weight": 100,
"events": [
{
"checkpoint": "experiment",
"target": "https://www.aem.live/some-other-page",
"source": 3,
"timeDelta": 1814
}
]
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"https://www.aem.live/home": [
{
"experiment": "short-home",
"variants": [
{
"name": "challenger-1",
"views": 1300,
"click": {
".hero": 100,
".header #navmenu-0": 100,
".roi-calculator .button": 100,
".hero .button": 100
},
"convert": {},
"formsubmit": {}
},
{
"name": "control",
"views": 800,
"click": {
".hero .button": 100,
".header .button": 200,
".header #navmenu-0": 200
},
"convert": {},
"formsubmit": {}
}
]
}
],
"https://www.aem.live/new-exp-page": [
{
"experiment": "",
"variants": [
{
"name": "https://www.aem.live/some-other-page",
"views": 100,
"click": {},
"convert": {},
"formsubmit": {}
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { expect } from 'chai';
import cwv from '../src/functions/cwv.js';
import notfound from '../src/functions/404.js';
import bundles from './fixtures/bundles.json' assert { type: 'json' };
import experiment from '../src/functions/experiment.js';
import expectedCwvResult from './fixtures/cwv.json' assert { type: 'json' };
import expected404Result from './fixtures/notfound.json' assert { type: 'json' };
import expectedExperimentsResult from './fixtures/experiments.json' assert { type: 'json' };

describe('Query functions', () => {
it('crunches cwv data', async () => {
Expand All @@ -28,4 +30,9 @@ describe('Query functions', () => {
const notfoundResult = notfound.handler(bundles.rumBundles);
expect(expected404Result).to.eql(notfoundResult);
});

it('crunches experiment data', async () => {
const experimentsResult = experiment.handler(bundles.rumBundles);
expect(expectedExperimentsResult).to.eql(experimentsResult);
});
});

0 comments on commit b1a076d

Please sign in to comment.